旗下导航:搜·么
当前位置:网站首页 > .Net教程 > 正文

教你怎样编写更好的C#代码示例【C#.Net教程】,C#代码

作者:搜教程发布时间:2019-11-27分类:.Net教程浏览:24评论:0


导读: 弁言  开辟人员老是喜欢就编码范例举行争辩,但更主要的是如何能够在项目中自始至终地遵照编码范例,以保证项目代码的一致性。而且团队中的一切人都须要明白编码范例所起到的作用。...

 弁言

  开辟人员老是喜欢就编码范例举行争辩,但更主要的是如何能够在项目中自始至终地遵照编码范例,以保证项目代码的一致性。而且团队中的一切人都须要明白编码范例所起到的作用。在这篇文章中,我会引见一些在我多年的从业历程中所进修和总结的一些较好的实践。

 举例为先

  我们先来看一个 FizzBuzz 示例。FizzBuzz 请求编写一个顺序,遍历从 1 到 100 的数字。个中假如某数字是 3 的倍数,则顺序输出 “Fizz”。假如某数字是 5 的倍数,则输出 “Buzz”。假如某数字即是 3 的倍数也是 5 的倍数,则输出 “FizzBuzz”。假如数字既不是 3 的倍数也不是 5 的倍数,则只需输出该数字自身。

  示例1:

public static void Test()
{
      for (int i = 1; i < 101; i++)
      {
        if (i % 3 == 0 && i % 5 == 0)
        {
          Console.WriteLine("FizzBuzz");
        }
        else if (i % 3 == 0)
        {
          Console.WriteLine("Fizz");
        }
        else if (i % 5 == 0)
        {
          Console.WriteLine("Buzz");
        }
        else
        {
          Console.WriteLine(i);
        }
      }
}

  什么觉得?这段代码须要革新吗?

  示例2:

public static void Check()
{
      for (int i = 1; i <= 100; i++)
      {
        string output = "";
        if (i % 3 == 0) { output = "Fizz"; }
        if (i % 5 == 0) { output = output + "Buzz"; }
        if (output == "") { output = i.ToString(); }
        Console.WriteLine(output);
      }
}

  如今觉得如何?还能不能进一步革新?

  好,让我们来尝试革新下。代码定名对一切软件开辟人员来说都是件异常难题的事变。我们消费了大批的时候来做这件事,而且有太多的须要被定名的元素,比方属性、要领、类、文件、项目等。不过我们确切须要消费一些精神在这些定名上,以使代码中的称号更有意义,进而能够进步代码的可读性。

public void DoFizzBuzz()
{
      for (int number = 1; number <= 100; number++)
      {
        var output = GetFizzBuzzOutput(number);
        Console.WriteLine(output);
      }
}

