在.NET / BCL源代码中混淆注释“string.Empty”的含义?
我试图理解为什么string.Empty
是readonly
而不是const
。 我看过这篇post,但我不明白微软写的关于它的评论。 正如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 = "";
我在这里看不到任何String构造函数调用,而且,它被标记为文字 – “”
有人可以用纯文本解释我,评论是什么意思,为什么是string.Empty
readonly
而不是const
?
更新:
Eric Lippert现在评论了一个删除的答案 :
我在午餐时间问了一位C#老人关于这一点,并且他没有具体回忆为什么做出这个决定,但推测这与实习有关。
重要的部分不是在这个类中发生的事情,但是当另一个类使用(并链接到它)时会发生什么。 让我用另一个例子解释一下:
假设您有一个包含类声明的Assembly1.dll
public static const int SOME_ERROR_CODE=0x10; public static readonly int SOME_OTHER_ERROR_CODE=0x20;
和另一个消耗这个例子
public int TryFoo() { try {foo();} catch (InvalidParameterException) {return SOME_ERROR_CODE;} catch (Exception) { return SOME_OTHER_ERROR_CODE;} return 0x00; }
您将类编译为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();
它将按预期工作(在与Assembly1.dll和Assembly2.dll链接后)
现在,如果你得到一个新版本的Assembly1.dll,那就有了
public const int SOME_ERROR_CODE=0x11; public readonly int SOME_OTHER_ERROR_CODE=0x21;
如果您重新编译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。
简而言之: const
创建一个LITERAL
, readonly
创建一个SYMBOL REFERENCE
。
LITERALS
是框架的内部,无法编组,因此可以由本机代码使用。
所以
public static readonly String Empty = "";
创建一个symbol reference
(通过调用String cosntuctor在第一次使用时重新调整),可以编组,因此可以从本机使用,而
public static const String Empty = "";
会创建一个文字,但不能。