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

本文关键字:局部 常量 引用 初始化 | 更新日期: 2023-09-27 17:55:49

我读过 C# 允许将局部常量初始化为 null 引用,例如:

const string MyString = null;

但是,这样做有什么意义吗?这可能有什么用途?

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

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

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

例如,可能有用的用途:

#IF (SILVELIGHT)
    public const string DefaultName = null;
#ELSE
    public const string DefaultName = "Win7";
#ENDIF 

事实上,你可以初始化本地const字符串并readonly引用类型来null,即使它似乎是多余的,因为它们的默认值无论如何都是null的。

但是,事实仍然是null是一个编译时常量,足以初始化字符串和引用类型。因此,编译器必须不遗余力地考虑、识别和拒绝这种特殊情况,即使从语言的角度来看它仍然是完全有效的。

这样做的好处是有争议的,而且一开始可能不值得付出努力。

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

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

选择命名一个值(而不是使用就地魔术常量)、使用 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

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

编辑:另一个问题是,无论如何,使用const的好情况是什么?对于配置,您可能需要一个配置文件,并且其他变量通常会更改(除非它们是不可变的,但readonly更适合......

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

局部常量声明

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

在10.4中内容如下:

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