常量
- 一个值不可以改变的静态字段
- 在编译时值就已经定下来了。
- 任何使用常量的地方,编译器都会把这个常量替换为它的值
- 常量的类型可以是内置的数值类型、bool、char、string或enum
- 使用const关键字声明,声明的同时必须使用具体的值来对其初始化
public class Test
{
public const string Message = "Hello World";
}
常量与静态只读字段
- 常量比静态只读字段更严格:
- 可使用的类型
- 字段初始化的语义上
- 常量是在编译时进行值的估算的
常量
注意
当值有可能改变,并且需要暴露给其它Assembly的时候,静态只读字段是相对较好的选择
public const decimal ProgramVersion = 2.3;
如果 Y Assembly引用了 X Assembly并且使用了这个常量,那么在编译的时候,2.3这个值就会被固化于Y Assembly里。这意味着,如果后来X重编译了,这个常量变成了2.4,如果Y不重新编译的话,Y将仍然使用2.3这个值,直到Y被重新编译,它的值才会变成2.4。静态只读字段就会避免这个问题的发生
本地常量
- 方法里可以有本地的常量
静态构造函数
- 静态构造函数,每个类型执行一次
- 非静态构造函数,每个实例执行一次
- 一个类型只能定义一个静态构造函数
- 必须无参
- 方法名与类型一致
在类型使用之前的一瞬间,编译器会自动调用类型的静态构造函数:
- 实例化一个类型
- 访问类型的一个静态成员
只允许使用 unsafe 和 extern 修饰符
注意
- 如果静态构造函数抛出了未处理的异常,那么这个类型在该程序的剩余生命周期内将无法使用了
初始化顺序
- 静态字段的初始化器在静态构造函数被调用之前的一瞬间运行
- 如果类型没有静态构造函数,那么静态字段初始化器在类型被使用之前的一瞬间执行,或者更早,在运行时突发奇想的时候执行
- 静态字段的初始化顺序与它们的声明顺序一致
静态类
类也可以是静态的
其成员必须全是静态的
不可以有子类
例如
System.Console
System.Math
Finalizer 终结器
- Finalizer是class专有的一种方法
- 在GC回收未引用对象的内存之前运行
- 其实就是对object的Finalize()方法重写的一种语法
Partial Type 局部类型
- 允许一个类型的定义分布在多个地方(文件)
- 典型应用:一个类的一部分是自动生成的,另一部分需要手动写代码
- 每个分布的类都必须使用partial来声明
- 下面这个例子就会报错:
- 每个分布类的成员不能冲突,不能有同样参数的构造函数
- 各分布类完全靠编译器来进行解析:每个分布类在编译时必须可用,且在同一个Assembly里
- 如果有父类,可以在一个或多个分布类上指明,但必须一致
- 每个分布类可以独立的实现不同的接口
- 编译器无法保证各分布类的字段的初始化顺序
partial method 局部方法
- partial 类型可以有partial method
- 自动生成的分布类里可以有partial method,通常作为“钩子”使用,在另一部分的partial method里,我们可以对这个方法进行自定义。
- partial method由两部分组成:定义 和 实现。
- 定义部分 通常是生成的
- 实现部分 通常是手动编写的
- 如果partial method只有定义,没有实现,那么编译的时候该方法定义就没有了,调用该方法的代码也没有了。这就允许自动生成的代码可以自由的提供钩子,不用担心代码膨胀
- partial method必须是void,并且隐式private的
nameof 操作符 C# 6
- nameof 操作符会返回任何符号(类型、成员、变量…)的名字(string)
- 利于重构