目录

  • 一、使用属性而不是可访问的数据成员
  • 二、使用运行时常量(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# 高效编程要点补充

《Effective C#》快速笔记(一)- C# 语言习惯的更多相关文章

  1. 《Effective C#》读书笔记-1.C# 语言习惯-2.使用运行时常量(readonly)而不是编译时常量(const)

    概念 编译时 编译时顾名思义就是正在编译的时候.那啥叫编译呢?就是编译器帮你把源代码翻译成机器能识别的代码.(当然只是一般意义上这么说,实际上可能只是翻译成某个中间状态的语言.比如Java只有JVM识 ...

  2. 《Effective C#》读书笔记-1.C# 语言习惯-1.使用属性而不是可访问的数据成员

    思维导图: 大纲: 1.使用属性而不是可访问的数据成员    属性        指定不同的访问权限        隐式属性降低了声明属性的工作量        允许将数据成员作为公共接口的一部分暴露 ...

  3. [.NET] 《Effective C#》快速笔记(一)- C# 语言习惯

    <Effective C#>快速笔记(一)- C# 语言习惯 目录 一.使用属性而不是可访问的数据成员 二.使用运行时常量(readonly)而不是编译时常量(const) 三.推荐使用 ...

  4. [.NET] 《Effective C#》快速笔记(三)- 使用 C# 表达设计

    <Effective C#>快速笔记(三)- 使用 C# 表达设计 目录 二十一.限制类型的可见性 二十二.通过定义并实现接口替代继承 二十三.理解接口方法和虚方法的区别 二十四.用委托实 ...

  5. [.NET] 《Effective C#》快速笔记(四)- 使用框架

    <Effective C#>快速笔记(四)- 使用框架 .NET 是一个类库,你了解的越多,自己需要编写的代码就越少. 目录 三十.使用重写而不是事件处理函数 三十一.使用 ICompar ...

  6. [.NET] 《Effective C#》快速笔记 - C# 中的动态编程

    <Effective C#>快速笔记 - C# 中的动态编程 静态类型和动态类型各有所长,静态类型能够让编译器帮你找出更多的错误,因为编译器能够在编译时进行大部分的检查工作.C# 是一种静 ...

  7. [.NET] 《Effective C#》快速笔记 - C# 高效编程要点补充

    <Effective C#>快速笔记 - C# 高效编程要点补充 目录 四十五.尽量减少装箱拆箱 四十六.为应用程序创建专门的异常类 四十七.使用强异常安全保证 四十八.尽量使用安全的代码 ...

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

    <Effective C#>快速笔记(二)- .NET 资源托管 简介 续 <Effective C#>读书笔记(一)- C# 语言习惯. .NET 中,GC 会帮助我们管理内 ...

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

    目录 四十五.尽量减少装箱拆箱 四十六.为应用程序创建专门的异常类 四十七.使用强异常安全保证 四十八.尽量使用安全的代码 四十九.实现与 CLS 兼容的程序集 五十.实现小尺寸.高内聚的程序集 这是 ...

随机推荐

  1. unhandled exception(没有处理异常)

    背景 今天在代码中抛出了Exception类, 但是出现了代码报错 意思是,未处理异常 原因 因为Exception是check异常,也就是必须在代码层面直接捕获处理的,这类异常有IOExceptio ...

  2. matlab:inv,pinv逆与伪逆

    对于方阵A,如果为非奇异方阵,则存在逆矩阵inv(A)对于奇异矩阵或者非方阵,并不存在逆矩阵,但可以使用pinv(A)求其伪逆   inv:   inv(A)*B实际上可以写成A\BB*inv(A)实 ...

  3. Echo团队Alpha冲刺随笔 - 第一天

    项目冲刺情况 进展 每个人开始搭建自己要用的各种框架.库,基本实现了登录功能 问题 除了框架使用问题外,暂未遇到其他疑难杂症 心得 今天有一个还可以的开头,相信后续会挺顺利的 今日会议内容 黄少勇 今 ...

  4. centos6安装tomcat8.5

    //参考https://www.cnblogs.com/xdp-gacl/p/4097608.html [root@192 ~]# mount /dev/sr0 /mnt/usb1[root@192 ...

  5. 谈高清显示接口HDMI、RGB、LVDS、MIPI、eDP、mini-LVDS、V-By-One

    近年来随着电子产业的高速发展,智能显示设备也取得了辉煌的成就,高清显示得到了消费者的青睐.目前高清显示协议接口有RGB.LVDS.MIPI.eDP.HDMI.miniLVDS.V-by-One等,由于 ...

  6. python常用工具组件

    1.JS 正则    test   - 判断字符串是否符合规定的正则        rep = /\d+/;        rep.test("asdfoiklfasdf89asdfasdf ...

  7. Luogu4338 ZJOI2018 历史 LCT、贪心

    传送门 题意:在$N$个点的$LCT$中,最开始每条边的虚实不定,给出每一个点的$access$次数,求一种$access$方案使得每条边的虚实变换次数之和最大,需要支持动态增加某个点的$access ...

  8. React-使用react-redux

    react-redux可以方便在react中使用redux,我们就可以忘记subscribe,只需要记住reducer,action和dispatch就可以了.react-redux提供Provide ...

  9. java 基础01

    标识符:字母,下划线和美元符号,数字组成大小写敏感,无长度限制 关键字: 数据类型

  10. Auto-ML之自动化特征工程

    1. 引言 个人以为,机器学习是朝着更高的易用性.更低的技术门槛.更敏捷的开发成本的方向去发展,且Auto-ML或者Auto-DL的发展无疑是最好的证明.因此花费一些时间学习了解了Auto-ML领域的 ...