7

所以,我在摆弄和学习反思时遇到了一个奇怪的问题。我正在尝试更改一个私有的只读字段,如下所示:

public class A 
{
    private static readonly int x;

    public int X
    {
        get { return x; }
    }
}

static void Main(string[] args)
{
    A obj = new A();
    Type objType = typeof(A);

    Console.WriteLine(obj.X);

    FieldInfo objField = objType.GetField("x", BindingFlags.Static | BindingFlags.NonPublic);
    objField.SetValue(null, 100);

    Console.WriteLine(obj.X);

    Console.ReadLine();
}

如果我按照上面的方式运行程序,那么每次都会将 0 打印到控制台。但是,如果我注释掉第一个打印,那么第二个将写出预期的 100。

任何人都可以阐明这里发生了什么?谢谢!

编辑:奇怪的是,它似乎在 Visual Studio 2012 中有效,但在 2010 年无效。据我发现,两者的设置都是相同的。

编辑 2:使用平台目标 x64 构建时有效,而不是 x86。猜猜新的问题是:为什么会这样?

编辑3:在反汇编中比较了x64和x86版本;x86 版本中似乎有一些内联。

编辑4:好吧,我我已经弄清楚发生了什么。我不认为 A 类中的属性被内联是问题。我相信当在 main 方法中第二次读取属性时,属性调用被优化掉(支持字段应该是只读的,值应该是相同的)并且旧值被重用。至少这是我的“理论”。

4

1 回答 1

6

JIT 内联吸气剂:

使用MethodImplAttributegetter 上的 建议 JIT 不内联该属性。这不会阻止x内联的值,但删除readonly将产生所需的结果。

public class A
{
    private static int x;

    public int X
    {
        [MethodImpl(MethodImplOptions.NoInlining)]
        get { return x; }
    }
}

现在输出将是:

0
100

请参阅:C# 是否内联属性?

一种简单的解决方法是使用可为空的整数 ( int?) 值类型。

public class A 
{
    private static readonly int? x;

    public int X
    {
        get
        {
            return x ?? 0;
        }
    }
}

x不会被内联,因为 CLR 将需要检查 的值是否是对 .x的有效强制转换int

于 2013-08-05T13:30:36.580 回答