const
值可以在静态只读字段无法使用的情况下使用(例如作为默认参数值)。 它们也被“烘焙”到编译代码中,在某些情况下这是不好的,但在其他情况下可能会有用。 - supercatC#中的Const表示它可以在编译时确定,这就是为什么只有非常基础的类型比如int
和string
才能被定义为const。
如果你来自于C语言背景,也许readonly
关键字更适合你。
readonly T
where T:struct
的类似物应该是const T&
(在C ++中)。但是,大多数情况下,当人们遇到C#中的readonly
关键字时,实际上是在寻找C ++对“常量正确性”的支持,而这在C#中并不存在(而新的一组Immutable类/模式则尝试提供一种类似但相当笨拙且费力的替代方法)。 - binkireadonly T
创造了一个不可变的字段,该值存储在该字段本身中 -- 而不是像 C++ 引用那样存在别处。 - cdhowieconst
值,它必须知道所有字段中应该放置的值。C#编译器本身知道如何初始化某些类型(如Decimal
)的字段,但对于大多数值类型,它没有这样的知识。struct
字段都被公开的情况下。如果结构体的字段是private
,那么该类型的常量只能在结构体内部声明;如果字段是internal
,则可以在程序集中的任何地方声明常量;如果字段是public
,则可以在任何地方声明常量。static readonly
变量则无法做到。例如,如果NumRows
是一个等于4的常量,则像Arr[3 * NumRows + 7]
这样的表达式可以替换为Arr[19]
,即使NumRows
是在外部程序集中定义的。这使得这些常量比static readonly
变量具有重要的优势。然而,如果一个常量是编译器不知道的类型,它将极度受限于参与任何常量表达式的能力,从而有效地抵消了它作为常量的优势。如果值类型常量有一个公开的字段,编译器可以使用该字段的值作为常量,但由于.NET语言的创建者在哲学上反对具有公开字段的结构体,即使他们有能力这样做,我也不指望他们允许这种用法。static readonly
变量相比较,有一些潜在的用例,但许多这样的情况可以使用现有类型来处理得到。例如,库可能会公开一个const Int64
来编码关于其版本的信息,并将该值用作GetLinkedVersionInfo
方法的默认参数值。当编译调用代码时,该值将被“烘焙”进去,从而允许该方法报告调用者链接的库的版本,并可能确定是否存在与运行的版本不兼容的问题。我刚刚使用一个简单的可变结构体测试了readonly
关键字:
struct Test
{
public int value;
public void setInt(int val)
{
value = val;
}
}
static class Program
{
public static readonly Test t = new Test();
static void Main()
{
Console.WriteLine(t.value); // Outputs "0"
t.setInt(10);
//t.value = 10; //Illegal, will not let you assign field of a static struct
Console.WriteLine(t.value); // Still outputs "0"
}
}
readonly
结构体在技术上不是编译时常量,但运行时不允许其改变。即使通过setInt()
方法进行调试,它看起来像值会改变,但在Main中并没有显示出变化。
我猜测这个结构体本身被放置在“只读”内存中,禁止它们进行更改。与类不同,后者仅保持指针恒定,允许类字段自由更改。
因此,即使对于可变的结构体,static readonly
实际上也相当于const
。ref
参数的形式接收this
,但在vb.net和C#中存在一个令人讨厌的怪癖:如果在只读结构体实例上调用结构体方法或属性,则编译器会默默地复制该实例并将其传递给相关代码。这在代码不修改结构体的情况下产生了缓慢但正确的语义,并在代码修改结构体的情况下产生破坏性的语义。我希望微软能够定义一个属性... - supercatthis
的方法在只读结构体上使用,但禁止使用会修改的方法。否则,最好的选择是接受annoying和ugly语法public static void setInt(ref Test it, int val)
和Test.setInt(ref t, 10)
,如果你尝试在只读变量t
上使用它将正确地产生错误提示。 - supercatref
参数与对象引用,我认为 .NET 如果有独立的复制输入、复制输出、复制输入输出、只读引用和读写引用参数类型会更好。 - supercatreadonly
值成员,那么像 void DoThing(readonly ref MyStruct s);
这样扩展 ref
就非常自然,因为 ref
参数已经像成员一样行为了。添加语言和运行时支持“纯”函数(或者再次使用 readonly
关键字?),你就可以拥有重要的 const 正确性语义。如果只有… - binki