Propiedad abstracta con getter público, definir setter privado en la clase concreta posible?


Estoy intentando crear una clase abstracta que defina una propiedad con un getter. Quiero dejar que las clases derivadas decidan si quieren implementar un setter para la propiedad o no. Es esto posible?

Lo que tengo hasta ahora:

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

En ConcreteClass1, obtengo un error en el set. No puede anular set_Value porque no existe un accessor de conjunto overridable en AbstractClass.

En ConcreteClass2, recibo un error en ambos Value porque un miembro con el mismo nombre ya está declarado.

ConcreteClass3 no da un error, pero a pesar de que el accessor set de Value se compilaría en set_Value, no funciona al revés. Definir un set_Value no significa que Value obtenga un accessor de conjunto. Así que no puedo asignar un valor a un ConcreteClass3.Valor de la propiedad. I puede usar ConcreteClass3.set_Value ("valor"), pero eso no es lo que estoy tratando de lograr aquí.

¿Es posible que la clase abstracta exija un getter público, al tiempo que permite una opción setter a definir en una clase derivada?

En caso de que te lo preguntes, esto es solo una pregunta teórica. No tengo una situación real en la que se necesite algo como esto. Pero puedo imaginar una clase abstracta que no le importa cómo se establece una propiedad, pero que necesita ser capaz de obtener la propiedad.

Author: Kalamarico, 2011-01-10

3 answers

Desafortunadamente, no puedes hacer exactamente lo que quieres. Sin embargo, puede hacer esto con interfaces:

public interface IInterface {
    string MyProperty { get; }
}

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

La forma en que lo haría es tener un método setProperty separado en las clases concretas:

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;
    }
}
 30
Author: thecoop,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-01-10 11:18:26

Encontró una solución: ¿Cómo anular una propiedad getter-only con un setter 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 ahora es equivalente a una clase heredada de B mientras que también es capaz de sobreescribir en un setter.

 5
Author: Nat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:54:59

No es muy elegante, pero es lo más cercano que puedes conseguir sin hacer algo como lo que tienes en 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
Author: Rob,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-01-10 12:32:39