private static string GetFizzBuzzOutput(int number)
{
      string output = string.Empty;
      if (number % 3 == 0)
      {
        output = "Fizz";
      }
      if (number % 5 == 0)
      {
        output += "Buzz";
      }
      if (string.IsNullOrEmpty(output))
      {
        output = number.ToString();
      }
      return output;
}

  此次觉得如何?是不是是比之前的示例要好些?是不是是可读性更好些?

 什么是更好的代码?

  起首就是代码要为人来编写,其次是为机械。从历久来看,编写可读性好的代码不会比编写杂沓的代码要消费更长的时候。假如你能够异常轻易地读懂你写的代码,那末想确认其能够平常事情就更轻易了。这应当已是编写易读代码充足充足的来由了。在许多状况下都须要浏览代码,比方在代码评审中会浏览你写的代码,在你或许其他人修复Bug时会浏览你写的代码,在代码须要修正时也会读到。另有就是当其他人预备在相似的项目或有相似功用的项目中尝试复用你的部份代码时也会先浏览你的代码。

  “假如你只为你本身写代码,为何要使代码更具可读性?”

  好,编写易读的代码最主要的缘由是,在将来的一到两周,你将事情在另一个项目上。而此时,有其他人须要修复当前项目标一个Bug,那末将会发作什么?我敢保证他肯定会丢失在你本身编写的恐惧代码中。

  从我的个人看法来看,好的代码应当具有以下几个特性:

  • 代码轻易编写,并易于修正和扩大。

  • 代码清洁,并表述正确。

  • 代码有价值,并注重质量。

  所以,要时候斟酌先为人来编写代码,然后再满足机械的须要。

 如何革新可读性?

  起首,你须要浏览进修其他人编写的代码,来相识什么是好的代码,什么是不好的代码。也就是那些你觉得异常轻易明白的代码,和觉得看起来超等庞杂的代码。然后,举行实践。末了消费一些时候、履历和实践来革新你的代码的可读性。平常来说仅经由过程培训这类体式格局,在任何软件公司中推进编码范例都有些难题。而诸如结对代码评审,自动化代码评审东西等也能够协助你。现在盛行的东西有:

  • FxCop:对 .NET 代码举行静态代码剖析,供应了多种划定规矩来举行差别情势的剖析。

  • StyleCop:开源项目,其运用代码作风和一致性范例来对剖析C#代码。可在 Visual Studio 中运转,也能够集成到 MSBuild 中。StyleCop 也已被集成到了一些第三方开辟东西中。

  • JetBrains ReSharper:异常有名的提拔生产力的东西,能够使 Microsoft Visual Studio IDE 越发壮大。全球的 .NET 开辟人员能够都没法设想,事情中怎么能没有 ReSharper 的代码检察、代码自动重构、疾速导航和编码助手等这些壮大的功用呢。

 范例是什么?

  依据维基百科上的形貌:"Coding conventions are a set of guidelines for a specific programming language that recommend programming style, practices and methods for each aspect of a piece program written in this language. These conventions usually cover file organization, indentation, comments, declarations, statements, white space, naming conventions, programming practices, programming principles, programming rules of thumb, architectural best practices, etc. These are guidelines for software structural quality. Software programmers are highly recommended to follow these guidelines to help improve the readability of their source code and make software maintenance easier. Coding conventions are only applicable to the human maintainers and peer reviewers of a software project. Conventions may be formalized in a documented set of rules that an entire team or company follows, or may be as informal as the habitual coding practices of an inpidual. Coding conventions are not enforced by compilers. As a result, not following some or all of the rules has no impact on the executable programs created from the source code."。

  你应当能说出属性、局部变量、要领名、类名等的差别,由于它们运用差别的大小写商定,所以这些商定异常有价值。经由过程互联网,你已相识了许多响应的准绳和范例,你所须要的仅是找到一种范例或许竖立你本身的范例,然后一向遵照该范例。

  下面运用到的源代码(类库设想准绳)是由微软的 Special Interest Group 团队开辟的,我只是做了些扩大。

  大小写商定

  下面是一些关于C#编码规范、定名商定和最好实践的示例,能够依据你本身的须要来运用。

  Pascal Casing

  标示符中的首字母,后续串连的每一个单词的首字母均为大写。假如须要,标示符的前几个字母都可大写。

  Camel Casing

  标示符的首字母为小写,后续串连的每一个单词的首字母为大写。

  参考:标示符大小写划定规矩

 一些定名商定示例

  在互联网上你能够找到充足多的资本,我只是引荐几个个中我最喜欢的:

  • C# 编码商定

  • C# 编码准绳

  • C# 编码规范和最好实践

  • C# 编码范例和定名商定

  这里我展现了一些最基本的示例,但就像我上面已提到的,找到一个适宜你的范例,然后对峙运用。

  要运用 Pascal Casing 为类和要领定名。

public class Product
{
      public void GetActiveProducts()
      {
        //...
      }
      public void CalculateProductAdditinalCost()
      {
        //...
      }
}

  要运用 Camel Casing 为要领的参数和局部变量定名。

