本文介绍了的String.Empty的行为改变(或System.String ::空)在.NET 4.5的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

短版:

在C#code

typeof(string).GetField("Empty").SetValue(null, "Hello world!");
Console.WriteLine(string.Empty);

编译和运行的时候,给人的输出世界,你好!在.NET 4.0和更早的版本,但给 .NET 4.5和.NET 4.5.1下。

when compiled and run, gives output "Hello world!" under .NET version 4.0 and earlier, but gives "" under .NET 4.5 and .NET 4.5.1.

如何写一个字段被忽略这样的,或者,谁重置这个领域?

How can a write to a field be ignored like that, or, who resets this field?

更长的版本:

我从来没有真正理解为什么的String.Empty 字段(也称为 [mscorlib程序] System.String ::空缺)是不是常量(又名文字),请参阅的。这意味着,例如,在C#中,我们不能使用的String.Empty 在以下几种情况:

I have never really understood why the string.Empty field (also known as [mscorlib]System.String::Empty) is not const (aka. literal), see "Why isn't String.Empty a constant?". This means that, for example, in C# we can't use string.Empty in the following situations:

  • 在一个开关的形式声明情况的String.Empty:
  • 作为可选参数的默认值,例如无效M(字符串x =的String.Empty){}
  • 在申请时的属性,如 [SomeAttribute(的String.Empty)]
  • 其中编译时间常数规定的其他情形
  • In a switch statement in the form case string.Empty:
  • As the default value of an optional parameter, like void M(string x = string.Empty) { }
  • When applying an attribute, like [SomeAttribute(string.Empty)]
  • Other situations where a compile-time constant is required

有含义的著名的宗教战争在是否使用的String.Empty ,见在C#中,我应该使用的String.Empty或的String.Empty或QUOT;"?

which has implications to the well-known "religious war" over whether to use string.Empty or "", see "In C#, should I use string.Empty or String.Empty or ""?".

几年前,我自己开心地通过反射设置空缺其他一些字符串实例,看看如何BCL许多地方开始表现的很奇怪,因为它。这是相当多的。而其中的变化空缺引用似乎持续应用的整个生命。现在,有一天,我想再说一遍,有点噱头,但使用.NET 4.5的机器,我不能这样做了。

A couple of years ago I amused myself by setting Empty to some other string instance through reflection, and see how many parts of the BCL started behaving strangely because of it. It was quite many. And the change of the Empty reference seemed to persist for the complete life of the application. Now, the other day I tried to repeat that little stunt, but then using a .NET 4.5 machine, and I couldn't do it anymore.

(NB!如果您有.NET 4.5的机器上,可能是你的的PowerShell 仍然使用.NET的旧版本,所以尽量复制粘贴 [字符串] .GetField(空)。的SetValue($空,世界,你好!)到PowerShell来查看更改此引用有一定的影响。)

(NB! If you have .NET 4.5 on your machine, probably your PowerShell still uses an older version of .NET, so try copy-pasting [String].GetField("Empty").SetValue($null, "Hello world!") into PowerShell to see some effects of changing this reference.)

当我试图寻找一个理由,我偶然发现了有趣的线索这是什么FatalExecutionEngineError在.NET 4.5的原因公测?。在接受这个问题的答案,是它指出,通过4.0版本, System.String 有一个静态构造函数 .cctor 在该领域空缺设置(在C#源代码,这很可能只是一个字段初始值,当然),而4.5没有静态构造函数存在。在这两个版本,本场本身看起来是一样的:

When I tried to search for a reason for this, I stumbled upon the interesting thread "What's the cause of this FatalExecutionEngineError in .NET 4.5 beta?". In the accepted answer to that question, is it noted that through version 4.0, System.String had a static constructor .cctor in which the field Empty was set (in the C# source, that would probably just be a field initializer, of course), while in 4.5 no static constructor exists. In both versions, the field itself looks the same:

.field public static initonly string Empty

(观察用IL DASM)。

(as seen with IL DASM).

没有其他领域的String ::空缺似乎受到影响。举个例子,我尝试用 System.Diagnostics.Debugger :: DefaultCategory 。这种情况似乎类似:含有静态只读密封类静态initonly )的类型字符串。但在这种情况下,它工作得很好,以改变通过反射的值(基准)。

No other fields than String::Empty seems to be affected. As an example, I experimented with System.Diagnostics.Debugger::DefaultCategory. This case seems analogous: A sealed class containing a static readonly (static initonly) field of type string. But in this case it works fine to change the value (reference) through reflection.

回到问题:

这怎么可能,从技术上讲,这空缺似乎并没有改变(4.5)当我设置字段?我已经验证了C#编译器不会骗与读取,它输出IL,如:

How is it possible, technically, that Empty doesn't seem to change (in 4.5) when I set the field? I have verified that the C# compiler does not "cheat" with the read, it outputs IL like:

ldsfld     string [mscorlib]System.String::Empty

因此​​实际字段应该被读。

so the actual field ought to be read.

赏金后,编辑被提上我的问​​题:请注意,写操作(这需要反思肯定的,因为该字段是只读(又名 initonly 在伊利诺斯州))实际上按预期工作。它是在操作,这是反常的。如果你阅读与反思,如 typeof运算(字符串).GetField(空)。的GetValue(空),一切正常(即价值的变动被认为是) 。请参见下面的评论。

Edit after bounty was put on my question: Note that the write operation (which needs reflection for sure, since the field is readonly (a.k.a. initonly in the IL)) actually works as expected. It is the read operation which is anomalous. If you read with reflection, as in typeof(string).GetField("Empty").GetValue(null), everything is normal (i.e. the change of value is seen). See comments below.

所以,更好的问题是:为什么该框架的这个新版本欺骗,当它读取这一特定领域

So the better question is: Why does this new version of the framework cheat when it reads this particular field?

推荐答案

的区别在于JIT的.NET,这显然优化引用新发布的的String.Empty 通过内联提及具体字符串实例,而不是加载保存在空缺字段。这是在的init-唯一约束下的定义有道理在ECMA-335分区我§8.6.1.2,它可以是PTED意味的价值除$ P $ 字符串类初始化后的String.Empty 字段不会改变。

The difference lies in the JIT for the new release of .NET, which apparently optimizes references to String.Empty by inlining a reference to a particular String instance rather than load the value stored in the Empty field. This is justified under the definition of the init-only constraint in ECMA-335 Partition I §8.6.1.2, which can be interpreted to mean the value of the String.Empty field will not change after the String class is initialized.

这篇关于的String.Empty的行为改变(或System.String ::空)在.NET 4.5的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-19 14:32