2013-03-17 16 views
8

Dlaczego można modyfikować wartość pola readonly za pomocą odbicia, ale nie wartości const?Dlaczego możliwa jest zmiana wartości pola tylko do odczytu, ale nie wartości stałej za pomocą odbicia?

class Program 
{ 
    static void Main(string[] args) 
    { 
     Foobar foobar = new Foobar(); 
     Console.WriteLine(foobar.foo);     // Outputs "Hello" 
     Console.WriteLine(Foobar.bar);     // Outputs "Hello" 

     var field = foobar.GetType().GetField("foo"); 
     field.SetValue(foobar, "World");    // Ok 
     field = foobar.GetType().GetField("bar"); 
     field.SetValue(foobar, "World");    // Throws FieldAccessException 

     Console.ReadKey(); 
    } 
} 

public class Foobar 
{ 
    public readonly string foo = "Hello"; 
    public const string bar = "Hello"; 
} 

Czytałem this answer więc rozumiem to wolno łamać zasady readonly ale dlaczego nie dla const w tym przypadku? Jestem pewien, że istnieje dobry powód, ale nie wiem, co to może być.

- Edit -

Kiedy przyjrzeć się powyższym kodzie za pomocą ildasm wartość pola readonly jest ustawiony w czasie kompilacji. Nie na samym polu, w przeciwieństwie do modelu const, ale w konstruktorze klasy. Nie wiem, dlaczego można "nadpisać" jeden, ale nie drugi.

Co mam na myśli to, że nawet wartość const jest "zakodowana" w pliku binarnym, jest powodem, że nie jest w stanie zmodyfikować jej ograniczenia technicznego w samej strukturze, ponieważ "jest już ustawiona" lub tylko decyzja projektowa. Nie widzę żadnego powodu, dla którego nie mogłaby istnieć jakaś "magia" gdzieś modyfikująca const, tak jak robi to dla readonly.

- Edycja 2 -

Aby dodać do przyjętej odpowiedź, nie jest również this other answer który jest dość interesująca. To, czego nie dostałem na pierwszym miejscu, zadając to pytanie, to fakt, że wartość const jest wymieniona wszędzie tam, gdzie jest używana w kodzie. Z niniejszym oświadczeniem:

public const string Foo = "Hello"; 

pisanie później

Console.WriteLine(Foo); 

jest równoważne formie pisemnej

Console.WriteLine("Hello"); 

Rzeczywiście mój kod

Console.WriteLine(foobar.foo); 
Console.WriteLine(Foobar.bar); 

otrzymuje IL przez

IL_0008: ldfld  string ConsoleApplication3.Foobar::foo 
IL_000d: call  void [mscorlib]System.Console::WriteLine(string) 
IL_0012: nop 
IL_0013: ldstr  "Hello" 
IL_0018: call  void [mscorlib]System.Console::WriteLine(string) 
+1

Zobacz też: [Jaka jest różnica między const a readonly?] (Http://stackoverflow.com/questions/55984/what-is-the-difference-between-const-and-readonly) –

+0

@CodyGray Dzięki dla twojego linku. Nie wiedziałem, w jaki sposób pamięć została obsłużona dla "const" i jaki wpływ może mieć na inne zgromadzenia. Modyfikowanie wartości 'const' może mieć nieznany wpływ na inne zespoły, jak sądzę. – Guillaume

Odpowiedz

9

Ponieważ const pola są „ustawione” w czasie kompilacji, to kompilator zastępuje const o podanej wartości w czasie kompilacji. W wyniku działania wartości wartości są kopiowane do każdego zespołu, który je wykorzystuje. Natomiast pola readonly są oceniane w czasie wykonywania.

+0

Kiedy przyjrzę się kodowi w moim pytaniu w ildazmie, wartość pola 'readonly' jest również ustawiona na czas kompilacji. Nie na samym polu, w przeciwieństwie do "const", ale i tak w konstruktorze. Więc nadal nie jestem pewien, dlaczego mogę być "nadpisany", ale nie drugi. – Guillaume

+0

@Guillaume czy możesz zaktualizować swoje pytanie, aby uwzględnić obserwacje IL zarówno dla const, jak i readonly. – ColinE

+0

@Guillaume to, co możesz obserwować, to optymalizacja kompilatora w tym przypadku, która sprawia, że ​​twój readonly wygląda tak samo jak deklaracja const. Nie można wnioskować zbyt wiele ze skompilowanego kodu! – ColinE

2

Powód jest taki, że stałe są zastępowane wartością podczas samego czasu kompilacji. Ale pola tylko do odczytu nie są. Możesz ustawić wartość dla pól tylko do odczytu na deklaracji i/lub na konstruktorze tej klasy. Mam nadzieję, że to odpowie na twoje pytanie.

Powiązane problemy