public class ProductCategory
{
      public void Save(ProductCategory productCategory)
      {
        // ...
      }
}

  不要运用缩写语。

    // Correct
    ProductCategory productCategory;

    // Avoid
    ProductCategory prodCat;

  不要在标示符中运用下划线。

    // Correct
    ProductCategory productCategory;

    // Avoid
    ProductCategory product_Category;

  要在接口称号前运用字母 I 。

    public interface IAddress
    {
    }

  要在类的顶端定义一切成员变量,在最顶端定义静态变量。

public class Product
{
    public static string BrandName;

    public string Name { get; set; }
    public DateTime DateAvailable { get; set; }

    public Product()
    {
      // ...
    }
}

  要运用单数的辞汇定义罗列,除非是BitField罗列。

public enum Direction
{
    North,
    East,
    South,
    West
}

  不要为罗列称号增加Enum后缀。

//Avoid
public enum DirectionEnum
{
    North,
    East,
    South,
    West
}

 为何我们须要编码范例?

  在大型项目中,开辟人员会常依赖于编码范例。他们竖立了许多范例和准绳,以至于记着这些范例和准绳已变成了一样平常事情的一部份。盘算机并不体贴你写的代码可读性是不是好,比起读懂那些高等的顺序语言语句,盘算机更轻易明白二进制的机械指令。

  编码范例供应了许多显著的优点,当然有能够你获得的更多。一般这些项目团体局限的计划,将使能够将精神更多的集合在代码中更主要的部份上。

  • 编码范例能够协助跨项目标通报学问。

  • 编码范例能够协助你在新的项目上更疾速的明白代码。

  • 编码范例强调构造中关联项目间的关联。

  你须要编写可读性高的代码,以此来协助其他人来明白你的代码。代码定名对我们软件开辟人员来说是件异常难题的事变,我们在这上面已消费了大批的时候,而且有太多的须要定名的元素,比方属性、要领、类、文件、项目等。所以我们确切须要消费一些精神在定名范例上,以使称号更有意义,进而进步代码的可读性。

  另有,编码范例能够让你晚上睡得更香。

 开辟人员最应当遵照的几个划定规矩

  一向掌握类的大小

  我曾看到过,而且也曾写过一些超大的类。而且不幸的是,效果老是不好的。厥后我找到了真正缘由,就是那些超大的类在尝试做太多的事变,这违反了单一职责准绳(SRP),也就是面向对象设想准绳 SOLID 中的 S。

  “The single responsibility principle states that every object should have a single responsibility, and that responsibility should be entirely encapsulated by the class. All its services should be narrowly aligned with that responsibility.”

  或许根据 Martin Fowler 的定义:"THERE SHOULD NEVER BE MORE THAN ONE REASON FOR A CLASS TO CHANGE."

  为何肯定要将两个职责星散到零丁的类中呢?由于每一个职责都是变化的中心。在需求变动时,这个变动将会出如今担任该职责的类中。假如一个类负担了多个职责,就会有一个以上的缘由致使其变化。假如一个类有多重职责,则申明这些职责已耦合到了一同。而且某个职责的变化将有能够减弱或限定这个类满足其他职责的才。这类耦合将会致使异常软弱的设想,进而在职责发作变化时,设想能够被意想不到的破坏了。

  防止过期的解释

  先说什么过期的解释。根据 Robert C. Martin 的定义:

  "A comment that has gotten old, irrelevant, and incorrect is obsolete. Comments get old quickly. It is best not to write a comment that will become obsolete. If you find an obsolete comment, it is best to update it or get rid of it as quickly as possible. Obsolete comments tend to migrate away from the code they once described. They become floating islands of irrelevance and misdirection in the code."

  针对这个主题,差别程度的开辟人员能够都邑有本身的看法。我的发起是尝试防止为零丁的要领或短小的类举行解释。由于我所见过的大部份的解释都是在尝试形貌代码的目标或企图,或许某些解释能够自身就没什么意义。一般开辟人员经由过程写解释来进步代码的可读性和可维护性,但要保证你所写的解释不会成为代码中的噪音。比起解释,我认为合理的要领定名将更加有效,比方你能够为一个要领起一个更有意义的名字。大部份解释都能够变成了无意义的代码噪音,让我们来看看下面这些解释:

