为什么不是String.Empty常量?

在.Net中,为什么String.Empty只读而不是一个常量? 我只是想知道是否有人知道这个决定背后的推理。

使用static readonly而不是const的原因是由于使用了非托pipe代码,正如Microsoft在这里共享源公共语言基础结构2.0版本中所指出的那样。 要查看的文件是sscli20\clr\src\bcl\system\string.cs

Empty常量保存空string值。 我们需要调用String构造函数,以便编译器不会将其标记为文字。

将其标记为字面意味着它不会显示为我们可以从本地访问的字段。

我从CodeProject上的这篇方便的文章中find了这些信息。

我觉得这里有很多困惑和不好的回应。

首先, const字段是static成员( 不是实例成员 )。

检查部分10.4 C#语言规范的常量。

即使常量被认为是静态成员,常量声明既不需要也不允许静态修饰符。

如果public const成员是静态的,不能认为常量会创build一个新的Object。

鉴于此,以下几行代码在创build新对象方面做了完全相同的事情。

 public static readonly string Empty = ""; public const string Empty = ""; 

这里是微软的一个说明,解释了2:

readonly关键字与const关键字不同。 const字段只能在该字段的声明处初始化。 readonly字段可以在声明中或在构造函数中初始化。 因此,只读字段可以具有不同的值,具体取决于所使用的构造函数。 此外,虽然const字段是编译时常量,只读字段可用于运行时常量,…

所以我发现这里唯一合理的答案是杰夫·耶茨(Jeff Yates)的答案。

 String.Empty read only instead of a constant? 

如果你使任何string都是常量 ,那么编译器会被你所调用的实际string所取代,而且你用相同的string填充你的代码,当代码运行的时候也需要再次读取来自不同内存的string数据。

如果你把string只读在一个地方,因为它是String.Empty ,程序只保留在同一个地方的string,并读取它,或引用它 – 保持在内存中的数据最小。

另外,如果你使用String.Empty作为const编译任何dll,并且由于任何原因String.Empty改变,那么编译后的dll将不再起作用,因为cost使内部代码实际上保留了每个通话都有string。

例如看这个代码:

 public class OneName { const string cConst = "constant string"; static string cStatic = "static string"; readonly string cReadOnly = "read only string"; protected void Fun() { string cAddThemAll ; cAddThemAll = cConst; cAddThemAll = cStatic ; cAddThemAll = cReadOnly; } } 

将由编译器来作为:

 public class OneName { // note that the const exist also here ! private const string cConst = "constant string"; private readonly string cReadOnly; private static string cStatic; static OneName() { cStatic = "static string"; } public OneName() { this.cReadOnly = "read only string"; } protected void Fun() { string cAddThemAll ; // look here, will replace the const string everywhere is finds it. cAddThemAll = "constant string"; cAddThemAll = cStatic; // but the read only will only get it from "one place". cAddThemAll = this.cReadOnly; } } 

和程序集调用

  cAddThemAll = cConst; 0000003e mov eax,dword ptr ds:[09379C0Ch] 00000044 mov dword ptr [ebp-44h],eax cAddThemAll = cStatic ; 00000047 mov eax,dword ptr ds:[094E8C44h] 0000004c mov dword ptr [ebp-44h],eax cAddThemAll = cReadOnly; 0000004f mov eax,dword ptr [ebp-3Ch] 00000052 mov eax,dword ptr [eax+0000017Ch] 00000058 mov dword ptr [ebp-44h],eax 

编辑:更正了错字

这个答案存在历史的目的。

本来:

因为String是一个类,因此不能是一个常量。

扩展讨论:

在审核这个答案时敲定了很多有用的对话,而不是删除它,直接转载此内容:

在.NET中,(与Java不同)string和string完全相同。 是的,你可以在.NET中的string字面量常量 – DrJokepu 09年2月3日在16:57

你是说一个类不能有常量吗? – – StingyJack 09年2月3日在16:58

是的,对象必须使用只读。 只有结构可以做常量。 我想当你使用string而不是String ,编译器会将const更改为只读。 所有与保持C程序员快乐。 – – Garry Shutler 09年2月3日在16:59

tvanfosson只是稍微详细地解释了一下。 “X不能是一个常量,因为包含Y是一个类”只是有点太上下文无聊) – – Leonidas 09年2月3日在17:01

string.Empty是返回String类实例的静态属性,即空string,而不是string类本身。 – – tvanfosson 09年2月3日在17:01

Empty是String类的只读实例(它不是属性)。 – – senfo 09年2月3日在17:02

头疼。 我仍然认为我是对的,但现在我不太确定。 今晚要求研究! – – Garry Shutler 09年2月3日在17:07

空string是string类的一个实例。 Empty是String类中的一个静态字段(不是一个属性,我站着纠正)。 基本上是指针和它指向的东西之间的区别。 如果它不是只读的,我们可以改变空字段指向哪个实例。 – – tvanfosson 09年2月3日在17:07

加里,你不需要做任何研究。 想想看。 string是一个类。 Empty是一个String的实例。 – – senfo 09年2月3日在17:12

有一些我不太清楚:String类的静态构造函数如何创buildString类的实例? 那不是某种“鸡还是蛋”的情景? – DrJokepu 2月3日在17:12 5

这个答案对于几乎任何其他类,但是System.String都是正确的。 .NET为string做了很多性能特殊的工作,其中一个就是你可以有string常量,试试吧。 在这种情况下,杰夫耶茨有正确的答案。 – – 乔尔米勒2009年2月3日在19:25

如§7.18所述,一个常量expression式是一个可以在编译时全面评估的expression式。 由于创build除string以外的引用types的非空值的唯一方法是应用new运算符,并且由于new运算符不允许在常量expression式中,所以引用types常量的唯一可能值除string以外为空。 前两个意见直接来自C#语言规范,并重申了Joel Mueller提到的内容。 – – senfo 2年2月4日在15:05 5