web-dev-qa-db-ja.com

C#6.0の自動プロパティ初期化で「これ」が使用できないのはなぜですか?

私は次のコードクラスを持っています:

public class Foo
{
    public Nested Bar { get; } = new Nested(this);

    public class Nested
    {
        public Nested(Foo foo)
        {
            foo.DoSomething();
        }
    }

    private void DoSomething()
    {

    }
}

ただし、次のコンパイルエラーが発生します。

キーワード「this」は現在のコンテキストでは使用できません

Auto-Property Initializerを使用せずに修正し、代わりにコンストラクターに明示的に移動することができます。

public Nested Bar { get; }

public Foo()
{
    this.Bar = new Nested(this);
}

なぜそうなのですか? Auto-Property Initializerは実際にILのコンストラクターコードに変換されませんか?

23
Luke Vo

簡単に言うと、初期化子でthisを使用することはできません。アイデアは、不完全なオブジェクトがエスケープするのを防ぐことです-Nested(this)はオブジェクトにanythingを実行でき、非常に混乱し、理解しにくいバグにつながります。初期化子はbefore追加したコンストラクターを実行することに注意してください。同じことがフィールド初期化子でも失敗します。まったく同じ方法です。

private Nested _field = new Nested(this);

基本的に、初期化子は単純初期化を実行することを目的としています-98%の問題を修正します。 thisに関連するものはすべてより複雑であり、独自のコンストラクターを作成する必要があります。タイミングの問題については責任を負います:)

41
Marc Gravell

なぜそうなのですか? Auto-Property Initializerは実際にILのコンストラクターコードに変換されませんか?

自動的に実装されるプロパティ初期化子のルールは、同じ理由でフィールド初期化子のルールと同じです。プロパティ初期化子は、フィールド初期化子と同じようにbefore基本クラス本体で実行されることに注意してください。したがって、「やや初期化されていない」オブジェクトのコンテキストにいることになります。コンストラクター本体の間よりもそうです。

したがって、プロパティが次のように変換されていることを想像してください。

private readonly Nested bar = new Nested(this); // Invalid

public Nested Bar
{
    get { return bar; }
}

要するに、この制限はあなたが自分自身をトラブルに巻き込むのを防ぐことです。プロパティを初期化するときにthisを参照する必要がある場合は、2番目の例のように、コンストラクターで手動で参照してください。 (私の経験では比較的まれです。)

16
Jon Skeet