Effective C# 改善C#程序的50种方法
作者:Bill Wagner
译者:DSQiu
来源:Effective C# 中文版改善C#程序的50种方法 第二版
原则1:使用 属性(Poperty)代替可直接访问的数据成员(Data Member)
原则2:偏爱 readonly 而不是 const
C# 有两种常量:编译时常量和运行时常量。你可以使用 readonly 关键字声明运行时常量,使用 const 关键字声明编译器常量。运行时常量的值是在运行时得到的。当你引用一个只读(read-only)常量, IL 会引用一个 readonly 变量而不是直接使用值。
相比 readonly ,使用 const 最后的一个优势就是性能:已知的常量值会比使用变量访问的 readonly 变量产生稍微高效的代码。然而,性能上甚微的收效和灵活性的减小应该做一个很好的权衡。放弃灵活性之前一定要剖析性能差异。可选参数的默认值会在调用时会像编译时变量(声明为 const 的变量)一样被替换成默认值。和使用 readonly 和 const 变量一样,你要非常认真对待可选参数值的不同。
原则3:选择 is 或 as 而不是强制类型转换
尽可能使用 as ,但是 as 操作符是不能再值类型上使用的。
原则4:使用条件特性(conditional attribute)代替 #if
C# 有一个更好的选择:条件特性。使用条件特性,能分离出不同函数,只有在特定的环境变量的定义或某些值的设置才会属于你的类。
[Conditional("DEBUG")]
private void CheckState()
{
// same code as above
}
原则5:个别情况建议重写C#提供的 ToString()
原则6:理解几个不同相等概念的关系
当你定义类型(类或结构体)时,你同时要定义类型的相等。 C# 提供四种不同的函数决定两个不同对象是否“相等”:
public static bool ReferenceEquals (object left, object right);
public static bool Equals (object left, object right);
public virtual bool Equals(object right);
public static bool operator ==(MyClass left, MyClass right);
原则7:明白 GetHashCode() 的陷阱
GetHashCode() 只用在一个地方:定义基于哈希 key 集合,典型地, HashSet<T> 或者 Dictionary<K,V> 容器。
任何重写 GetHashCode() 必须遵循下面三个条件:
1.如果两个对象相等(被操作符 == 定义),你产生相同的哈希值。否则哈希码不能用来查找容器中的对象。
2.对任何对象 A , A.GetHashCode() 必须是一个实例不变量。无论什么方法调用 A.GetHashCode() 必须返回相同的值。这保证了一个物体总是存储在正确的桶中。
3.哈希函数应该针对所有输入情况产生一个整数随机分布。这就是为什么基于哈希容器高效。
原则8:优先考虑查询语法
举个例子:
private readonly List<T> datas = new List<T>();
public List<T> FindAll(Predicate<T> match, ref List<T> result,int count = 0)
{
result.Clear();
foreach (var pair in datas)
{
if (null == pair)
continue;
if (null != match && match.Invoke(pair) == false)
continue;
result.Add(pair);
if (0 < count && count <= result.Count)
break;
}
return result;
}
private static bool Check(T t)
{
//TODO
}
private Predicate<T> Checker()
{
return x => Check(x);
}
原则9:在你的 API 中避免转换操作
原则10:使用默认参数减少函数的重载
原则11:理解小函数的魅力
用多个简短的小函数代替大段代码块组成的函数,目的一是可以增强阅读性和扩展性,二是避免编译器产生额外的开销
短小而简单的函数可以让 JIT 编译器很容易支持寄存器化(enregistration) 。寄存器化是指处理器选择寄存器而不是栈存储局部变量。创建更少的局部变量使得 JIT 编译器更好的找到可用的寄存器。
原则12:选择变量初始化语法(initializer)而不是赋值语句
在变量声明的时候初始化而不是在构造函数内初始化。你应该使用初始化语法为静态变量和实例变量进行初始化。
原则13:使用恰当的方式对静态成员进行初始化
静态成员变量在创建对象实例之前就已经初始化了。C# 提供了静态初始化语法和静态构造函数对静态成员变量进行初始化。静态构造函数是一个比其他函数,变量,属性在没有访问之前就被执行的特殊函数。
和实例初始化一样,静态初始化语法在任何静态构造函数之前执行。并且,你的静态初始化语法比基类的静态构造函数更早执行。
原则14:减少重复的代码块
原则15:使用 using 和 try/finally 清理资源
使用 using 语句可以保证 Dispose() 被调用。你使用 using 语句分配对象,C# 编译器就会产生 try/finally 块包含这些对象:
SqlConnection myConnection = null;
// Example Using clause:
using (myConnection = new SqlConnection(connString))
{
myConnection.Open();
}
// example Try / Catch block:
try
{
myConnection = new SqlConnection(connString);
myConnection.Open();
}
finally
{
myConnection.Dispose();
}