Chapter7 常量和字段

1.1 常量

常量(constant)是一个特殊的符号,它有一个从不变化的值,定义常量符号时,它的值必须能在编译时确定,确定之后,编译器将常量的值保存到程序集的元数据中。
这意味着只能为编译器认定的基元类型定义常量,也可以是非基元类型,但必须是null。
所以代码在引用一个常量符号时,不需要为常量分配任何内存,编译器会在元数据中提取常量值,嵌入的IL代码中。
除此之外,不能获取常量的地址,也不能按引用的方式传递常量。
这些限制意味着,常量没有很好的跨程序集版本特性 ,如果希望在运行时从一个程序集中提取另一个程序集中的值,那么不应该使用常量,而应该使用readonly字段

下面举个例子
将以下代码编译一个dll程序集(假定这个DLL程序集没有进行强命名)

using System;

namespace ClassLibrary
{
    public sealed class SomeType
    {
        //注意:C#不允许为常量指定static关键字,因为常量总是隐式的static
        public const Int32 constValue = 50;
        //将类型和字段关联,因为static修饰的字段是类型状态的一部分,static关键字是必需的
        public static readonly Int32 readOnlyValue = 50;
    }
}

1.打开cmd->输入命令cd C:\Windows\Microsoft.NET\Framework\v4.0.30319 进入Framework4.0的安装目录(不同机器可能安装路径不一样,也可以使用vs自带的命令行提示工具)。
2.将SomeType类型的代码源文件复制到上面目录,然后执行命令行:csc /target:library SomeType.cs,(csc.exe会默认reference MSCorLib.dll程序集)然后会生成一个SomeType.dll。
3.接着用下面代码生成一个应用程序程序集:

using System;

namespace ConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("const value:" + ClassLibrary.SomeType.constValue);
            Console.WriteLine("readonly value:" + ClassLibrary.SomeType.readOnlyValue);
            Console.ReadLine();
        }
    }
}

4.将包含上面代码的源文件复制到同样的目录下,执行命令行:csc /out:Main.exe /target:exe /r:SomeType.dll Program.cs,然后生成一个Main.exe的应用程序
运行Main.exe
结果:const value:50
readOnly value:50
5.现在把SomeType中的值改为:

public const Int32 constValue = 100;
public static readonly Int32 readOnlyValue = 100;

重新编译SomeType.dll,然后在运行Main.exe
结果:const value:50
readOnly value:100
显然常量的值没有变,所以常量没有很好的跨程序集版本特性

1.2字段

字段(field)是一种数据成员,其中容纳了一个值类型的实例或者对一个引用类型的引用
表格:
CLR支持类型字段(静态字段)和实例字段(非静态)。
对于静态字段,分配给它的内存是在类型对象中分配的,而类型对象是在类型加载到一个AppDomain时创建的,而AppDomain是在引用了该类型的方法首次进行JIT编译时加载的。
对于实例字段,内存则是在构造类型的一个实例时分配的。

CLR支持readonly字段和read/write字段,但大多是都是read/write字段(字段的值可多次改变),但是readonly字段只能在一个构造器方法中写入

//这是一个静态readonly字段,在运行时对这个类型进行初始化,它的值会被计算并存储到内存中
public static readonly Random s_random = new Random();
//这是个静态read/write字段
private static Int32 s_numberOfWrites=0;
//这是一个实例readonly字段
public readonly String Pathname = "Unitled";
//这是个实例read/write字段
private System.IO.FileStream m_fs;

public SomeType(String pathname)
{
//改行修改只读字段pathname,由于代码在构造器中所以可以这样做
this.Pathname = pathname;
}

public String DoSomething()
{
//该行读写静态read/write字段
s_numberOfWrites = s_numberOfWrites + 1;
//该行读取readonly实例字段
return Pathname;
}

上面许多字段都是内联初始化,这只是C#语法的一种简化,实际上还是在构造器中初始化。

原文地址:https://www.cnblogs.com/hailiang2013/p/2862545.html