2009-09-28 3 views
19

Vorrei forzare l'implementazione di un getter C# su una proprietà data da una classe abstract base. Le classi derivate potrebbero, se lo desiderano, fornire anche un setter per quella proprietà per l'uso pubblico del tipo con collegamento statico.Ignora proprietà readonly astratta per leggere/scrivere proprietà

Dato il seguente classe astratta:

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

Se voglio una classe derivata che implementa anche un setter, potrei ingenuamente provare:

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

    private int field; 
} 

Ma poi ho ottenere un errore di sintassi da quando ho prova a scavalcare il setter non esistente. Ho provato in un altro modo, come dichiarare privato il setter di base e così ancora mi imbatto in tutti i tipi di errori che mi impediscono di farlo. Ci deve essere un modo per farlo in quanto non infrange alcun contratto di classe base.

Inavvertitamente, può essere fatto con le interfacce, ma ho davvero bisogno di quella implementazione di default.

Mi sono imbattuto in questa situazione così spesso, mi chiedevo se c'era un trucco di sintassi C# nascosto per farlo, altrimenti mi limiterò a conviverci e implementerò un metodo manuale SetProperty().

+0

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

risposta

11

Non è possibile farlo direttamente, poiché non è possibile utilizzare new e override con la stessa firma sullo stesso tipo; ci sono due opzioni - se controlli la classe base, aggiungere un alloggio secondo:

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

altro si può introdurre un ulteriore livello nella gerarchia delle classi:

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

vostre soluzioni sono interessanti, io riflettere un po 'su di loro. – Coincoin

+1

La tua soluzione è la cosa più vicina alla cosa. Ma non credo sia possibile farlo senza costringere la classe derivata a fare acrobazie. – Coincoin

2

Che dire qualcosa del tipo:

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

    protected abstract int GetProperty(); 
} 
+1

Ogni erede ora deve ignorare entrambi - un po 'ridondante? –

+0

Solo se si esclude la proprietà. Altrimenti, senza la proprietà virtuale che potrebbe effettivamente essere un'alternativa accettabile. – Coincoin

+1

Se non si esegue l'override della proprietà, lo scopo del set è molto ... insolito. –

1

Questo soddisfa le tue esigenze?

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

Il virtual stato rimosso, ma il valore di base è ancora la memoria di sola per il valore. Quindi questo dovrebbe mostrare "5". E il compilatore dovrebbe polverone su 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

ho avuto un requisito analogo in cui avevo bisogno di un'interfaccia di essere in grado di condividere le funzionalità di ordinamento comune tra due classi vagamente correlati. Uno di loro aveva una proprietà Order di sola lettura e l'altro aveva una proprietà Order di lettura-scrittura, ma avevo bisogno di un modo per leggere la proprietà allo stesso modo da entrambe le classi.

Si scopre che questo può essere fatto nascondendo il valore di sola lettura in un'interfaccia derivata. Ecco come l'ho fatto.

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