找回密码
 立即注册
首页 业界区 业界 编写更好的C#代码

编写更好的C#代码

公新蕾 2025-5-29 16:31:18
引言

开发人员总是喜欢就编码规范进行争论,但更重要的是如何能够在项目中自始至终地遵循编码规范,以保证项目代码的一致性。并且团队中的所有人都需要明确编码规范所起到的作用。在这篇文章中,我会介绍一些在我多年的从业过程中所学习和总结的一些较好的实践。
举例为先

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

示例1:
  1. 1     public static void Test()
  2. 2     {
  3. 3       for (int i = 1; i < 101; i++)
  4. 4       {
  5. 5         if (i % 3 == 0 && i % 5 == 0)
  6. 6         {
  7. 7           Console.WriteLine("FizzBuzz");
  8. 8         }
  9. 9         else if (i % 3 == 0)
  10. 10         {
  11. 11           Console.WriteLine("Fizz");
  12. 12         }
  13. 13         else if (i % 5 == 0)
  14. 14         {
  15. 15           Console.WriteLine("Buzz");
  16. 16         }
  17. 17         else
  18. 18         {
  19. 19           Console.WriteLine(i);
  20. 20         }
  21. 21       }
  22. 22     }
复制代码
什么感觉?这段代码需要改进吗?
示例2:
  1. 1     public static void Check()
  2. 2     {
  3. 3       for (int i = 1; i <= 100; i++)
  4. 4       {
  5. 5         string output = "";
  6. 6         if (i % 3 == 0) { output = "Fizz"; }
  7. 7         if (i % 5 == 0) { output = output + "Buzz"; }
  8. 8         if (output == "") { output = i.ToString(); }
  9. 9         Console.WriteLine(output);
  10. 10       }
  11. 11     }
复制代码
复杂的表达式意味着其背后隐藏了一些涵义,我们可以通过使用属性来封装这些表达式,进而使代码更易读些。
把警告等同于错误

2.jpeg

如果你注意看代码,你会发现一个变量被声明了但从没被使用过。正常来讲,我们编译工程后会得到一个警告,但仍可以运行工程而不会发生任何错误。但是我们应该尽可能地移除这些警告。通过如下步骤可以在工程上设置将警告等同于错误:
3.jpeg

4.jpeg

5.jpeg

精简多处返回

在每段程序中都减少函数返回的数量。假设从底部开始阅读代码,你很难意识到有可能在上面的某处已经返回了,这样的代码将是非常难理解的。
仅使用一处返回可以增强可读性。如果程序这么写的话可能看起来比较干净,但不立即返回也意味着需要编写更多代码。
  1. 1     public void DoFizzBuzz()
  2. 2     {
  3. 3       for (int number = 1; number <= 100; number++)
  4. 4       {
  5. 5         var output = GetFizzBuzzOutput(number);
  6. 6         Console.WriteLine(output);
  7. 7       }
  8. 8     }
  9. 9
  10. 10     private static string GetFizzBuzzOutput(int number)
  11. 11     {
  12. 12       string output = string.Empty;
  13. 13       if (number % 3 == 0)
  14. 14       {
  15. 15         output = "Fizz";
  16. 16       }
  17. 17       if (number % 5 == 0)
  18. 18       {
  19. 19         output += "Buzz";
  20. 20       }
  21. 21       if (string.IsNullOrEmpty(output))
  22. 22       {
  23. 23         output = number.ToString();
  24. 24       }
  25. 25       return output;
  26. 26     }
复制代码
  1.     public class Product
  2.     {
  3.       public void GetActiveProducts()
  4.       {
  5.         //...
  6.       }
  7.       public void CalculateProductAdditinalCost()
  8.       {
  9.         //...
  10.       }
  11.     }
复制代码
你可以想象在这 20-30 行代码中就散落了 4 个退出点,这会使你非常难理解到底程序内部做了什么,到底会执行什么,什么时候执行。
关于这一点我得到了很多人的回复,一些人同意这个观点,有些则不同意这是一个好的编码标准。为了找出潜在的问题,我做了些单元测试,发现如果复杂的方法包含多个退出点,通常情况下会需要一组测试来覆盖所有的路径。
  1.     public class ProductCategory
  2.     {
  3.       public void Save(ProductCategory productCategory)
  4.       {
  5.         // ...
  6.       }
  7.     }
复制代码
  1.     // Correct
  2.     ProductCategory productCategory;
  3.     // Avoid
  4.     ProductCategory prodCat;
复制代码
进一步理解可以参考 Steve McConnell 的《代码大全》。
使用断言

在软件开发中,断言代码常被用于检查程序代码是否按照其设计在执行。通常 True 代表所有操作按照预期的完成,False 代表已经侦测到了一些意外的错误。断言通常会接收两个参数,一个布尔型的表达式用于一个描述假设为真的假定,一个消息参数用于描述断言失败的原因。
尤其在开发大型的、复杂的高可靠系统中,断言通常是非常有用的功能。
例如:如果系统假设将最多支持 100,000 用户记录,系统中可能会包含一个断言来检查用户记录数小于等于 100,000,在这种范围下,断言不会起作用。但如果用户记录数量超过了 100,000,则断言将会抛出一个错误来告诉你记录数已经超出了范围。
检查循环端点值

一个循环通常会涉及三种条件值:第一个值、中间的某值和最后一个值。但如果你有任何其他的特定条件,也需要进行检测。如果循环中包含了复杂的计算,请不要使用计算器,要手工检查计算结果。
总结

通常在任何软件公司中推行编码规范都需要按照组织行为、项目属性和领域来进行,在此我想再次强调“找到一个适合你的编码规范,并一直遵循它”。
如果你认为我遗漏了某个特别有用的编码准则,请在评论中描述,我会尝试补充到文章中。
Coding For Fun.
 
原文地址
译者注:原文作者 Monjurul Habib 是孟加拉国人,我不知道孟加拉国的人说什么语言,但我感觉作者的英语非常生硬,有些地方我实在是理解不上去,读者见谅。

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册