Why are we allowed to use const with reference types if we may only assign null to them?
这个问题实际上非常简单。以下代码在其正下方引发异常:
1 2 3 4 5 6 7 |
错误:
Foo.BarBuilder' is of type 'System.Text.StringBuilder'. A const field
of a reference type other than string can only be initialized with
null.
我理解,从
A constant expression is an expression that can be fully evaluated at
compile time. Therefore, the only possible values for constants of
reference types are string and a null reference.
然而,我不明白为什么或在哪里使用
更新:
当我们想到一个答案时,请让我们以不同于"我们有这个,为什么不……"的方式思考。
来自MSDN
when the compiler encounters a constant identifier in C# source code (for example, months), it substitutes the literal value directly into the intermediate language (IL) code that it produces. Because there is no variable address associated with a constant at run time, const fields cannot be passed by reference and cannot appear as an l-value in an expression.
因为在运行时需要构造引用类型(而不是空值和特殊的字符串),所以对于引用类型来说,上述方法是不可能的。
对于引用类型,最接近的是静态只读:
1 2 3 4 5 6 7 | class Foo { // This is not a good idea to expose a public non-pure field public static readonly StringBuilder BarBuilder = new StringBuilder(); public Foo(){ } } |
与const替换(在调用代码中)不同,
尽管不能(通常)重新分配引用,但它并不排除调用
However, I don't see the reason why or where we would use null constant.
空常量用作sentinel值。
例如,这:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | public class MyClass { private const Action AlreadyInvoked = null; private Action _action; public MyClass(Action action) { _action = action; } public void SomeMethod() { _action(); _action = AlreadyInvoked; } public void SomeOtherMethod() { if(action == AlreadyInvoked) { //... } } } |
比这更具表现力:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | public class MyClass { //... public void SomeMethod() { _action(); _action = null; } public void SomeOtherMethod() { if(action == null) { //... } } } |
1 2 3 4 5 | static readonly Func<T> ALREADY_INVOKED_SENTINEL = delegate { Contract.Assert(false,"ALREADY_INVOKED_SENTINEL should never be invoked."); return default(T); }; |
我认为您在问,为什么具有空值的引用类型允许作为常量。
我认为你是对的,它没有多大意义,但如果你设计了自己的库,如果你想与空值进行比较,但想给出特殊的意义(比如只与库值进行比较,而不是直接与空值进行比较),它是有用的。
1 2 3 4 5 6 7 | public class MyClass { public const MyClass MyClassNull = null; public MyClass() { } } |
它的用法是这样的。
1 2 3 4 | object obj = GetMyClass(); if(obj == MyClass.MyClassNull) // This going to convert to actual null in MSIL. { } |
正如您在问题中所述,有一个引用类型可以放入
当然,这就引出了一个问题——为什么不让字符串作为唯一可以是