//ensure that we are not exporting
 //deleted products
 if (product.IsDeleted && !product.IsExported)
 {
       ExportProducts = false;
 }

 // This is a for loop that prints the 1 million times
 for (int i = 0; i < 1000000; i++)
 {
       Console.WriteLine(i);
 }

  假如我们不写解释,而是定名一个要领,比方叫 CancelExportForDeletedProducts() ,状况会如何?所以,适宜的要领定名比解释更有效。然则某些状况下,代码解释也会异常有协助,比方 Visual Studio 会从解释生成 API 文档。此处的解释略有差别,你须要运用 “///” 标识符来解释,如许其他开辟人员才看到 API 或类库的智能提醒。

  我没有说老是要防止解释。根据 Kent Beck 说法,能够运用更多的解释来形貌顺序团体是如何事情的,而不是对零丁的要领举行解释。假如解释是在尝试形貌代码的目标或企图,那就错了。假如你在代码中看到了密密层层的的解释,你能够就会意想到有这么多解释申明代码写的很蹩脚。相识更多信息能够浏览下面这几本书:

  • 《Professional Refactoring in C# and ASP.NET》 by Danijel Arsenovski

  • 《重构:改良既有代码设想》 by Martin Fowler, Kent Beck, John Brant, William Opdyke, Don Roberts

  防止不必要的Region

  Region 是 Visual Studio 供应的一个功用,它许可你将代码分块。Region 的存在是由于它能够使大文件导航变得轻易。Region 还常被用于隐蔽貌寝的代码,或许类已膨胀的异常大了须要分块。而假如一个类做了太多的事变,也就申明其违反了单一职责准绳。所以,下次当你想新增一个 Region 时,先斟酌下有没有能够将这个 Region 星散到一个零丁的类中。

  坚持要领的短小

  要领中的代码行数越多,则要领越难明白。我们引荐每一个要领中只包括 20-25 行代码。但有些人说 1-10 行更合理,这只是些个人喜欢,没有硬性的划定规矩。抽取要领是最常见的重构体式格局之一。假如你发明一个要领太长,或许已须要一个解释来形貌它的目标了,那末你就能够运用抽取要领了。人们老是会问一个要领究竟多长适宜,但实在长度并非题目的泉源。当你在处置惩罚庞杂的要领时,跟踪一切局部变量是最庞杂和斲丧时候的,而经由过程抽取一个要领能够节约一些时候。能够运用 Visual Studio 来抽取要领,它会协助你跟踪局部变量,并将其通报给新的要领或许吸收要领的返回值。

  Using ReSharper

  Using Microsoft Visual Studio

  更多的信息能够参考 MSDN。

  根据《重构:改良既有代码设想》中的形貌,

  "Extract Method is one of the most common refactoring I do. I look at a method that is too long or look at code that needs a comment to understand its purpose. I then turn that fragment of code into its own method. I prefer short, well-named methods for several reasons. First, it increases the chances that other methods can use a method when the method is finely grained. Second, it allows the higher-level methods to read more like a series of comments. Overriding also is easier when the methods are finely grained. It does take a little getting used to if you are used to seeing larger methods. And small methods really work only when you have good names, so you need to pay attention to naming. People sometimes ask me what length I look for in a method. To me length is not the issue. The key is the semantic distance between the method name and the method body. If extracting improves clarity, do it, even if the name is longer than the code you have extracted."

  防止过量的参数

  经由过程声明一个类来替代多个参数。建立一个类,用于包括一切的参数。一般来说,这是一个较好的设想,而且这个笼统异常的有价值。

//avoid
    public void Checkout(string shippingName, string shippingCity,
      string shippingSate, string shippingZip, string billingName,
      string billingCity, string billingSate, string billingZip)
    {
    }
    //DO
    public void Checkout(ShippingAddress shippingAddress, BillingAddress billingAddress)
    {
    }

  我们须要引入类来替代一切的参数。

  防止庞杂的表达式

