在.Net中为什么String.Empty只读而不是常量?我只是想知道是否有人知道该决定背后的原因是什么。
答案 0 :(得分:133)
使用static readonly
代替const
的原因是由于使用了非托管代码,正如Microsoft Shared Source Common Language Infrastructure 2.0 Release中所述。要查看的文件是sscli20\clr\src\bcl\system\string.cs
。
空常量保持空 字符串值。我们需要打电话给 字符串构造函数使 编译器不会将此标记为 文字。
将此标记为文字意味着 它不会显示为一个字段 我们可以从本地访问。
我从this handy article at CodeProject找到了这些信息。
答案 1 :(得分:23)
我认为这里存在很多混乱和不良反应。
首先,const
个字段是static
个成员(非实例成员)。
检查10.4节C#语言规范的常量。
即使考虑了常数 静态成员,一个常量声明 既不需要也不允许静态 改性剂。
如果public const
成员是静态的,则不能认为常量会创建新的对象。
鉴于此,以下几行代码在创建新Object方面完全相同。
public static readonly string Empty = "";
public const string Empty = "";
以下是Microsoft的一份说明,解释了2:
之间的区别readonly关键字不同于 const关键字。 const字段可以 只能在声明中初始化 领域的。只读字段即可 在宣言中初始化 或者在构造函数中。因此, readonly字段可以有不同 值取决于构造函数 用过的。此外,虽然const字段是a 编译时常量,只读 字段可用于运行时 常数,......
所以我发现这里唯一合理的答案是杰夫耶茨的。
答案 2 :(得分:4)
String.Empty read only instead of a constant?
如果你使任何字符串保持不变,那么编译器将被实际字符串替换为你调用它的地方,并且你用相同的字符串填充你的代码。代码运行也需要一次又一次地读取来自不同内存数据的字符串。
如果您将字符串只读取在一个地方,因为它是String.Empty
,程序只在一个地方保留相同的字符串并读取它,或者参考它 - 将数据保存在内存中。< / p>
此外,如果使用String.Empty作为const编译任何dll,并且由于任何原因String.Empty发生更改,那么编译后的dll将不再起作用,因为cost
生成内部代码在每次通话中实际保留字符串的副本。
请参阅此代码:
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
编辑:纠正错字
答案 3 :(得分:0)
此答案出于历史目的。
<强>最初:强>
因为String
是一个类,因此不能是常量。
扩展讨论:
在审核这个答案时,很多有用的对话被敲定了,而不是删除它,这个内容直接转载:
在.NET中,(与Java不同)string和String完全相同。是的,你可以在.NET中使用字符串文字常量 - DrJokepu 2009年2月3日16:57
你是说一个班级不能有常数吗? - StingyJack 09年2月3日16:58
是的,对象必须使用readonly。只有结构才能做常量。我认为当您使用
tvanfosson刚才解释得有点冗长。 “X不能是一个常数,因为包含Y是一个类”只是有点太没有上下文;) - Leonidas 09年3月3日在17:01string
而不是String
时,编译器会将const更改为只读。这一切都与保持C程序员的快乐有关。 - Garry Shutler 2009年2月3日16:59string.Empty是静态属性,它返回String类的实例,即空字符串,而不是字符串类本身。 - tvanfosson 09年2月3日17:01
Empty是String类的只读实例(它不是属性)。 - senfo 2009年2月3日17:02
头部受伤。我仍然认为我是对的,但现在我不太确定。今晚需要研究! - Garry Shutler 2009年2月3日17:07
空字符串是字符串类的实例。 Empty是String类上的静态字段(不是属性,我会更正)。基本上指针与它指向的东西之间的区别。如果它不是readonly,我们可以更改Empty字段引用的实例。 - tvanfosson 2009年2月3日17:07
加里,你不需要做任何研究。想一想。 String是一个类。 Empty是String的一个实例。 - senfo 2009年2月3日17:12有些事我不太了解:String类的静态构造函数如何创建String类的实例?这不是某种“鸡肉或鸡蛋”的情景吗? - DrJokepu 2009年2月3日17:12 5
这个答案对于几乎任何其他类都是正确的,但System.String。 .NET为字符串做了很多性能特殊的外壳,其中一个就是你可以拥有字符串常量,只需尝试一下。在这种情况下,杰夫耶茨有正确的答案。 - Joel Mueller 2009年2月3日19:25
如第7.18节所述,constant-expression是一个可以在编译时完全评估的表达式。由于创建除字符串以外的引用类型的非空值的唯一方法是应用new运算符,并且因为常量表达式中不允许使用new运算符,所以引用类型的常量唯一可能的值除了字符串之外是null。前两条评论直接来自C#语言规范,并重申了Joel Mueller所提到的内容。 - senfo 2009年2月4日15:05 5