所以,我在摆弄和学习反思的过程中遇到了一个奇怪的问题。 我正在尝试更改一个私有的readonly字段,如下所示:
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:Okey,想想我已经弄清楚发生了什么,等等。我不认为A类中的属性是内联的问题。我相信当在main方法中第二次读取属性时,属性调用被优化掉了(后备字段应该是readonly,值应该相同)并且旧值被重用。这至少是我的“理论”。
答案 0 :(得分:6)
JIT正在勾勒出吸气剂:
使用getter上的MethodImplAttribute
建议JIT不要内联属性。这不会阻止x
的内联值,但删除readonly
会产生所需的结果。
public class A
{
private static int x;
public int X
{
[MethodImpl(MethodImplOptions.NoInlining)]
get { return x; }
}
}
现在输出将是:
0
100
请参阅:Does C# inline properties?
一个简单的解决方法是使用可空整数(int?
)值类型。
public class A
{
private static readonly int? x;
public int X
{
get
{
return x ?? 0;
}
}
}
x
不会被内联,因为CLR需要检查x
的值是否为int
的有效广告。