I think you fall prey to the optimization that JIT does. In fact, you can change the value of this field, but for some reason, the results of this change will not be immediately visible. I managed to get around this by doing something stupid:
typeof(Type).GetField("Delimiter", BindingFlags.Public | BindingFlags.Static).SetValue(null, '-'); Func<char> getDelimiter = () => Type.Delimiter; Console.WriteLine( getDelimiter() );
This code reliably showed the updated field value for me. I cannot say that I am terribly surprised; the field is declared read-only, so JITTER can use this assumption when accessing the field. You are doing something naughty and evil, there should be no expectation for this to work reasonably.
Now, why didnโt this appear when changing the bool.TrueString field, I think that because bool.TrueString is a reference type ( string ), while Type.Delimiter is a value type ( char ). I could imagine that this causes various optimizations.
I looked at the disassembly for this code:
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
You can see quite clearly that JITTER has optimized access to the Type.Delimiter field, replacing it with the literal value '.' . Access to the static field for bool.TrueString is still loading from the actual field.
source share