# 原则13:使用恰当的方式对静态成员进行初始化
**By D.S.Qiu**
**尊重他人的劳动,支持原创,转载请注明出处:[http://dsqiu.iteye.com](http://dsqiu.iteye.com)**
你应该知道静态成员变量在创建对象实例之前就已经初始化了。C# 提供了静态初始化语法和静态构造函数对静态成员变量进行初始化。静态构造函数是一个比其他函数,变量,属性在没有访问之前就被执行的特殊函数。你可以使用这个函数初始化静态变量,完善单例模式,或者任何需要在类还没有被使用的必要工作。你不能使用构造函数,一些特殊 private 函数,或其他语法初始化静态变量。
和实例初始化一样,初始化语法是静态构造函数的另一选择。你只需要声明一个静态成员,然后使用初始化语法。如果有静态变量的初始化逻辑很复杂,你可以创建一个静态构造函数。
C# 实现单例模式最常用的方法就是静态构造函数。让构造函数变为 private ,然后添加一个初始化语法:
```
public class MySingleton
{
private static readonly MySingleton theOneAndOnly = new MySingleton();
public static MySingleton TheOnly
{
get { return theOneAndOnly; }
}
private MySingleton()
{
}
// remainder elided
}
```
单例模式很容易像上面的方式一样实现。如果初始化逻辑更复杂:
```
public class MySingleton2
{
private static readonly MySingleton2 theOneAndOnly;
static MySingleton2()
{
theOneAndOnly = new MySingleton2();
}
public static MySingleton2 TheOnly
{
get { return theOneAndOnly; }
}
private MySingleton2()
{
}
// remainder elided
}
```
和实例初始化一样,静态初始化语法在任何静态构造函数之前执行。并且,你的静态初始化语法比基类的静态构造函数更早执行。
CLR 在类型第一次在应用空间被访问之前自动执行静态构造函数。你只能定义一个静态构造函数,并且不能有参数。因此你需要注意在静态构造函数是否会产生异常。如果你在静态构造函数抛出了异常, CLR 会终止你的程序。这种情况捕获异常是非常阴险的。这时的代码区创建这个类型就会失败直到 AppDomain 被卸载。 CLR 就不能执行静态构造函数去初始化这个类型。即使你再尝试,类型不会被正确初始化。创建这个类型的对象(或者任意子类)都是没有被定义的。所以,这是不允许的。
异常是使用静态构造函数代替静态初始化语法的最常见原因。因为你使用静态初始化语法,你不能自己捕获异常。使用静态构造函数,你就可以(查看原则47:):
```
static MySingleton2()
{
try
{
theOneAndOnly = new MySingleton2();
}
catch
{
// Attempt recovery here.
}
}
```
静态初始化语法和静态构造函数是最干净,最清晰的方式去初始化静态成员变量。它们具有很强的可读性和很容易正确使用。它们被支持就是为了解决这个其他语言初始化静态成员会出现的问题。
小结:
这个事情一直拖着,一直想继续,今天又起了个头了,希望能一鼓作气。翻译很烂并且有很多不明确的地方(自己读的疑惑),算是给自己买下一个伏笔吧,还有很多工作要去完善。
欢迎各种不爽,各种喷,写这个纯属个人爱好,秉持”分享“之德!
有关本书的其他章节翻译请[点击查看](/category/297763),转载请注明出处,尊重原创!
如果您对D.S.Qiu有任何建议或意见可以在文章后面评论,或者发邮件(gd.s.qiu@gmail.com)交流,您的鼓励和支持是我前进的动力,希望能有更多更好的分享。
转载请在**文首**注明出处:[http://dsqiu.iteye.com/blog/2077189](/blog/2077189)
更多精彩请关注D.S.Qiu的博客和微博(ID:静水逐风)
- 第一章 C# 语言习惯
- 原则1:使用 属性(Poperty)代替可直接访问的数据成员(Data Member)
- 原则2:偏爱 readonly 而不是 const
- 原则3:选择 is 或 as 而不是强制类型转换
- 原则4:使用条件特性(conditional attribute)代替 #if
- 原则5:总是提供 ToString()
- 原则6:理解几个不同相等概念的关系
- 原则7:明白 GetHashCode() 的陷阱
- 原则8:优先考虑查询语法(query syntax)而不是循环结构
- 原则9:在你的 API 中避免转换操作
- 原则10:使用默认参数减少函数的重载
- 原则11:理解小函数的魅力
- 第二章 .NET 资源管理
- 原则12:选择变量初始化语法(initializer)而不是赋值语句
- 原则13:使用恰当的方式对静态成员进行初始化
- 原则14:减少重复的初始化逻辑
- 原则15:使用 using 和 try/finally 清理资源
- 原则16:避免创建不需要的对象
- 原则17:实现标准的 Dispose 模式
- 原则17:实现标准的 Dispose 模式
- 原则18:值类型和引用类型的区别
- 原则19:确保0是值类型的一个有效状态
- 原则20:更倾向于使用不可变原子值类型
- 第三章 用 C# 表达设计
- 原则21:限制你的类型的可见性
- 原则22:选择定义并实现接口,而不是基类
- 原则23:理解接口方法和虚函数的区别
- 原则24:使用委托来表达回调
- 原则25:实现通知的事件模式
- 原则26:避免返回类的内部对象的引用
- 原则27:总是使你的类型可序列化
- 原则28:创建大粒度的网络服务 APIs
- 原则29:让接口支持协变和逆变
- 第四章 和框架一起工作
- 原则30:选择重载而不是事件处理器
- 原则31:用 IComparable<T> 和 IComparer<T> 实现排序关系
- 原则32:避免 ICloneable
- 原则33:只有基类更新处理才使用 new 修饰符
- 原则34:避免定义在基类的方法的重写
- 原则35:理解 PLINQ 并行算法的实现
- 原则36:理解 I/O 受限制(Bound)操作 PLINQ 的使用
- 原则37:构造并行算法的异常考量
- 第五章 杂项讨论
- 原则38:理解动态(Dynamic)的利与弊
- 原则39:使用动态对泛型类型参数的运行时类型的利用
- 原则40:使用动态接收匿名类型参数