web-dev-qa-db-ja.com

基本クラスコンストラクターで設定したときに、オーバーライドされたget-onlyプロパティがnullのままになるのはなぜですか?

私は次の例を試しました:

public class TestBase
{
    public virtual string ReadOnly { get; }

    public TestBase()
    {
        ReadOnly = "from base";
    }
}

class Test : TestBase
{
    public override string ReadOnly { get; }
    public Test()
    {
        // nothing here
    }
}

Testのインスタンスを作成すると、ReadOnlyがnullのままになることがわかります。しかし、なぜ?私は本当にそれのこつを得ません、誰かがこれがなぜ起こるか私に説明してもらえますか?少なくとも、所有クラスの外部で読み取り専用プロパティを設定できないというエラーが予想されます。

44
apfelstrudel24

コンパイラはこれを以下のように扱います。基本的に、コンストラクターのコードは、TestBaseoriginalバッキングフィールドに書き込みます。あなたのシナリオはサポートされていないようですが、...言語チームがこのケースを検討したかどうかは疑問です。

ところで:コンパイラがコードで何をするかを見たい場合: sharplab.io

public class TestBase
{
    [CompilerGenerated]
    private readonly string <ReadOnly>k__BackingField; // note: not legal in "real" C#

    public virtual string ReadOnly
    {
        [CompilerGenerated]
        get
        {
            return <ReadOnly>k__BackingField; // the one in TestBase
        }
    }

    public TestBase()
    {
        <ReadOnly>k__BackingField = "from base";
    }
}
internal class Test : TestBase
{
    [CompilerGenerated]
    private readonly string <ReadOnly>k__BackingField;

    public override string ReadOnly
    {
        [CompilerGenerated]
        get
        {
            return <ReadOnly>k__BackingField; // the one in Test
        }
    }
}
38
Marc Gravell

これを説明する最も簡単な方法は、これを実装するためにコンパイラが生成するコードを検討することです。

基本クラスはこれと同等です:

public class TestBase
{
    public virtual string ReadOnly => _testBaseReadOnly;

    public TestBase()
    {
        _testBaseReadOnly = "from base";
    }

    readonly string _testBaseReadOnly;
}

派生クラスはこれと同等です:

class Test : TestBase
{
    public override string ReadOnly => _testReadOnly;

    readonly string _testReadOnly;
}

ここで注意すべき重要なことは、派生クラスがReadOnlyに対して独自のバッキングフィールドを持っていることです-基本クラスのバッキングフィールドは再利用しません。

気付いたので、オーバーライドされたプロパティがnullである理由は明らかです。

派生クラスにはReadOnlyの独自のバッキングフィールドがあり、そのコンストラクタはそのバッキングフィールドを初期化していないためです。

ちなみに、Resharperを使用している場合、派生クラスでReadOnlyを設定していないことを実際に警告します。

 "Get-only auto-property 'ReadOnly' is never assigned."
17
Matthew Watson