const与readonly

  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 字段只能在该字段的声明中初始化

  当然,如果是静态只读字段,那么这个值只能够在初始化阶段或静态构造函数中修改。因此,我认为这是数据库连接字符串会定义成静态只读字段的原因吧。

 

原文地址:https://www.cnblogs.com/xianrongbin/p/2987991.html