const :编译时常量,即编译时确定数据。
readyonly :运行时常量 ,即运行时被计算,其编译后的IL将维持对变量的引用,而非它的值得引用,类似于c语言的地址。
编译时常量只可用于基元类型、枚举类型,因为只有这些类型才允许我们在初始化中指定有意义的常量值。
何为基元类型?编译器能够直接支持的数据类型叫做基元类型,下面的类型就是基元类型。
sbyte / byte / short / ushort / int / uint / long / ulong/char / float / double / bool / decimal /object / string
这里顺便带一下什是值类型,下面就是值类型
sbyte / byte / short / ushort / int / uint / long / ulong / char / float / double / bool / decimal / 枚举(enum) / 结构(struct)
那么什么是引用类型呢
引用对象(Object) / 字符串(String) / 数组(Array) / 装箱后的值类型
说到现在,这两个东西现在到底有什么不同呢,请看下面的事例
public class UsefulValues
{
public static readonly int StartValue = 105;
public const int EndValue = 120;
}
如果单纯在VS编译器中看,则看不出StartValue与EndValue这两个变量不同点,但经过反编译器观察,你则会了解许多。
反编译器中的代码是这样的:
public class UsefulValues { // Fields public const int EndValue = 120; public static readonly int StartValue; // Methods static UsefulValues(); public UsefulValues(); }
其中 静态构造函数如下
static UsefulValues() { StartValue = 0x69; } |
其中0x表示16进制(比如我们的网页颜色#FF8899,就是16进制),计算一下:16*6+9=105。
编译器在编译的时候已经给EndValue指定值了,而StartValue的值是在静态构造函数中才给其赋值,而静态构造函数只有运行时才会调用。
让我们在看看IL代码是怎样的吧
.field public static literal int32 EndValue = int32(120) .field public static initonly int32 StartValue
initonly 指示变量赋值可以只为声明的一部分或在同一个类的静态构造函数
literal:字面值。这里即EndValue 常量直接被替换为它的字面值120。
运行时常量和编译时常量最重要的区别就 在于运行时常量值的辨析发生在运行时,而编译时常量值的辨析发生编译时。换言之,使用运行时常量编译后的IL代码引用的是readonly变量的地址,而非它的值;而使用编译时常量编译后的IL代码将直接引用它的值。
把微软的官方解释拿过来总结一下: readonly 字段可以在声明或构造函数中初始化, 因此,根据所使用的构造函数,readonly 字段可能具有不同的值。 const 字段只能在该字段的声明中初始化。
当然,如果是静态只读字段,那么这个值只能够在初始化阶段或静态构造函数中修改。因此,我认为这是数据库连接字符串会定义成静态只读字段的原因吧。