为什么String.Empty不是常量?

时间:2009-02-03 16:49:47

标签: .net string readonly constants

在.Net中为什么String.Empty只读而不是常量?我只是想知道是否有人知道该决定背后的原因是什么。

4 个答案:

答案 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。只有结构才能做常量。我认为当您使用string而不是String时,编译器会将const更改为只读。这一切都与保持C程序员的快乐有关。 - Garry Shutler 2009年2月3日16:59

     tvanfosson刚才解释得有点冗长。 “X不能是一个常数,因为包含Y是一个类”只是有点太没有上下文;) - Leonidas 09年3月3日在17:01

     

string.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