2011-01-10 11 views
37

Estoy tratando de crear una clase abstracta que defina una propiedad con un getter. Quiero dejarlo en las clases derivadas para decidir si quieren implementar un setter para la propiedad o no. es posible?¿Propiedad abstracta con getter público, define el setter privado en la clase concreta 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, me sale un error en el set. No puede anular set_Value porque no existe ningún acceso de conjunto invalidado en AbstractClass.

En ConcreteClass2, aparece un error en ambos Value porque ya se ha declarado un miembro con el mismo nombre.

ConcreteClass3 no da error, pero aunque el acceso de conjunto de Value se compilaría en set_Value, no funciona al revés. Definir un set_Value no significa que Value obtiene un acceso de conjunto. Por lo tanto, no puedo asignar un valor a una propiedad ConcreteClass3.Value. I puede utilizar 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, mientras que permite definir un setter opcional en una clase derivada?

En caso de que se lo pregunte, esta 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 a la que no le importe cómo se establece una propiedad, pero que necesita ser capaz de obtener la propiedad.

Respuesta

28

Lamentablemente, no puede hacer exactamente lo que quiere. Usted puede hacer esto con interfaces sin embargo:

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 separada 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; 
    } 
} 
+0

Usando la 'interfaz', no puedo implementar el método' DoSomething' en mi clase base (no hay una clase base, solo una interfaz). Usar 'SetValue' es lo mismo que' set_Value' en mi 'ConcreteClass3'. Pero si ese es el camino a seguir, nombrarlo 'SetValue' es probablemente mejor que' set_Value'. – comecme

+0

El motivo set_Value no está vinculado a la propiedad si hay una definición explícita de 'PropertyDef' en el ensamblado que vincula los métodos' get_' y 'set_'; simplemente nombrar un método 'set_' no lo vincula a una propiedad. No hay forma de hacer exactamente lo que quieres en C#; Tendrás que comprometerte. – thecoop

+0

Puede implementar 'DoSomething' como método de extensión en' IInterface'. Ver mi edición – piedar

0
No

muy elegante, pero es el más cercano que pueda obtener sin hacer algo 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

No veo por qué defines un 'nuevo DoSomething' en la clase concreta. Además, su solución emitirá una excepción en el tiempo de ejecución, en el momento de la compilación, la ausencia de una implementación de Value no se notará en absoluto. – comecme

5

encontrado una solución: How to override a getter-only property with a setter in 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 que hereda de B y también se puede sobrescribir en un setter.

Cuestiones relacionadas