【问题标题】:Local constant initialised to null reference局部常量初始化为空引用
【发布时间】:2011-08-22 20:38:21
【问题描述】:

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

const string MyString = null;

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

【问题讨论】:

  • 考虑到可能有多种用途,我认为这没有明确的答案。因此,它可能应该是一个社区 wiki。

标签: c# string reference null constants


【解决方案1】:

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

编辑: 另一个问题是,在什么情况下使用const 有什么好处?对于配置,您可能希望配置文件和其他变量通常会更改(除非它们是不可变的,但 readonly 更适合...)

【讨论】:

  • 如果你初始化记录器,你不能设置那个值?
  • @Derk 如果是状态发生了变化,那么我不会使用const。该示例假定 logger 是一个在运行时不会更改的全局设置。
  • 你有例子吗?我可以想象将它用作持有者(未来的实现)。一个好的情况可能是库设置(不可配置的设置,但是你不想硬编码的东西,或者在你的库中使用很多),版本号。 public/internal/private String const ErrorMessage = "Library Fault";
【解决方案2】:

确实,您可以将本地const 字符串和readonly 引用类型初始化为null,尽管这似乎是多余的,因为它们的默认值无论如何都是null

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

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

【讨论】:

  • @Derk-Jan,我所指的特殊情况是提问者想知道的“本地常量初始化为null”的情况。还有更多,我的意思是有时,即使一个特殊情况似乎没有意义,但为了支持更一般的情况,仍然值得保留它的行为。
  • 是的,我理解并 - 支持您所说的,但还有更多这样的没有意义但设计存在的吗?
  • @Derk-Jan,是的,很多。例如,您可以使用一个不执行任何操作的无参数构造函数来定义一个类,即使如果您不这样做,编译器也会为您生成完全相同的构造函数。这也是因为阻止你在这种情况下定义构造函数是不值得的(并且可能会让你生气)。
  • 酷。我从来没有这样想过——但我知道你可以做到。我们每天都在学习!
【解决方案3】:

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

const string UninitializedSetting = null;

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

【讨论】:

    【解决方案4】:

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

    可能存在一些非常有用的极端情况,例如多目标条件编译。 IE 您想为一个平台定义一个常量,但由于缺少功能而在另一个平台上将其定义为 null。

    例如,可能有用的用法:

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

    【讨论】:

    • 正是我正在寻找的那种示例用法,谢谢。
    【解决方案5】:

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

    【讨论】:

    • 感谢 Merlyn,明确方法重载就是一个很好的例子。
    【解决方案6】:

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

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

    10.4 以内的内容如下:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-03-17
      • 2016-09-07
      • 1970-01-01
      • 1970-01-01
      • 2021-05-25
      • 2014-01-08
      • 2012-10-03
      相关资源
      最近更新 更多