为什么 String.Empty 不是常量?

发布于 2024-07-12 08:26:17 字数 83 浏览 4 评论 0 原文

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

In .NET why is String.Empty read only instead of a constant? I'm just wondering if anyone knows what the reasoning was behind that decision.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

复古式 2024-07-19 08:26:17

使用 static readonly 而不是 const 的原因是与非托管代码一起使用,如 Microsoft 在 共享源公共语言基础结构 2.0 版本。 要查看的文件是 sscli20\clr\src\bcl\system\string.cs。

Empty 常量保存空值
字符串值。 我们需要调用
字符串构造函数使得
编译器不会将其标记为
字面意思。

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

我从CodeProject 上这篇方便的文章中找到了此信息。

The reason that static readonly is used instead of const is due to use with unmanaged code, as indicated by Microsoft here in the Shared Source Common Language Infrastructure 2.0 Release. The file to look at is sscli20\clr\src\bcl\system\string.cs.

The Empty constant holds the empty
string value. We need to call the
String constructor so that the
compiler doesn't mark this as a
literal.

Marking this as a literal would mean
that it doesn't show up as a field
which we can access from native.

I found this information from this handy article at CodeProject.

落日海湾 2024-07-19 08:26:17

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

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

请查看 C# 语言规范的第 10.4 节常量。

即使考虑常量
静态成员,常量声明
既不需要也不允许静态
修饰符。

如果public const成员是静态的,就不能认为常量会创建一个新对象。

鉴于此,以下代码行在创建新对象方面完全相同执行相同的操作。

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

以下是 Microsoft 的注释,解释了两者之间的区别:

readonly 关键字不同于
const 关键字。 const 字段可以
仅在声明时初始化
领域的。 只读字段可以是
在声明处初始化
或在构造函数中。 所以,
只读字段可以有不同的
值取决于构造函数
用过的。 另外,虽然 const 字段是
编译时常量,只读
字段可用于运行时
常数,...

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

I think there is a lot of confusion and bad responses here.

First of all, const fields are static members (not instance members).

Check section 10.4 Constants of the C# language specification.

Even though constants are considered
static members, a constant-declaration
neither requires nor allows a static
modifier.

If public const members are static, one could not consider that a constant will create a new Object.

Given this, the following lines of code do exactly the same thing in respect to the creation of a new Object.

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

Here is a note from Microsoft that explains the difference between the 2:

The readonly keyword is different from
the const keyword. A const field can
only be initialized at the declaration
of the field. A readonly field can be
initialized either at the declaration
or in a constructor. Therefore,
readonly fields can have different
values depending on the constructor
used. Also, while a const field is a
compile-time constant, the readonly
field can be used for runtime
constants, ...

So I find that the only plausible answer here is Jeff Yates's.

北陌 2024-07-19 08:26:17
String.Empty read only instead of a constant?

如果您设置任何字符串常量,那么编译器将在您调用它的任何地方替换为实际字符串,并且在代码运行时用相同的字符串填充您的代码还需要一次又一次地从不同的内存数据中读取该字符串。

如果您将字符串保留在一处只读,因为它是 String.Empty,则程序仅将相同的字符串保留在一处并读取它,或引用它 - 将内存中的数据保持最少。

另外,如果您使用 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 

编辑:更正的拼写错误

String.Empty read only instead of a constant?

If you make any string constant, then the compiler is replace with the actually string everywhere you call it and you fill your code with the same string all over and when the code runs is also need to read again and again that string from the different memory data.

If you leave your string read only on one place as it is the String.Empty, the program keep the same string only on one place and read it, or refer to it - keeping the data in memory minimum.

Also if you compile any dll using the String.Empty as const, and for any reason the String.Empty change, then the compiled dll will not work any more the same, because the cost make the inside code to actually keep a copy of the string on every call.

See this code for example:

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;    
    }
}

will be come by the compiler as:

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;

    }
}

and the assembly call

        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 

Edit: Corrected typo

一身骄傲 2024-07-19 08:26:17

这个答案的存在是为了历史目的。

原来:

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

扩展讨论:

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

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

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

是的,对象必须使用只读。 只有结构体可以做常量。 我认为当您使用 string 而不是 String 时,编译器会将 const 更改为只读。 所有这些都是为了让 C 程序员开心。 – Garry Shutler,2009 年 2 月 3 日 16:59

tvanfosson 只是解释得更详细一些。 “X 不能是常量,因为包含的 Y 是一个类”有点太上下文无关了 ;) – Leonidas Feb 3 '09 at 17:01

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

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

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

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

Garry,你不需要做任何研究。 想一想。 字符串是一个类。 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 节中所述,常量表达式是可以在编译时完全求值的表达式。 由于创建除字符串之外的引用类型的非空值的唯一方法是应用 new 运算符,并且由于常量表达式中不允许使用 new 运算符,因此引用类型常量的唯一可能值除字符串之外的其他内容为空。 前两条评论直接取自 C# 语言规范,并重申了 Joel Mueller 提到的内容。 – senfo 2009 年 2 月 4 日 15:05
5

This answer exists for historical purposes.

Originally:

Because String is a class and therefore cannot be a constant.

Extended Discussion:

A lot of useful dialog was hammered out in vetting this answer, and rather than deleting it, this content is reproduced directly:

In .NET, (unlike in Java) string and String are exactly the same. And yes, you can have string literal constants in .NET – DrJokepu Feb 3 '09 at 16:57

Are you saying that a Class cannot have constants? – StingyJack Feb 3 '09 at 16:58

Yes, objects have to use readonly. Only structs can do constants. I think when you use string instead of String the compiler changes the const into a readonly for you. All to do with keeping C programmers happy. – Garry Shutler Feb 3 '09 at 16:59

tvanfosson just explained it a little bit more verbose. "X cannot be a constant, because the containing Y is a class" was just a little bit too context-free ;) – Leonidas Feb 3 '09 at 17:01

string.Empty is static property that returns an instance of the String class, namely the empty string, not the string class itself. – tvanfosson Feb 3 '09 at 17:01

Empty is a readonly instance (it's not a property) of the String class. – senfo Feb 3 '09 at 17:02

Head hurting. I still think I'm right, but now I'm less certain. Research required tonight! – Garry Shutler Feb 3 '09 at 17:07

The empty string is an instance of the string class. Empty is a static field (not a property, I stand corrected) on the String class. Basically the difference between a pointer and the thing it points to. If it weren't readonly we could change which instance the Empty field refers to. – tvanfosson Feb 3 '09 at 17:07

Garry, you don't need to do any research. Think about it. String is a class. Empty is an instance of a String. – senfo Feb 3 '09 at 17:12

There is something I don't quite get: how on earth can the static constructor of the String class create an instance of the String class ? Isn't that some sort of "chicken or the egg" scenario? – DrJokepu Feb 3 '09 at 17:12
5

This answer would be correct for nearly any other class but System.String. .NET does a lot of performance special-casing for strings, and one of them is that you CAN have string constants, just try it. In this case, Jeff Yates has the correct answer. – Joel Mueller Feb 3 '09 at 19:25

As described in §7.18, a constant-expression is an expression that can be fully evaluated at compile-time. Since the only way to create a non-null value of a reference-type other than string is to apply the new operator, and since the new operator is not permitted in a constant-expression, the only possible value for constants of reference-types other than string is null. The previous two comments were taken directly from the C# language specification and reiterate what Joel Mueller mentioned. – senfo Feb 4 '09 at 15:05
5

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文