为什么在通过反射更改静态只读字段后,该只读字段的输出是旧的?

Why after changing a static readonly field via reflection the output of that readonly field is old?

为什么 "someValue" 变量是只读的(但我们仍然可以通过反射更改它的值)输出为“10”,尽管它实际上已更改为 55?

static class Program
{
    static readonly int someValue = 10;

    static void Main(string[] args)
    {
        Console.WriteLine(someValue); // 10

        typeof(Program)
             .GetField("someValue", BindingFlags.Static | BindingFlags.NonPublic)
             .SetValue(null, 55); // change readonly field via reflection to 55

        Console.WriteLine(someValue); // output in console 10, 
                                      // but in visual studio debugger it shows 55

        Console.ReadKey();
    }
}

可能只是为了防止多次读取变量而进行的 JIT 优化。

您正在更改已声明为只读的内存位置,因此如果读者缓存这些值,请不要感到惊讶。

这是JIT-compiler的优化。 JIT 内联静态只读字段。

让我解释一下。

让我们从简单的事实开始:

Static constructors are only called once in a process for each type.

因此,静态只读字段只能初始化一次,这与实例只读字段不同: 实例构造函数可以被多次调用(为了创建 class 的新实例),因此当涉及到实例只读字段时,可以有多个不同的值。您不能在方法中内联某些实例的只读字段,因为该方法可能正在使用其他实例。

When you access any type's or its instance's data or functions or whatever else, the static constructor of that type has already been called.

这意味着,在访问类型时,总是先调用静态构造函数。所以,static readonly字段一定已经被初始化了!

JIT-Compiler perfectly knows what i'm talking about above.

那么,为什么不决定在使用该静态只读字段的方法中内联它呢?

看,如果一个方法正在使用该静态只读字段,那么它正在访问该类型。如果它正在访问该类型,那么该类型的静态构造函数已经被调用,并且静态只读字段已经被初始化。静态构造函数将永远不会被再次调用,静态只读字段将具有相同的值,直到您不重新启动应用程序!如果我们知道该字段将始终具有相同的值,为什么不将其内联到方法中呢?