为什么不是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:59tvanfosson只是稍微详细地解释了一下。 “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