zoukankan      html  css  js  c++  java
  • 《Effective C#》快速笔记(一)- C# 语言习惯

    目录

    • 一、使用属性而不是可访问的数据成员
    • 二、使用运行时常量(readonly)而不是编译时常量(const)
    • 三、推荐使用 is 或 as 操作符而不是强制类型转换
    • 四、使用 Conditional 特性而不是 #if 条件编译
    • 五、为类型提供 ToString() 方法
    • 六、理解几个等同性判断之间的关系
    • 七、理解 GetHashCode() 的陷阱
    • 八、推荐使用查询语法而不是循环
    • 九、避免在 API 中使用转换操作符
    • 十、使用可选参数减少方法重载的数量
    • 十一、理解短小方法的优势

    一、使用属性而不是可访问的数据成员

    二、使用运行时常量(readonly)而不是编译时常量(const)

      1. C# 有两种类型的常量:编译时常量和运行时常量。

      2.尽量使用运行时常量,而不是编译时常量。

    复制代码
            /// <summary>
            /// 编译时常量
            /// </summary>
            public const int Num = 100;
    
            /// <summary>
            /// 运行时常量
            /// </summary>
            public static readonly int Year = 2017;
    复制代码

      3.编译时常量只能用于数字和字符串,运行时常量也是一种常量,因为在构造函数执行后它不能被再次修改。

      4.const 比 readonly 效率高,但灵活性低。

    三、推荐使用 is 或 as 操作符而不是强制类型转换

      1.as 比强转更加高效、安全。

      2.as 操作符不能配合值类型使用,因为值类型永远不可能为 null。

    四、使用 Conditional 特性而不是 #if 条件编译

    复制代码
            public static void Test()
            {
                string msg = null;
    
                #if DEBUG
                msg = "Hi";
                #endif
    
                Console.WriteLine(msg);
            }
    复制代码

      假如你是将这块代码在 Release 版本中执行的话,就会输出空行。出现 Bug 的原因是我们把程序中的主要逻辑代码和条件编译代码混在一块了。这会让我们很难察觉不同版本间的差异,导致错误的行为发生。

    五、为类型提供 ToString() 方法

      1.应该为类型提供一个合适的 ToString() 版本,否则使用者会根据类的一些属性来自行构造并用于显示。

      2.object 默认提供的 ToString() 方法会返回类型的完整名称,意义不大。如:System.Drawing.Rect。

      3.重写所有类型的 ToString(),可以简单明了的显示对象的摘要信息。

    六、理解几个等同性判断之间的关系

      1.系统提供 4 种函数判断两个对象是否“相等”。

      2.对于前两种方法,我们永远不要重新定义,我们通常要重写 Equals 方法。

      3.重写 Equals 的类型也要实现 IEquatable<T>,如果是结构体的话需要实现 IStructuralEquatable。

      4.引用同一个 DataRow,会认为相等,如果想比较内容的话,而不是引用地址,那么就应该重写 Equals() 实例方法。

      5.Equals() 实例方法的重写原则:对于所有的值类型,都应该重写 Equals() 方法,对于引用类型,如果不能满足需要时才去重写该方法。重写该方法的同时也需要重写 GetHashCode() 方法。

      6.operator == ():只要创建的是值类型,都必须重新定义 operator == (),因为系统默认是通过反射来比较两个值是否相等,效率过低。

    七、理解 GetHashCode() 的陷阱

      1.对于我们实现的大多数类型来说,避免实现 GetHashCode()。

      2.GetHashCode() 的重载版本必须遵循以下三条原则:

      (1)如果两个对象相等(由 operator == 定义),那么它们必须生成相同的散列码。

      (2)对于任何一个对象 A,A.GetHashCode() 必须保持不变。

      (3)对于所有的输入,散列函数应该在所有整数中按照随机分布生成散列码。

    八、推荐使用查询语法而不是循环

      示例:

    复制代码
                //1.使用循环
                var foo = new int[100];
    
                for (int i = 0; i < 100; i++)
                {
                    foo[i] = i * i;
                }
    
                //使用查询语法
                var foo2 = (from n in Enumerable.Range(0, 100) select n * n).ToArray();
    复制代码

      1.有些方法语法没有对应的查询语法,如 Take、TaskWhile、Skip、SkipWhile、Min、Max 等,就需要使用方法语法。

    九、避免在 API 中使用转换操作符

    十、使用可选参数减少方法重载的数量

      1.对于程序集的第一次发布,可以随意使用可选参数和命名参数。而在进行后续发布时,必须为额外的参数创建重载。这样才能保证现在的程序仍能正常运行。此外,在任何的后续发布中,都要避免修改参数的名称,因为参数名称已经成为公有接口的一部分。

    十一、理解短小方法的优势

      1.我们最好尽可能地编写出最清晰的代码,将优化工作交给 JIT 完成。一个常见的错误优化是,我们将大量的逻辑放在一个函数中,以为这样可以减少额外的方法调用开销。

    复制代码
            public string Test(bool isTrue)
            {
                var sb = new StringBuilder();
    
                if (isTrue)
                {
                    sb.AppendLine("A");
                    sb.AppendLine("B");
                    sb.AppendLine("C");
                }
                else
                {
                    sb.AppendLine("E");
                    sb.AppendLine("F");
                    sb.AppendLine("G");
                }
    
                return sb.ToString();
            }
    复制代码

      在第一次调用 Test 方法时, if-else 的两个分支都被 JIT 编译,而实际上只需要编译其中一个,修改后:

    复制代码
            public string Test2(bool isTrue)
            {
                var sb = new StringBuilder();
    
                if (isTrue)
                {
                    return Method1();
                }
                else
                {
                    return Method2();
                }
            }
    复制代码

      现在进行了方法拆分,这两个方法就可以根据需要进行 JIT 编译,而不必第一次进行全部编译。

      2.可以将 if-else 分支中有超过几十条的语句,或者某个分支专门用来处理程序发生的错误,或者 switch 语句中的每个 case 中的代码进行选择性的提取。

      3.短小精悍的方法(一般包含较少的局部变量)会让 JIT 更容易地进行寄存器选择工作,即选择哪些局部变量放在寄存器中,而不是栈上。

      4.尽量编写短小精悍的方法。

    本系列

      《Effective C#》快速笔记(一)- C# 语言习惯

      《Effective C#》快速笔记(二)- .NET 资源托管

      《Effective C#》快速笔记(三)- 使用 C# 表达设计

      《Effective C#》快速笔记(四) - 使用框架

      《Effective C#》快速笔记(五) - C# 中的动态编程

      《Effective C#》快速笔记(六) - C# 高效编程要点补充

  • 相关阅读:
    开发中常见的七种加密算法及实现
    MySql 函数大全(一)
    MySql 函数大全(二)
    MySql中查询优化方法
    double类型保留一位小数, 其他位数舍弃方法
    java.lang.IllegalArgument,Parse error in application web.xml file at jndi:/localhost/WEB-INF/web.xml
    c#版HOOK微信来了。实时获取微信消息以及公众号文章等
    c#hook微信,实现实时获取微信公众号文章
    C# 未能创建 SSL/TLS 安全通道 和C# 基础连接已经关闭: 发送时发生错误. 解决方案
    .net post一个xml文件到url
  • 原文地址:https://www.cnblogs.com/MuNet/p/6902511.html
Copyright © 2011-2022 走看看