web-dev-qa-db-ja.com

プロパティをパブリックゲッターで抽象化し、具体的なクラスでプライベートセッターを定義することは可能ですか?

ゲッターでプロパティを定義する抽象クラスを作成しようとしています。派生クラスに任せて、プロパティのセッターを実装するかどうかを決定します。これは可能ですか?

私がこれまでに持っているもの:

public abstract class AbstractClass {
    public abstract string Value { get; }
    public void DoSomething() {
        Console.WriteLine(Value);
    }
}

public class ConcreteClass1 : AbstractClass {
    public override string Value { get; set; }
}

public class ConcreteClass2 : AbstractClass {
    private string _value;
    public override string Value {
        get { return _value; }
    }
    public string Value {
        set { _value = value; }
    }
}

public class ConcreteClass3 : AbstractClass {
    private string _value;
    public override string Value {
        get { return _value; }
    }
    public void set_Value(string value) {
        _value = value;
    }
}

ConcreteClass1で、setでエラーが発生します。オーバーライド可能なセットアクセサがAbstractClassに存在しないため、set_Valueをオーバーライドできません。

ConcreteClass2では、同じ名前のメンバーが既に宣言されているため、両方のValueでエラーが発生します。

ConcreteClass3はエラーになりませんが、Valueのsetアクセサーがset_Valueにコンパイルされても、その逆は機能しません。 set_Valueを定義しても、Valueがsetアクセサーを取得するわけではありません。したがって、ConcreteClass3.Valueプロパティに値を割り当てることはできません。私can ConcreteClass3.set_Value( "value")を使用しますが、ここではそれを達成しようとはしていません。

オプションのセッターを派生クラスで定義できるようにしながら、抽象クラスにパブリックゲッターを要求させることは可能ですか?

あなたが疑問に思っている場合、これは単なる理論的な質問です。このような何かが必要な実際の状況はありません。しかし、プロパティの設定方法を気にしない抽象クラスを想像できます、ただし、プロパティを取得できる必要があります。

46
comecme

残念ながら、あなたが望むことを正確に行うことはできません。ただし、インターフェイスを使用してこれを行うことができます。

public interface IInterface {
    string MyProperty { get; }
}

public class Class : IInterface {
    public string MyProperty { get; set; }
}

私がそれをする方法は、具体的なクラスに別個のSetPropertyメソッドを持たせることです:

public abstract class AbstractClass {
    public abstract string Value { get; }
}

public class ConcreteClass : AbstractClass {

    private string m_Value;
    public override string Value {
        get { return m_Value; }
    }

    public void SetValue(string value) {
        m_Value = value;
    }
}
33
thecoop

解決策が見つかりました: C#でゲッター専用プロパティをセッターでオーバーライドする方法

public abstract class A
{
    public abstract int X { get; }
}
public class B : A
{
    public override int X { get { return 0; } }
}
/*public class C : B  //won't compile: can't override with setter
{
    private int _x;
    public override int X { get { return _x; } set { _x = value; } }
}*/
public abstract class C : B  //abstract intermediate layer
{
    public sealed override int X { get { return this.XGetter; }  }
    protected abstract int XGetter { get; }
}
public class D : C  //does same thing, but will compile
{
    private int _x;
    protected sealed override int XGetter { get { return this.X; } }
    public new virtual int X { get { return this._x; } set { this._x = value; } }
}

DBを継承するクラスと同等になりましたが、セッターでオーバーライドすることもできます。

6
Nat

あまりエレガントではありませんが、concreteclass3のようなことをせずに取得できる最も近いものです

public class Concrete : AbstractClass
{
    public new void DoSomething()
    {
        Console.WriteLine(Value);
    }
}

public abstract class AbstractClass
{
    protected AbstractClass()
    {
        try
        {
            var value = Value;
        }
        catch (NotImplementedException)
        {
            throw new Exception("Value's getter must be overriden in base class");
        }
    }
    public void DoSomething()
    {
        Console.WriteLine(Value);
    }

    /// <summary>
    /// Must be override in subclass
    /// </summary>
    public string Value { get { throw new NotImplementedException(); } }
}
0
Rob