在.NET/BCL源代码中混淆注释"string.Empty"的含义?

gdo*_*ica 33 .net c# compiler-construction string base-class-library

我试图理解为什么string.Emptyreadonly和不是const.我看过这篇帖子,但我不明白微软写的关于它的评论.正如Jon Skeet 在评论中所写的那样"我不知道 - 对我来说这没有多大意义,说实话......"

共享源公共语言基础结构2.0版本.string.cs位于sscli20\clr\src\bcl\system\string.cs中

// The Empty constant holds the empty string value.
//We need to call the String constructor so that the compiler doesn't mark this as a literal.
//Marking this as a literal would mean that it doesn't show up as a field which we can access 
//from native.
public static readonly String Empty = ""; 
Run Code Online (Sandbox Code Playgroud)

我在这里看不到任何String构造函数调用,而且,它被标记为文字 - ""

有人可以用明文解释我,评论意味着什么,为什么string.Empty readonly不是const


更新:
Eric Lippert现在评论了一个删除的答案:

我在午餐时间问了一位C#老人关于这一点,他没有具体回忆为什么做出这个决定,但推测这与实习有关.

Eug*_*eck 14

重要的部分不是在这个类中发生的事情,但是当另一个类使用(并链接到它)时会发生什么.让我用另一个例子解释一下:

假设您有一个包含类声明的Assembly1.dll

public static const int SOME_ERROR_CODE=0x10;
public static readonly int SOME_OTHER_ERROR_CODE=0x20;
Run Code Online (Sandbox Code Playgroud)

和另一个消耗这个例如

public int TryFoo() {
    try {foo();}
    catch (InvalidParameterException) {return SOME_ERROR_CODE;}
    catch (Exception) { return SOME_OTHER_ERROR_CODE;}
    return 0x00;
}
Run Code Online (Sandbox Code Playgroud)

您将类编译为Assembly2.dll并将其链接到Assembly1.dll,正如预期的那样,您的方法将在无效参数上返回0x10,在其他错误上返回0x20,在成功时返回0x00.

特别是,如果您创建包含类似的东西的Assembly3.exe

int errorcode=TryFoo();
if (errorcode==SOME_ERROR_CODE) bar();
else if (errorcode==SOME_OTHER_ERROR_CODE) baz();
Run Code Online (Sandbox Code Playgroud)

它将按预期工作(在与Assembly1.dll和Assembly2.dll链接后)

现在,如果你得到一个新版本的Assembly1.dll,那就有了

public const int SOME_ERROR_CODE=0x11;
public readonly int SOME_OTHER_ERROR_CODE=0x21;
Run Code Online (Sandbox Code Playgroud)

如果您重新编译Assembly3.exe并将最后一个片段链接到新的Assembly1.dll和未更改的Assembly2.dll,它将按预期停止工作:

bar()将无法正确调用:Assembly2.dll会记住LITERAL 0x20,它与Assembly3.exe从Assembly1.dll读取的文字0x21不同

将正确调用baz():Assembly2.dll和Assembly3.exe都引用名为SOME_OTHER_ERROR_CODE的SYMBOL REFERENCE,这两种情况都是由当前版本的Assembly1.dll解析的,因此在两种情况下都是0x21.

简而言之:a const创造a LITERAL,readonly创造a SYMBOL REFERENCE.

LITERALS 是框架内部的,不能编组,因此由本机代码使用.

所以

public static readonly String Empty = ""; 
Run Code Online (Sandbox Code Playgroud)

创建一个symbol reference(通过调用String cosntuctor在第一次使用时恢复),可以编组,因此从本机使用,而

public static const String Empty = ""; 
Run Code Online (Sandbox Code Playgroud)

会创建一个文字,但不能.

  • string.Empty没有被"记住"有什么好处,它不会被改变.const可以没事,不是吗? (2认同)
  • 我想了解为什么文字不可编组...文字和返回相同值的引用之间有什么不同? (2认同)
  • 尽管此答案正确地说明了为什么使用“只读”,但它绝不能回答问题。 (2认同)