2009-09-28 17 views
19

Me gustaría forzar solo la implementación de un getter de C# en una propiedad dada a partir de una clase abstracta base. Las clases derivadas pueden, si así lo desean, también proporcionar un setter para esa propiedad para uso público del tipo enlazado estáticamente.Anular propiedad de solo lectura para leer/escribir propiedad

Dada la siguiente clase abstracta:

public abstract class Base 
{ 
    public abstract int Property { get; } 
} 

Si quiero una clase derivada que también implementa un setter, ingenuamente podría intentar:

public class Derived : Base 
{ 
    public override int Property 
    { 
     get { return field; } 
     set { field = value; } // Error : Nothing to override. 
    } 

    private int field; 
} 

Pero cuando me siento un error de sintaxis desde que intenta anular el colocador no existente. Intenté de alguna otra manera, como declarar el iniciador de bases en privado y tal, y aún me tropiezo con todo tipo de errores que me impiden hacer eso. Debe haber una forma de hacerlo, ya que no rompe ningún contrato de la clase base.

Incidentalmente, se puede hacer con interfaces, pero realmente necesito esa implementación predeterminada.

Me tropecé con esa situación tan a menudo, me preguntaba si había un truco de sintaxis de C# oculto para hacer eso, sino que simplemente viviré con él e implementaré un método manual SetProperty().

+0

Cross-link: http://stackoverflow.com/questions/2243886/make-a-read-only-property-writable-in-the-derived-class – Mikhail

Respuesta

11

No puede hacerlo directamente, ya que no puede new y override con la misma firma en el mismo tipo; hay dos opciones - si el control de la clase base, añadir un segundo propiedad:

public abstract class Base 
{ 
    public int Property { get { return PropertyImpl; } } 
    protected abstract int PropertyImpl {get;} 
} 
public class Derived : Base 
{ 
    public new int Property {get;set;} 
    protected override int PropertyImpl 
    { 
     get { return Property; } 
    } 
} 

cosa que se pueda introducir un nivel adicional en la jerarquía de clases:

public abstract class Base 
{ 
    public abstract int Property { get; } 
} 
public abstract class SecondBase : Base 
{ 
    public sealed override int Property 
    { 
     get { return PropertyImpl; } 
    } 
    protected abstract int PropertyImpl { get; } 
} 
public class Derived : SecondBase 
{ 
    public new int Property { get; set; } 

    protected override int PropertyImpl 
    { 
     get { return Property; } 
    } 
} 
+0

Sus soluciones son interesantes, voy a reflexionar un poco sobre ellos. – Coincoin

+1

Su solución es lo más cercano a la cosa. Pero no creo que sea posible hacerlo sin obligar a la clase derivada a hacer acrobacias. – Coincoin

2

¿Qué pasa con algo como:

public abstract class Base 
{ 
    public virtual int Property 
    { 
     get { return this.GetProperty(); } 
     set { } 
    } 

    protected abstract int GetProperty(); 
} 
+1

Cualquier heredero ahora tiene que anularlos a ambos, ¿es algo redundante? –

+0

Solo si anula la propiedad. De lo contrario, sin la propiedad virtual que en realidad podría ser una alternativa aceptable. – Coincoin

+1

Si no anula la propiedad, el propósito del conjunto es muy ... inusual. –

1

¿esto se adapten a sus necesidades?

public abstract class TheBase 
{ 
    public int Value 
    { 
     get; 
     protected set; 
    } 
} 
public class TheDerived : TheBase 
{ 
    public new int Value 
    { 
     get { return base.Value; } 
     set { base.Value = value; } 
    } 
} 

El virtual se eliminó, pero el valor de la base sigue siendo el único de almacenamiento para el valor. Entonces esto debería mostrar '5'. Y el compilador debe alboroto sobre b.Value = 4;

TheDerived d = new TheDerived(); 
d.Value = 5; 
TheBase b = d; 
//b.Value = 4; // uncomment for compiler error 
cout << "b.Value == " << b.Value << endl; 

-Jesse

1

que tenía un requisito similar en el que necesitaba una interfaz para poder compartir la funcionalidad de clasificación común entre dos clases vagamente relacionados. Uno de ellos tenía una propiedad de Pedido de solo lectura y el otro tenía una propiedad de Pedido de lectura/escritura, pero necesitaba una forma de leer la propiedad de la misma manera en ambas clases.

Resulta que esto se puede hacer ocultando el valor de solo lectura en una interfaz derivada. Así es como lo hice.

interface ISortable 
{ 
    int Order { get; } 
} 

interface ISortableClass2 
    : ISortable 
{ 
    // This hides the read-only member of ISortable but still satisfies the contract 
    new int Order { get; set; } 
} 

class SortableClass1 
    : ISortable 
{ 
    private readonly int order; 

    public SortableClass1(int order) 
    { 
     this.order = order; 
    } 

    #region ISortable Members 

    public int Order 
    { 
     get { return this.order; } 
    } 

    #endregion 
} 

class SortableClass2 
    : ISortableClass2 
{ 
    #region ISortableClass2 Members 

     public int Order { get; set; } 

    #endregion 
} 

class RunSorting 
{ 
    public static void Run() 
    { 
     // Test SortableClass1 
     var list1 = new List<SortableClass1>(); 

     list1.Add(new SortableClass1(6)); 
     list1.Add(new SortableClass1(1)); 
     list1.Add(new SortableClass1(5)); 
     list1.Add(new SortableClass1(2)); 
     list1.Add(new SortableClass1(4)); 
     list1.Add(new SortableClass1(3)); 

     var sorted1 = SortObjects(list1); 

     foreach (var item in sorted1) 
     { 
      Console.WriteLine("SortableClass1 order " + item.Order); 
     } 

     // Test SortableClass2 
     var list2 = new List<SortableClass2>(); 

     list2.Add(new SortableClass2() { Order = 6 }); 
     list2.Add(new SortableClass2() { Order = 2 }); 
     list2.Add(new SortableClass2() { Order = 5 }); 
     list2.Add(new SortableClass2() { Order = 1 }); 
     list2.Add(new SortableClass2() { Order = 4 }); 
     list2.Add(new SortableClass2() { Order = 3 }); 

     var sorted2 = SortObjects(list2); 

     foreach (var item in sorted2) 
     { 
      Console.WriteLine("SortableClass2 order " + item.Order); 
     } 
    } 

    private static IEnumerable<T> SortObjects<T>(IList<T> objectsToSort) where T : ISortable 
    { 
     if (objectsToSort.Any(x => x.Order != 0)) 
     { 
      return objectsToSort.OrderBy(x => x.Order); 
     } 

     return objectsToSort; 
    } 
} 
Cuestiones relacionadas