初始化为空引用的局部常量
本文关键字:局部 常量 引用 初始化 | 更新日期: 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。