字段(field)是类中最常见的成员之一。C# 支持静态字段(类型字段)和实例字段,而上一节《C# const》中介绍的常量属于特殊的静态字段。
对于实例字段,其内存在创建实例时动态分配,而对于静态字段,其内存在类型对象创建时分配。
类型对象是类型加载到一个应用程序域(AppDomain) 时创建的。
由 readonly (只读)修饰的字段只能在定义时或构造函数中赋值。
如果试图在构造函数之外的地方修改只读字段,就会发生编译错误。
不过,反射可以修改只读字段(实际上,没有什么是反射改不了的)。只读字段和常量很像,但也有如下区别:
假设直到运行时才知道值(例如通过读取外部数据库),并且希望之后值不会被改变,那么只读字段就很有用。
如果想将只读字段设置为静态的,而且也是直到运行时才知道值, 那么需要使用静态构造函数为其赋值。
注意,即使对于引用类型的只读字段,我们也可以更改引用类型引用对象的值,但是, 我们不能更改引用类型的引用本身。
下面的代码中,我们试图更改一个只读字符串字段的值,但是,更改字符串的值,实质上是在字符串池中新建一个字符串,并将栈上原字符串的变量指向堆中新的字符串,即为更改引用。所以,这是不可以的。
class Program
{
static void Main(string[] args)
{
A a = new A();
a.print(); //0
//可以更改引用对象成员的值
a.field.b = 999;
a.print(); //999
//但是不可以更改引用本身
//a.field = new B();
//a.str = "hello";
Console.ReadKey();
}
}
class A
{
public readonly B field;
public readonly string str;
public A()
{
field = new B();
}
public void print()
{
Console.WriteLine(field.b);
}
}
class B
{
public double b;
}