2013-08-05 25 views
7

Così, ho incontrato un problema strano, mentre armeggiare intorno e imparare di riflessione. sto cercando di cambiare una, campo di sola lettura privata, come si vede qui sotto:Impossibile modificare il campo di sola lettura con la riflessione

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

Se eseguo il programma come si sta al di sopra, quindi 0 verrà stampata per consolare ogni volta. Tuttavia, se commento la prima stampa, il secondo scriverà l'atteso 100.

Chiunque può far luce su quello che sta succedendo qui? Grazie!

EDIT: Strangly sembra funzionare in Visual Studio 2012, ma non nel 2010. Per quanto ho trovato, le impostazioni sono le stesse in entrambi.

EDIT 2: funziona quando si costruisce con x64 bersaglio piattaforma, e non con x86. Indovina la nuova domanda è: perché è così?

EDIT 3: Rispetto alle versioni x64 e x86 in disassemblaggio; sembra esserci qualche inlining in corso nella versione x86.

EDIT 4: Okey, think Ho capito cosa sta succedendo, una specie di. Non penso che la proprietà in classe A sia in linea sia il problema. Credo che quando è il momento di leggere la proprietà la seconda volta nel metodo principale, la chiamata di proprietà viene ottimizzata (il campo di supporto deve essere di sola lettura, il valore dovrebbe essere lo stesso) e il vecchio valore viene riutilizzato. Questa è la mia "teoria" almeno.

+0

Questo perché la prima volta che si stampa si chiama assegnandogli il suo valore predefinito che è 0, e dopo è sempre 0, se si commenta il primo, quindi si assegna il valore 100 e quindi si stampa il suo valore. – terrybozzio

+1

* Calling Marc Ghiaia, chiamando Marc Gravel * – Will

+0

Poiché il campo è contrassegnato come 'readonly' JIT potrebbe essere messa in linea del rinfusa getter'. – Romoku

risposta

6

Il JIT è inlining il getter:

Utilizzare il MethodImplAttribute sul getter per suggerito il JIT di non inline la proprietà. Questo non impedirà il valore di x da ottenere inline, ma la rimozione del readonly produrrà il risultato desiderato.

public class A 
{ 
    private static int x; 

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

Ora la produzione saranno:

0 
100 

Vedi: Does C# inline properties?

Una soluzione semplice è quella di usare l'intero nullable (int?) tipo di valore.

public class A 
{ 
    private static readonly int? x; 

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

x non andranno inline poiché il CLR sarà necessario verificare se il valore di x è un cast valido int.

+0

È possibile visualizzare risultati diversi quando si compila una build di debug invece di una versione anche dopo aver apportato tale modifica. Sono sicuro che deve essere * qualcosa * da fare con il jitter, però. –

+1

Ho ancora lo stesso risultato; entrambi con derivazione da MarshalByRefObject e con l'attributo. –

+0

Il codice sopra riproduce ancora il "problema" nella condizione specificata nei paragrafi di EDIT della domanda, quindi "NoInlining" nell'attributo dell'accessorio get non sembra essere sufficiente. –