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

时间:2019-01-26 17:33:32

标签: c# .net jit system.reflection inlining

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

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();
    }
}

2 个答案:

答案 0 :(得分:2)

可能只是JIT优化,以防止多次读取变量。

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

答案 1 :(得分:0)

这是JIT编译器的优化。 JIT内联静态只读字段。

让我解释一下。

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

  

静态构造函数在每种类型的过程中仅被调用一次。

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

  

当您访问任何类型或其实例的数据或函数或其他内容时,该类型的静态构造函数已被调用。

这意味着,访问类型时,始终首先调用静态构造函数。因此,静态只读字段必须已经初始化!

  

JIT编译器完全了解我在上面所说的内容。

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

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