if(product.Price>500 && !product.IsDeleted && 
  !product.IsFeatured && product.IsExported)
{
      // do something
}

  庞杂的表达式意味着其背地隐蔽了一些涵义,我们能够经由过程运用属性来封装这些表达式,进而使代码更易读些。

  把正告等同于毛病

  假如你注重看代码,你会发明一个变量被声清楚明了但从没被运用过。平常来说,我们编译工程后会获得一个正告,但仍能够运转工程而不会发作任何毛病。然则我们应当尽量地移除这些正告。经由过程以下步骤能够在工程上设置将正告等同于毛病:

  精简多处返回

  在每段顺序中都削减函数返回的数目。假定从底部最先浏览代码,你很难意想到有能够在上面的某处已返回了,如许的代码将是异常难明白的。

  仅运用一处返回能够加强可读性。假如顺序这么写的话能够看起来比较清洁,但不马上返回也意味着须要编写更多代码。

//avoid
      if(product.Price>15)
      {
         return false;
      }
      else if(product.IsDeleted)
      {
         return false;
      }
      else if(!product.IsFeatured)
      {
         return false;
      }
      else if()
      {
         //.....
      }
      return true;
//DO
      var isValid = true;
      if(product.Price>15)
      {
         isValid= false;
      }
      else if(product.IsDeleted)
      {
         isValid= false;
      }
      else if(!product.IsFeatured)
      {
         isValid= false;
      }
      return isValid;

  你能够设想在这 20-30 行代码中就散落了 4 个退出点,这会使你异常难明白究竟顺序内部做了什么,究竟会实行什么,什么时候实行。

  关于这一点我获得了许多人的复兴,一些人赞同这个看法,有些则差别意这是一个好的编码规范。为了找出潜伏的题目,我做了些单元测试,发明假如庞杂的要领包括多个退出点,一般状况下会须要一组测试来掩盖一切的途径。

if( BADFunction() == true)
      {
          // expression
          if( anotherFunction() == true )
          {
           // expression
           return true;
          }
          else
          {
               //error
          }
      }
      else
      {
          //error
      }
      return false;
if( !GoodFunction())
      {
          // error.
          return false
      } 
      // expression
      if( !GoodFunction2())
      {
          //error.
          return false;
      }
      // more expression
      return true;

  进一步明白能够参考 Steve McConnell 的《代码大全》。

  运用断言

  在软件开辟中,断言代码常被用于搜检顺序代码是不是根据其设想在实行。一般 True 代表一切操纵根据预期的完成,False 代表已侦测到了一些不测的毛病。断言一般会吸收两个参数,一个布尔型的表达式用于一个形貌假定为真的假定,一个音讯参数用于形貌断言失利的缘由。

  尤其在开辟大型的、庞杂的高牢靠体系中,断言一般是异常有效的功用。

  比方:假如体系假定将最多支撑 100,000 用户纪录,体系中能够会包括一个断言来搜检用户纪录数小于即是 100,000,在这类局限下,断言不会起作用。但假如用户纪录数目超过了 100,000,则断言将会抛出一个毛病来通知你纪录数已超出了局限。

  搜检轮回端点值

  一个轮回一般会触及三种前提值:第一个值、中心的某值和末了一个值。但假如你有任何其他的特定前提,也须要举行检测。假如轮回中包括了庞杂的盘算,请不要运用盘算器,要手工搜检盘算效果。

 总结

  一般在任何软件公司中履行编码范例都须要根据构造行动、项目属性和范畴来举行,在此我想再次强调“找到一个适宜你的编码范例,并一向遵照它”。

  假如你认为我遗漏了某个迥殊有效的编码准绳,请在批评中形貌,我会尝试补充到文章中。

  Coding For Fun.

 

以上就是教你如何编写更好的C#代码示例的细致内容,更多请关注ki4网别的相干文章!

标签:C#代码


欢迎 发表评论: