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.尽量编写短小精悍的方法。
【博主】反骨仔
【原文】http://www.cnblogs.com/liqingwen/p/6754401.html
C# 语言习惯的更多相关文章
- [.NET] 《C# 高效编程》(一) - C# 语言习惯
C# 语言习惯 目录 一.使用属性而不是可访问的数据成员 二.使用运行时常量(readonly)而不是编译时常量(const) 三.推荐使用 is 或 as 操作符而不是强制类型转换 四.使用 Con ...
- [.NET] 《Effective C#》快速笔记(一)- C# 语言习惯
<Effective C#>快速笔记(一)- C# 语言习惯 目录 一.使用属性而不是可访问的数据成员 二.使用运行时常量(readonly)而不是编译时常量(const) 三.推荐使用 ...
- 改善 C# 的语言习惯(一) - 使用属性而不是可访问的数据成员(整理中)
改善 C# 的语言习惯(一) - 使用属性而不是可访问的数据成员 序 为什么我们的程序运行得棒棒的,还要改呢?Why? 答:我们要让程序运行得更快,执行的效率更高,代码的可读性更强,维护的成本更低.. ...
- 《Effective C#》快速笔记(一)- C# 语言习惯
目录 一.使用属性而不是可访问的数据成员 二.使用运行时常量(readonly)而不是编译时常量(const) 三.推荐使用 is 或 as 操作符而不是强制类型转换 四.使用 Conditional ...
- 1-3 - C#语言习惯 - 推荐使用查询语法而不是循环
C#语言中并不缺少控制程序流程的结构,for.while.do-while和foreach等都可以做到这点. 历史上所有计算机语言设计者都不曾遗漏这些重要的循环控制结构. 不过我们还有一个更好的方式: ...
- 《Effective C#》读书笔记-1.C# 语言习惯-2.使用运行时常量(readonly)而不是编译时常量(const)
概念 编译时 编译时顾名思义就是正在编译的时候.那啥叫编译呢?就是编译器帮你把源代码翻译成机器能识别的代码.(当然只是一般意义上这么说,实际上可能只是翻译成某个中间状态的语言.比如Java只有JVM识 ...
- 1.2 - C#语言习惯 - 用运行时常量readonly而不是编译期常量const
C#中有两种类型的常量:编译期常量和运行时常量.二者有着截然不同的行为,使用不当将会带来性能上或正确性上的问题. 这两个问题最好都不要发生,不过若难以同时避免的话,那么一个略微慢一些但能保证正确的程序 ...
- 《Effective C#》读书笔记-1.C# 语言习惯-1.使用属性而不是可访问的数据成员
思维导图: 大纲: 1.使用属性而不是可访问的数据成员 属性 指定不同的访问权限 隐式属性降低了声明属性的工作量 允许将数据成员作为公共接口的一部分暴露 ...
- 符合语言习惯的Python优雅编程技巧
Python最大的优点之一就是语法简洁,好的代码就像伪代码一样,干净.整洁.一目了然.要写出 Pythonic(优雅的.地道的.整洁的)代码,需要多看多学大牛们写的代码,github 上有很多非常优秀 ...
随机推荐
- 扫盲记-第六篇--Normalization
深度学习模型中的Normalization 数据经过归一化和标准化后可以加快梯度下降的求解速度,这就是Batch Normalization等技术非常流行的原因,Batch Normalization ...
- Objective-C 浅拷贝与深拷贝
一个Objective-C对象通常分配在堆上,并有一个或者多个指针指向它.如下代码及其关系图所示: NSObject *obj1 = [[NSObject alloc] init]; NSObject ...
- TerraGate软件安装后,服务无法启动的解决方法
前些天有朋友问,TerraGate安装后,服务无法启动,而且启动按钮也是不可用的状态,不知道是为什么,如下图: 打开TerraGate的安装目录,发现里面缺少一些文件,如下图: *解决办法: 重新安装 ...
- Recurrent Neural Network[CTC]
0. 背景 1. CTC原理 图 CTC结构图 CTC是看似和HMM有些联系,然后也采用DP来进行求解,将CTC结构图中<RNN输出,CTC层>单独拿出来,得到如下形式: 图 用前向-后向 ...
- 浅析单点登录,以及不同二级域名下的SSO实现
一家公司有多个产品线,就可能要有多个子域名,下头以baidu域名为例,a.baidu.com, b.baidu.com.com 是顶级域名,baidu 就是一个二级域名,a和b就是子域名. 当用户在a ...
- NowCoder110E Pocky游戏 状压DP
传送门 题意:给出$N$个数和一个长为$M$.所有数在$[1,N]$范围之内的正整数序列$a_i$,求出这$N$个数的一种排列$p_1...p_N$使得$\sum\limits_{i=2}^M |p_ ...
- BZOJ4883 棋盘上的守卫 基环树、Kruskal
题目传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=4883 题意:给出一个$N \times M$的棋盘,每个格子有权值.你需要每一行选中一 ...
- React-state props与render()的关系
state或者props发生改变,render()j就会执行一次. 父组件的render()被重新执行时,它的子组件的render()都会重新执行.
- 给echarts加个“全屏展示”
echarts的工具箱并没有提供放大/全屏的功能, 查找文档发现可自定义工具https://www.echartsjs.com/option.html#toolbox.feature show代码 t ...
- 使用IntelliJ IDEA开发SpringMVC网站(二)框架配置
原文:使用IntelliJ IDEA开发SpringMVC网站(二)框架配置 摘要 讲解如何配置SpringMVC框架xml,以及如何在Tomcat中运行 目录[-] 文章已针对IDEA 15做了一定 ...