为什么我不能使用Reflection更改Type.Delimiter?

Mat*_*ero 5 .net c# reflection

如果我要改变它的值bool.TrueString,我会用反射来做:

typeof(bool).GetField("TrueString", BindingFlags.Public | BindingFlags.Static).SetValue(null, "Yes");
Console.WriteLine(bool.TrueString); // Outputs "Yes"
Run Code Online (Sandbox Code Playgroud)

但是,我无法改变,例如Type.Delimiter:

typeof(Type).GetField("Delimiter", BindingFlags.Public | BindingFlags.Static).SetValue(null, '-');
Console.WriteLine(Type.Delimiter); // Outputs "."
Run Code Online (Sandbox Code Playgroud)

为什么是这样?

Kyl*_*yle 4

我认为您正在成为 JIT 执行的优化的牺牲品。您实际上可以更改该字段的值,但由于某种原因,该更改的结果不会立即可见。我设法通过做了一些愚蠢的事情来解决这个问题:

typeof(Type).GetField("Delimiter", BindingFlags.Public | BindingFlags.Static).SetValue(null, '-');
Func<char> getDelimiter = () => Type.Delimiter;
Console.WriteLine( getDelimiter() );
Run Code Online (Sandbox Code Playgroud)

该代码可靠地为我显示了该字段的更新值。我不能说我非常惊讶;该字段被声明为只读,因此 JITter 在访问该字段时可以使用该假设。你正在做一些顽皮和邪恶的事情,不应该期望它能以理智的方式发挥作用。

现在,至于为什么在修改bool.TrueString字段时没有出现这一点,我最好的猜测是,这是由于它bool.TrueString是引用类型(string),而Type.Delimiter是值类型(char)。我可以想象这会触发不同的优化。

我确实查看了这段代码的反汇编:

        Console.WriteLine( bool.TrueString );
006F2E53 8B 0D B8 10 40 03    mov         ecx,dword ptr ds:[34010B8h]  
006F2E59 E8 52 A6 77 54       call        54E6D4B0  

        Console.WriteLine(Type.Delimiter);
006F2E5E B9 2E 00 00 00       mov         ecx,2Eh  
006F2E63 E8 B0 FA E0 54       call        55502918  
Run Code Online (Sandbox Code Playgroud)

您可以非常清楚地看到,JITterType.Delimiter通过将字段访问替换为文字值来优化掉字段访问'.'。静态字段访问似乎bool.TrueString仍然是从实际字段加载的。