web-dev-qa-db-fra.com

Propriété abstraite avec getter public, définir un séparateur privé dans une classe concrète possible?

J'essaie de créer une classe abstraite qui définit une propriété avec un getter. Je veux laisser le soin aux classes dérivées de décider si elles veulent ou non implémenter un configurateur. Est-ce possible?

Ce que j'ai jusqu'ici:

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

Dans ConcreteClass1, j'obtiens une erreur sur la set. Il ne peut pas remplacer set_Value car aucun accesseur d'ensemble pouvant être remplacé n'existe dans AbstractClass.

Dans ConcreteClass2, j'obtiens une erreur sur les deux Value car un membre portant le même nom est déjà déclaré.

ConcreteClass3 ne donne pas d'erreur, mais même si l'accesseur set de Value serait compilé dans set_Value, cela ne fonctionne pas dans l'autre sens. Définir un set_Value ne signifie pas que Value obtient un accesseur défini. Je ne peux donc pas attribuer de valeur à une propriété ConcreteClass3.Value. Je peux utiliser ConcreteClass3.set_Value ("valeur"), mais ce n'est pas ce que j'essaie de réaliser ici.

Est-il possible que la classe abstraite demande un getter public, tout en permettant à un setter optionnel d'être défini dans une classe dérivée?

Au cas où vous vous le demanderiez, ceci est juste une question théorique. Je n'ai pas de situation réelle où une telle chose est nécessaire. Mais je peux imaginer une classe abstraite qui ne se soucie pas de la façon dont une propriété est définie, mais qui doit pouvoir obtenir la propriété.

43
comecme

Malheureusement, vous ne pouvez pas faire exactement ce que vous voulez. Vous pouvez le faire avec des interfaces cependant:

public interface IInterface {
    string MyProperty { get; }
}

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

La façon dont je le ferais est d'avoir une méthode SetProperty distincte dans les classes concrètes:

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;
    }
}
32
thecoop

Solution trouvée: Comment remplacer une propriété en lecture seule avec un paramètre en 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; } }
}

D est maintenant équivalent à une classe héritant de B tout en pouvant également remplacer dans un séparateur.

6
Nat

Pas très élégant, mais c’est le plus proche que vous puissiez obtenir sans faire quelque chose comme vous le faites dans 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