Jep*_*sen 40 .net c# string readonly .net-4.5
精简版:
C#代码
typeof(string).GetField("Empty").SetValue(null, "Hello world!");
Console.WriteLine(string.Empty);
Run Code Online (Sandbox Code Playgroud)
在编译和运行时,"Hello world!"在.NET 4.0及更早版本下提供输出,但""在.NET 4.5和.NET 4.5.1下提供.
如何像这样忽略对字段的写入,或者,谁重置该字段?
更长的版本:
我从来没有真正理解为什么string.Empty字段(也称为[mscorlib]System.String::Empty)不是const(aka.literal),请参阅" 为什么String.Empty不是常量? ".这意味着,例如,在C#中我们不能string.Empty在以下情况下使用:
switch表格中的陈述case string.Empty:void M(string x = string.Empty) { }[SomeAttribute(string.Empty)]这对于众所周知的"宗教战争"是否影响是否使用string.Empty或"",请参阅" 在C#中,我应该使用string.Empty或String.Empty还是"来初始化字符串? ".
几年前,我Empty通过反射设置其他字符串实例来自娱自乐,看看BCL有多少部分由于它而开始表现奇怪.这是很多.并且Empty参考的变化似乎在应用程序的整个生命周期中持续存在.现在,有一天我试图重复那个小噱头,但后来使用的是.NET 4.5机器,我再也无法做到了.
(注意!如果您的计算机上安装了.NET 4.5,可能PowerShell仍然使用较旧版本的.NET,请尝试复制粘贴[String].GetField("Empty").SetValue($null, "Hello world!")到PowerShell中以查看更改此引用的一些效果.)
当我试图寻找原因时,我偶然发现了一个有趣的主题:" .NET 4.5 beta版本中FatalExecutionEngineError的原因是什么? ".在该问题的公认答案中,是否注意到通过版本4.0,System.String有一个静态构造函数.cctor,其中Empty设置了字段(在C#源中,当然可能只是一个字段初始化程序),而在4.5中没有静态构造函数存在.在这两个版本中,字段本身看起来都是一样的:
.field public static initonly string Empty
Run Code Online (Sandbox Code Playgroud)
(如IL DASM所示).
没有其他领域String::Empty似乎受到影响.作为一个例子,我进行了实验System.Diagnostics.Debugger::DefaultCategory.这种情况似乎是类似的:包含类型的static readonly(static initonly)字段的密封类string.但在这种情况下,通过反射更改值(引用)可以正常工作.
回到问题:
在技术上,Empty当我设置字段时,它似乎没有变化(在4.5中)?我已经验证了C#编译器没有"欺骗"读取,它输出IL如:
ldsfld string [mscorlib]System.String::Empty
Run Code Online (Sandbox Code Playgroud)
所以应该阅读实际的领域.
在我的问题上提出赏金之后的编辑:请注意,写操作(由于字段是readonly(也就是initonly在IL中)确实需要反射)实际上按预期工作.这是读操作是反常.如果你用反射阅读,就像在typeof(string).GetField("Empty").GetValue(null),一切都正常(即看到值的变化).见下面的评论.
所以更好的问题是:为什么这个新版本的框架在读取这个特定字段时会作弊?
Sam*_*ell 21
不同之处在于.NET新版本的JIT,它显然String.Empty通过内联对特定String实例的引用来优化引用,而不是加载存储在Empty字段中的值.根据ECMA-335分区I§8.6.1.2 中的init-only约束的定义,这是合理的,可以解释为在初始化类String.Empty之后字段的值不会改变String.
我没有答案,也许只是一些提示。
String::Empty我看到和之间的唯一区别System.Diagnostics.Debugger::DefaultCategory是第一个标记为__DynamicallyInvokableAttribute。
我不知道这个未记录的属性的含义。关于此属性的问题已在 SO 上提出:What is the __DynamicallyInvokable attribute for?
我只能假设这个属性被运行时捕获以进行一些缓存?
| 归档时间: |
|
| 查看次数: |
1506 次 |
| 最近记录: |