.net 为什么不是';t字符串。是否为常数?

.net 为什么不是';t字符串。是否为常数?,.net,string,readonly,constants,.net,String,Readonly,Constants,在.NET中,String.Empty为什么是只读的而不是常量?我只是想知道是否有人知道这个决定背后的原因。这个答案是出于历史目的而存在的 原版: 因为String是一个类,因此不能是常量 扩展讨论: 在审查这一答案时,大量有用的对话被敲定,而不是将其删除,而是直接复制以下内容: 在.NET中,(与Java不同)字符串和字符串完全相同。是的,您可以在.NET中使用字符串文字常量–DrJokepu 2009年2月3日16:57 你是说一个类不能有常数吗吝啬鬼杰克2009年2月3日16:58 是的,

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

这个答案是出于历史目的而存在的

原版:

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

扩展讨论:

在审查这一答案时,大量有用的对话被敲定,而不是将其删除,而是直接复制以下内容:

在.NET中,(与Java不同)字符串和字符串完全相同。是的,您可以在.NET中使用字符串文字常量–DrJokepu 2009年2月3日16:57

你是说一个类不能有常数吗吝啬鬼杰克2009年2月3日16:58

是的,对象必须使用只读。只有结构可以执行常量。我认为当您使用
string
而不是
string
时,编译器会将常量更改为只读。所有这些都是为了让C程序员开心加里·舒特勒2009年2月3日16:59

tvanfosson只是解释得更详细一点。“X不能是常数,因为包含Y的是一个类”与上下文无关;)-利奥尼达斯2009年2月3日17:01

string.Empty是一个静态属性,返回string类的实例,即空字符串,而不是string类本身tvanfosson 2009年2月3日17:01

Empty是String类的只读实例(不是属性)senfo 2009年2月3日17:02

头部受伤。我仍然认为我是对的,但现在我不太确定了。今晚需要进行研究!——加里·舒特勒2009年2月3日17:07

空字符串是string类的一个实例。Empty是String类上的一个静态字段(不是属性,我已更正)。基本上就是指针和它指向的东西之间的区别。如果不是只读的,我们可以更改空字段引用的实例tvanfosson 2009年2月3日17:07

加里,你不需要做任何研究。想想看。字符串是一个类。Empty是字符串的一个实例senfo 2009年2月3日17:12

有一点我不太明白:String类的静态构造函数究竟如何创建String类的实例?这不是某种“鸡还是蛋”的情景吗DrJokepu 2009年2月3日17:12 五,


这个答案几乎适用于除System.String之外的任何其他类。NET为字符串做了很多性能特殊的大小写,其中之一是可以有字符串常量,只要试试就可以了。在这种情况下,杰夫·耶茨给出了正确的答案Joel Mueller 2009年2月3日19:25

如§7.18所述,常量表达式是可在编译时完全计算的表达式。由于创建除字符串以外的引用类型的非null值的唯一方法是应用新运算符,并且由于常量表达式中不允许使用新运算符,因此除字符串以外的引用类型的常量的唯一可能值为null。前两条评论直接取自C语言规范,并重申了Joel Mueller提到的内容senfo 2009年2月4日15:05 五,


使用
static readonly
而不是
const
的原因是与非托管代码一起使用,如Microsoft在中所示。要查看的文件是
sscli20\clr\src\bcl\system\string.cs

Empty常量保存空值 字符串值。我们需要打电话给警察 字符串构造函数,以便 编译器不会将此标记为 文字

将此标记为文字将意味着 它没有显示为字段 我们可以从本地访问它


我从中找到了这些信息。

我认为这里有很多混乱和糟糕的反应

首先,
const
字段是
静态
成员(不是实例成员

检查C语言规范第10.4节常量

即使考虑了常数 静态成员,一个常量声明 既不需要也不允许静态 修饰语

如果<代码>公共const 成员是静态的,则不能考虑常量将创建新对象。

public static readonly string Empty = "";
public const string Empty = "";
鉴于此,以下代码行在创建新对象方面做了完全相同的事情

public static readonly string Empty = "";
public const string Empty = "";
以下是Microsoft的一条说明,解释了2之间的区别:

readonly关键字不同于 const关键字。常量字段可以 只能在声明时初始化 这场比赛的最后一场。可以创建只读字段 在声明中初始化 或者在构造函数中。所以,, 只读字段可以具有不同的 值取决于构造函数 用过。此外,常量字段是 编译时常量,只读 字段可用于运行时 常数

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

String.Empty read only instead of a constant?
如果将任何字符串设为常量,则编译器将被替换为实际字符串,无论您在哪里调用它,您都将使用相同的字符串填充代码,并且当代码运行时,还需要从不同的内存数据中反复读取该字符串

如果将字符串保留在一个位置上,因为它是
字符串.Empty
,则程序只在一个位置上保留相同的字符串并读取它,或引用它-将内存中的数据保持在最小值

另外,如果您使用字符串.Empty作为const编译任何dll,并且由于任何原因字符串.Empty发生了更改,那么编译后的dll将不再工作,因为
成本
使内部代码在每次调用时实际保留字符串的副本

请参见以下代码示例:

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 
编辑:Corre