2

C#6 では、セッターなしでプロパティを初期化する機能が導入されたため、この種の構文を使用できるようになりました

public class MyClass
{
    public int Answer { get; } = 42;
}

またはこれさえ

public class MyClass
{
    public int Answer { get; }
    public MyClass() 
    {
        Answer = 42;
    }
}

readonlyこれがCILのアクセサメソッドを使用して生成されたフィールドに変換されることを知っている(というか、強く想定している)ので、これがどのように行われるかを理解しています

public class MyClass
{
    public int Answer { get; }
    public MyClass CreateMyClassInstance()
    {
        return new MyClass()
        {
            Answer = 42
        };
    }
}

コンパイルされません (代入は技術的にコンストラクターの外部で発生し、バッキングreadonlyフィールドによって課される制限と競合するため)。

私の質問は、そもそもなぜそのような行為が禁止されているのですか? 構文および/またはコンパイルの観点から、オブジェクト初期化子の一部であるプロパティの割り当てが、後で実行する追加のインライン ロジックと見なされるだけでなく、オブジェクトのコンストラクター内にあるのはなぜですか? それは設計によるものなのか、技術的な制限や下位互換性の結果なのか、それとも考慮に値するほど重要ではない単なる変更なのか?

4

2 に答える 2

7

そもそもなぜこのような行為が禁止されているのでしょうか。

オブジェクト初期化子から読み取り専用プロパティを割り当てることを許可すると、カプセル化が壊れます。コンストラクターで行われた初期化は、後でオブジェクト初期化子のクライアント コードによってオーバーライドされる可能性があります。クラスが不変条件を保持することは不可能です。

このような機能は不要であるだけでなく、危険です。

構文および/またはコンパイルの観点から、オブジェクト初期化子の一部であるプロパティの割り当てが、後で実行する追加のインライン ロジックと見なされるだけでなく、オブジェクトのコンストラクター内にあるのはなぜですか?

これは、すべてのオブジェクト初期化子に対して、コンパイラが新しいコンストラクターを生成する必要があることを意味します。別のアセンブリの型を変更して壊している可能性があります。

または、newobjCIL 命令を変更して、コンストラクターの後に任意のコードを実行できるようにする必要があります。

于 2015-12-13T20:42:37.640 に答える
1

Jackub Lortzが言ったことに加えて、あなたが望んでいる効果を達成するための最良の方法は、を使用することです.C#6では、次のように初期化時にプロパティをAnswer { get; private set }割り当てることができます:readonly

int Answer { get; } = 42;

Answerそれからはどこreadonlyだ。に割り当てられる値Answerは定数でなければならないと思います。そうでない場合は、ハックを実行できる可能性があります。

編集:

次のようにオブジェクトを変更できます。

public class MyClass
{
    private bool readOnly;

    private int x;
    public int X
    {
        get { return x; }
        set
        {
            if (readOnly) throw new InvalidOperationException();
            else x = value;
        }
    }

    public MyClass()
    {
        X = 42;
        readOnly = true;
    }
}

これはテスト済みで動作します。このコードでは、型の任意の時点で readOnly を変更できるため、X を変更できます。ただし、これをobjectinterface、またはgeneric型に作成する場合、メソッドを持ち、メソッドx.MakeReadOnly();を持たないこのアイデアを拡張できます。元に戻そうとすると、エラーが発生します。

于 2015-12-15T06:42:22.677 に答える