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

目录
- 一、使用属性而不是可访问的数据成员
- 二、使用运行时常量(readonly)而不是编译时常量(const)
- 三、推荐使用 is 或 as 操作符而不是强制类型转换
- 四、使用 Conditional 特性而不是 #if 条件编译
- 五、为类型提供 ToString() 方法
- 六、理解几个等同性判断之间的关系
- 七、理解 GetHashCode() 的陷阱
- 八、推荐使用查询语法而不是循环
- 九、避免在 API 中使用转换操作符
- 十、使用可选参数减少方法重载的数量
- 十一、理解短小方法的优势
一、使用属性而不是可访问的数据成员
二、使用运行时常量(readonly)而不是编译时常量(const)
1. C# 有两种类型的常量:编译时常量和运行时常量。
2.尽量使用运行时常量,而不是编译时常量。
/// <summary>
/// 编译时常量
/// </summary>
public const int Num = ; /// <summary>
/// 运行时常量
/// </summary>
public static readonly int Year = ;
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[]; for (int i = ; i < ; i++)
{
foo[i] = i * i;
} //使用查询语法
var foo2 = (from n in Enumerable.Range(, ) 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#》快速笔记(五) - C# 中的动态编程
《Effective C#》快速笔记(六) - C# 高效编程要点补充
【博主】反骨仔
【原文】http://www.cnblogs.com/liqingwen/p/6754401.html
【参考】《Effective C#》
[.NET] 《C# 高效编程》(一) - C# 语言习惯的更多相关文章
- C语言高效编程的几招(绝对实用,绝对经典)
编写高效简洁的C语言代码,是许多软件工程师追求的目标.废话不说,走起! 第一招:以空间换时间 计算机程序中最大的矛盾是空间和时间的矛盾,那么,从这个角度出发逆向思维来考虑程序的效率问题 eg.字符串的 ...
- [收藏转贴]struct探索·extern "C"含义探索 ·C++与C的混合编程·C 语言高效编程的几招
一.C/C++语言 struct深层探索 1.自然对界 struct是一种复合数据类型,其构成元素既可以是基本数据类型(如 int.long.float等)的变量,也可以是一些复合数据类型(如 arr ...
- 【C/C++】struct探索·extern "C"含义探索 ·C++与C的混合编程·C 语言高效编程的几招
本文为笔者阅读<嵌入式C精华>的摘录,推荐一下,不错的书 一.C/C++语言 struct深层探索 1.自然对界 struct是一种复合数据类型,其构成元素既可以是基本数据类型(如 int ...
- C 语言高效编程的几招——A few action of efficient C language programming
编写高效简洁的C 语言代码,是许多软件工程师追求的目标.本文就工作中的一些体会和经验做相关的阐述,不对的地方请各位指教. 第1 招:以空间换时间 计算机程序中最大的矛盾是空间和时间的矛盾,那么,从这个 ...
- C语言高效编程的几招,你会了几招了?
编写高效简洁的C 语言代码,是许多软件工程师追求的目标.本文就工作中的一些体会和经验做相关的阐述,不对的地方请各位指教. 第1 招:以空间换时间 计算机程序中最大的矛盾是空间和时间的矛盾,那么,从这个 ...
- [.NET] 《Effective C#》快速笔记 - C# 高效编程要点补充
<Effective C#>快速笔记 - C# 高效编程要点补充 目录 四十五.尽量减少装箱拆箱 四十六.为应用程序创建专门的异常类 四十七.使用强异常安全保证 四十八.尽量使用安全的代码 ...
- [.NET] 《Effective C#》快速笔记(一)- C# 语言习惯
<Effective C#>快速笔记(一)- C# 语言习惯 目录 一.使用属性而不是可访问的数据成员 二.使用运行时常量(readonly)而不是编译时常量(const) 三.推荐使用 ...
- 《Effective C#》快速笔记(一)- C# 语言习惯
目录 一.使用属性而不是可访问的数据成员 二.使用运行时常量(readonly)而不是编译时常量(const) 三.推荐使用 is 或 as 操作符而不是强制类型转换 四.使用 Conditional ...
- 《Effective C#》快速笔记(六)- - C# 高效编程要点补充
目录 四十五.尽量减少装箱拆箱 四十六.为应用程序创建专门的异常类 四十七.使用强异常安全保证 四十八.尽量使用安全的代码 四十九.实现与 CLS 兼容的程序集 五十.实现小尺寸.高内聚的程序集 这是 ...
随机推荐
- html表单 2017-03-10PM
在写表单之前补充一点:网页名以及属性的值命名都不能用中文,尽量用英文或拼音. html表单特写 1.表单格式 <form method="get/post" action=& ...
- C++ 构造函数或析构函数调用虚函数
构造函数和析构函数中的虚函数 在执行基类构造函数时,对象的派生类部分是未初始化的.实际上,此时对象还不是一个派生类对象. 为 了适应这种不完整,编译器将对象的类型视为在构造或析构期间发生了变化.在基类 ...
- 重回博客 谈一谈Node中的异步和单线程
重回博客,这个帐号之前注册后就只发了一篇博客.听朋友建议,决定一周两次更新. 第一篇谈论一下最近想的比较多的异步的问题. 传统多线程异步 传统的异步是多线程的,当要同时做两件事的时候,他们是执行在不同 ...
- AVFoundation之如何从摄像头获取图像
前言: 最近项目有个需求是对试图对手机密码进行强破解的人进行拍照(通过摄像头截图),因为之前没做过,所以一堆坑.现在就把我的经验都分享出来,希望后来人不用再踏上坑途中. 直接上代码: // 创建会话 ...
- Effective Modern C++ Item 37:确保std::thread在销毁时是unjoinable的
下面这段代码,如果调用func,按照C++的标准,程序会被终止(std::terminate) void func() { std::thread t([] { std::chrono::micros ...
- Day4 数据库的建立||数据库对外查询||使用命令行来操作数据库
###数据库的创建 建立一个项目 先进行测试,测试新项目是否可以成功运行 创建一个PersonContrary包,并建立一个Person类实现BaseColumns借口,在此类中添加所有的表的列名,并 ...
- 解决SQLServer 2008 日志无法收缩,收缩后大小不改变
问题 数据库日志文件上G,或者几十G了,使用日志收缩,和日志截断收缩都不管用.体积一直减不下来.. 解决方案 查看日志信息 在查询分析器中执行如下代码来查看日志信息: DBCC LOGINFO('数 ...
- cuda内存总结
1.shared memory __shared__ 声明为共享内存,将会保存在共享内存中 2.constant memory __constant__ 声明为常量内存,将会保存在常量内存中,常量内 ...
- linux下大于2T的硬盘格式化方法
我们先在超级用户模式下用fdisk -l命令查看挂载的硬盘设备,假设设备号为/dev/sdb,接下来我们使用parted命令来进行GPT分区:1. yum install parted -y# par ...
- Tcl与Design Compiler (四)——DC启动环境的设置
本文属于原创手打(有参考文献),如果有错,欢迎留言更正:此外,转载请标明出处 http://www.cnblogs.com/IClearner/ ,作者:IC_learner 主要内容有: ·启动环 ...