C#中的常量和字段

1.常量

常量是一个特殊的符号,它有一个不改变的值,定义常量时,它的值必须在编译时确定,确定后编译器将常量的值保存到程序集的元数据中。常量总是被视为静态成员,而不是实例成员,定义常量将导致创建元数据。

这意味着只能为编译器确定的基元类型定义常量。然后C#也允许定义一个非基元类型的常量变量,前提是把它的值设为null。

class Program 
{
 public const Program p1 = null;

 public const Program p3 = new Program();//编译出错,只能用null对引用类型(字符串除外)的常量字段进行初始化

}

代码引用一个常量符号时,编译器会在定义常量的程序集的元数据中查找该符号,然后提取常量的值并将值嵌入生成的IL代码中,由于常量的值直接嵌入代码,所以运行时不会为常量分配任何内存,因此,不能获取常量的地址,也不能以传址的方式传递常量。

所以说常量没有很好的跨程序集版本控制特性,只有在确定一个符号的值从不变化时,才使用常量。

如果希望在运行时从一个程序集中提取另一个程序集中的值,那么不应该使用常量,而应该使用readonly字段。

2.字段

字段是一种数据成员,容纳了一个值类型的实例,或者对一个引用类型的引用。

CLR支持类型字段和实例字段,对于类型字段,用于容纳字段数据的动态内存是在类型对象中分配的。而类型对象是在类型加载到一个AppDomain时创建的,什么时候加载到AppDomain呢?这通常是在引用了该类型的任何方法首次进行JIT编译时。对于实例字段,用于容纳字段数据的动态内存则是在构造类型的一个实例时分配的

CLR支持readonly字段和read/write字段,大多数字段都是read/write的,代码执行中字段的值可以多次改变,但是readonly字段只能在一个构造器方法中写入。

    internal  class Manager
{

public readonly int d=200;
public Manager(int r)
{
//修改字读字段d,因为代码在构造器中,所以允许这样做。
this.d = r;
}
}
class Program 
{
public const Program p=null;
static void Main()
{

Manager m = new Manager(400);
Console.WriteLine(m.d);//
}

当某个字段时引用类型时,并且该字段标记为readonly,那么不可改变的是引用,而不是字段引用的对象:
 internal  class Manager 
{
public static readonly int[] n =new int[]{22,33,44,55,66};
public readonly int d=200;
public Manager(int r)
{
this.d = r;
}
}
class Program
{
public const Program p=null;
static void Main()
{

Manager.n[0] = 400;
Manager.n[1] = 800;
foreach (int p in Manager.n)
{
Console.WriteLine(p);
}//输出400,800,44,55,66
}
}



许多字段都是内联初始化的(直接在代码中赋值来初始化,而不是通过构造器。)C#允许使用这种方便的内联初始化语法来初始化类的常量,字段。但是C#实际是在构造器中对字段进行初始化的,字段的内联初始化只不过是语法上的简化而已。在C#中初始化一个字段时,如果使用内联语法,而不是在构造器中赋值,有一些性能问题需要考虑。
原文地址:https://www.cnblogs.com/smailxiaobai/p/2266436.html