const
和readonly
相似,但并不完全相同。
甲const
字段是一个编译时间常数,这意味着该值可以在编译时计算。甲readonly
字段允许在其中一些代码必须结构的类型的期间运行附加情景。构造后,readonly
不能更改字段。
例如,const
成员可用于定义成员,例如:
struct Test
{
public const double Pi = 3.14;
public const int Zero = 0;
}
由于像3.14和0这样的值是编译时常量。但是,请考虑定义一种类型并想提供一些预制实例的情况。例如,您可能想要定义一个Color类,并为常见的颜色(如黑色,白色等)提供“常量”。使用const成员是不可能的,因为右侧不是编译时常量。可以使用常规静态成员执行此操作:
public class Color
{
public static Color Black = new Color(0, 0, 0);
public static Color White = new Color(255, 255, 255);
public static Color Red = new Color(255, 0, 0);
public static Color Green = new Color(0, 255, 0);
public static Color Blue = new Color(0, 0, 255);
private byte red, green, blue;
public Color(byte r, byte g, byte b) => (red, green, blue) = (r, g, b);
}
但是,没有什么可以阻止Color的客户使用它了,也许可以通过交换Black和White值来解决。不用说,这会使Color类的其他客户端感到震惊。“只读”功能解决了这种情况。
通过readonly
在声明中简单地引入关键字,我们保留了灵活的初始化,同时防止了客户端代码的混乱。
public class Color
{
public static readonly Color Black = new Color(0, 0, 0);
public static readonly Color White = new Color(255, 255, 255);
public static readonly Color Red = new Color(255, 0, 0);
public static readonly Color Green = new Color(0, 255, 0);
public static readonly Color Blue = new Color(0, 0, 255);
private byte red, green, blue;
public Color(byte r, byte g, byte b) => (red, green, blue) = (r, g, b);
}
有趣的是,const成员始终是静态的,而readonly成员可以是静态的,也可以不是静态的,就像常规字段一样。
可以将单个关键字用于这两个目的,但这会导致版本问题或性能问题。假设一会儿,我们为此关键字(const)使用了一个关键字,并且开发人员写道:
public class A
{
public static const C = 0;
}
另一位开发人员编写了依赖于A的代码:
public class B
{
static void Main() => Console.WriteLine(A.C);
}
现在,生成的代码是否可以依赖AC是编译时常量的事实?即,AC的使用是否可以简单地替换为值0?如果对此说“是”,则意味着A的开发人员无法更改AC初始化的方式-未经许可,这会束缚A的开发人员的双手。
如果您对这个问题说“否”,那么将错过重要的优化。也许A的作者肯定AC将始终为零。const和readonly的使用允许A的开发人员指定意图。这样可以实现更好的版本控制行为以及更好的性能。
static readonly
:尝试在内部使用const,IEnumerator
这将触发无法确定的操作,yield
并且您会收到可怕的“内部编译器错误”。我没有在Unity3D之外测试代码,但是我相信这是mono或.NET bug。但是,这是一个C#问题。