8

readonlyリフレクションを使用してフィールドの値を変更できるのに、a の値を変更できないのはなぜconstですか?

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";
}

この回答を読んだので、ルールを破ることが許可されていることは理解していますが、その場合はreadonlyなぜですか? const正当な理由があると確信していますが、それが何であるかはわかりません。

- 編集 -

ildasm を使用して上記のコードを見ると、readonlyコンパイル時にフィールドの値が設定されています。とは異なり、フィールド自体ではconstなく、クラスのコンストラクターで。そのため、一方を「上書き」できるのに、もう一方を上書きできない理由がわかりません。

つまり、値がconstバイナリで「ハードコード」されていても、「既に設定されている」ため、または単に設計上の決定であるため、フレームワーク自体の技術的な制限を変更できない理由です。constのためにそれを行っているので、どこかに を変更する「魔法」が存在しない理由はわかりませんreadonly

-- 編集 2 --

受け入れられた回答に追加するために、非常に興味深いこの他の回答もあります。この質問をしたときに最初に得られなかったのは、コード内で使用されている場所の背後にある値const実際に置き換えられるということです。この宣言では:

public const string Foo = "Hello";

後で書く

Console.WriteLine(Foo);

書くことに等しい

Console.WriteLine("Hello");

確かに私のコード

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

ILでは次のように置き換えられます

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)
4

2 に答える 2

9

constフィールドはコンパイル時に「設定」されるため、つまり、コンパイラはコンパイル中に を指定された値に置き換えますconst。値が機能する方法の結果としてconst、それらの値は、それらを使用するすべてのアセンブリにコピーされます。一方readonly、フィールドは実行時に評価されます。

于 2013-03-17T08:00:32.410 に答える
2

理由は、コンパイル時に定数がその値に置き換えられるためです。ただし、読み取り専用フィールドはそうではありません。宣言時および/またはそのクラスのコンストラクターで、読み取り専用フィールドの値を設定できます。これがあなたの質問に答えることを願っています。

于 2013-03-17T08:03:26.830 に答える