2013-08-05 19 views
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がそれぞれの時間をコンソールに出力されます。 しかし、私が最初のプリントをコメントアウトすると、2番目のプリントは期待される100を書き出します。

ここで何が起こっているのか光を当てることができる人は誰ですか?ありがとう!

EDIT:StranglyそれはVisual Studio 2012では動作するようですが、2010では動作していないようです。私が見た限り、設定は両方で同じです。

編集2:x86ではなくプラットフォームターゲットx64でビルドするときに機能します。新しい質問があると推測する:それはなぜですか?

EDIT 3:逆アセンブリ時のx64およびx86バージョンと比較します。 x86版ではいくつかのインライン展開が行われているようです。

EDIT 4:Okey、think私は何が起きているのか分かりました。私は、インライン化されているクラスAのプロパティが問題だとは思わない。私は、メインメソッドで2回目のプロパティを読み込むときに、プロパティ呼び出しを最適化して(バッキングフィールドは読み取り専用で、値は同じでなければならない)、古い値が再利用されると信じています。それは少なくとも私の「理論」です。

+0

これは、最初に印刷するときにデフォルト値の0を割り当て、それ以降は常に0にするので、最初にコメントアウトすると値100が割り当てられ、その値が印刷されます。 – terrybozzio

+1

* Marc Gravelの呼び出し、Marc Gravelの呼び出し* – Will

+0

フィールドは 'readonly'とマークされているので、JITは' X'ゲッターをインライン展開している可能性があります。 – Romoku

答えて

6

JITはゲッターをインライン化されていますプロパティをインライン化しないようにJITを提案する

がゲッターにMethodImplAttributeを使用してください。これにより、xの値がインライン化されるのを防ぐことはできませんが、readonlyを削除すると望ましい結果が得られます。

public class A 
{ 
    private static int x; 

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

今出力は次のようになります

0 
100 

参照:Does C# inline properties?

は、一つの簡単な回避策は、NULL可能整数(int?)値型を使用することです。 CLRはxの値がintへの有効なキャストであるかどうかを確認する必要がありますので、

public class A 
{ 
    private static readonly int? x; 

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

xはインライン化されません。

+0

変更を行った後であっても、リリースではなくデバッグビルドをコンパイルすると、異なる結果が表示されます。しかし、私はそれがジッタに関係するものでなければならないと確信しています。 –

+1

私はまだ同じ結果を得ています。両方ともMarshalByRefObjectと属性から派生しています。 –

+0

上記のコードは、問題のEDIT段落で指定された条件の下で "問題"を再現します。したがって、 'get'アクセサの属性の' NoInlining'は十分ではないようです。 –

関連する問題