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

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

问题描述:

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

Why is the "someValue" variable which is readonly (but we still can change its value via reflection) output as "10", although it actually did change to 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内联静态只读字段.

It is a JIT-compiler's optimization. JIT inlines static readonly fields.

让我解释一下.

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

Let's start with simple facts:

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

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

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

So, static readonly field can only be initialized once, unlike instance readonly fields: instance constructor can be called multiple times (in order to create new instances of a class), so there can be multiple, different values when it comes to instance readonly fields. You can't inline some instance's readonly field in a method, because there might be other instances that method is working with.

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

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.

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

That means, static constructors are always called first when accessing a type. So, static readonly field must have already been initialized!

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

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

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

So, why not decide to inline that static readonly field in a method that's using it?

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

See, if a method is using that static readonly field, then it is accessing that type. If it is accessing that type, then static constructor of that type has already been called, and static readonly field has already been initialized. Static constructor will never be called again and static readonly field will have the same value until you don't restart the app! Why not inline it in a method if we know that field will always have the same value?