C# 初始化为空引用的局部常量

C# 初始化为空引用的局部常量,c#,string,reference,null,constants,C#,String,Reference,Null,Constants,我已经读到C#允许将局部常量初始化为空引用,例如: const string MyString = null; 然而,这样做有什么意义吗?这有什么可能的用途?如果您使用常量(例如)来配置应用程序,那么为什么不使用呢?null值可以表示有效状态-例如,未安装记录器。还要注意,当您声明一个局部常量时,您可以将其初始化为全局常量给定的值(这可能是一个更有趣的场景) EDIT:另一个问题是,使用const的好情况是什么?对于配置,您可能希望配置文件和其他变量通常会发生更改(除非它们是不可变的,但是只读

我已经读到C#允许将局部常量初始化为空引用,例如:

const string MyString = null;

然而,这样做有什么意义吗?这有什么可能的用途?

如果您使用常量(例如)来配置应用程序,那么为什么不使用呢?
null
值可以表示有效状态-例如,未安装记录器。还要注意,当您声明一个局部常量时,您可以将其初始化为全局常量给定的值(这可能是一个更有趣的场景)


EDIT:另一个问题是,使用
const
的好情况是什么?对于配置,您可能希望配置文件和其他变量通常会发生更改(除非它们是不可变的,但是
只读
更适合…)

实际上,您可以将本地
常量
字符串和
只读
引用类型初始化为
,尽管它似乎是多余的,因为它们的默认值是
null

但是,
null
是一个编译时常量,足以初始化字符串和引用类型。因此,编译器必须走出它的道路,以便考虑、识别和拒绝这种特殊情况,即使从语言的观点来看,它仍然是完全有效的。
这样做的好处是有争议的,而且可能一开始就不值得付出努力。

如果你想编写没有关键字的代码,如果你喜欢的话,可以使用它:

const string UninitializedSetting = null;

if (mySetting == UninitializedSetting)
{
    Error("mySetting string not initialized");
}

我的猜测是因为null是一个有效的值,可以分配给引用类型和可为null的值类型。 我看不出有什么理由禁止这样做

这可能在某些边远的情况下很有用,例如多目标条件编译。IE您希望为一个平台定义一个常量,但由于缺少功能,为另一个平台将其定义为null

例如,可能有用的用途:

#IF (SILVELIGHT)
    public const string DefaultName = null;
#ELSE
    public const string DefaultName = "Win7";
#ENDIF 
选择命名一个值(而不是使用就地魔法常数)、使用
const
和设置为
null
或多或少都是正交的问题,尽管我同意维恩图可能会有非常小的重叠区域:)

我能想到的一种情况是,当您丢弃的数据与编写代码的数据一样多或更多时,但您希望确保在编写或维护代码时不会意外更改这些值。这种情况在单元测试中相当常见:

[Test]
public void CtorNullUserName()
{
    const string expectedUserName = null;

    var user = new User(expectedUserName);

    Assert.AreEqual(expectedUserName, user.Name, "Expected user name to be unchanged from ctor");
}
可以说,您可以通过多种方式构造这样的代码,而不需要将
null
赋值给
const
,但这仍然是一个有效的选项

这也可能有助于解决方法重载问题:

public class Something
{
    public void DoSomething(int? value) { Console.WriteLine("int?"); }
    public void DoSomething(string value) { Console.WriteLine("string"); }
}

// ...

new Something().DoSomething(null); // This is ambiguous, and won't compile

const string value = null;
new Something().DoSomething(value); // Not ambiguous

除了已经指出的情况外,这可能与C语言的一个怪癖有关。C#规范3.0第8.5.2节规定:

局部常量声明的类型和常量表达式必须遵循与常量成员声明相同的规则(§10.4)

第10.4条中的内容如下:

如§7.18所述,常量表达式是可在编译时完全计算的表达式。由于创建除字符串以外的引用类型的非null值的唯一方法是应用新运算符,并且由于常量表达式中不允许使用新运算符,因此除字符串以外的引用类型的常量的唯一可能值为null


如果初始化记录器,则无法设置该值?@Derk如果状态发生变化,则我不会使用
const
。本例假设logger是一个在运行时不会更改的全局设置。您有这样的示例吗?我可以想象使用它作为持有者(未来的实现)。一个好的情况可能是库设置(不是可配置的设置,而是您不希望硬编码的内容,或者在您的库中使用很多)、版本号<代码>公共/内部/私有字符串常量ErrorMessage=“库错误”@Derk Jan,我提到的特例是提问者想知道的“局部常量初始化为
null
”的情况。还有很多,我只是想说,有时候,即使一个特殊的案例似乎没有意义,为了支持一个更一般的案例,它仍然值得保持它的行为。是的,我理解并理解你所说的,但是还有很多类似的案例是没有意义的,而是通过设计存在的吗?@Derk Jan,是的,很多。例如,您可以使用一个不做任何事情的无参数构造函数定义一个类,即使如果您不这样做,编译器也会为您生成完全相同的类。这也是因为在这种情况下阻止您定义构造函数是不值得的(可以理解,这会让您生气)。酷。我从来没有这样想过,但我知道你能做到。我们每天都在学习!考虑到可能有多种用途,我不相信这有一个明确的答案。因此,它应该是一个社区wiki。这正是我想要的示例用法,谢谢。谢谢Merlyn,让方法重载明确无误是一个很好的示例。