2011-01-10 13 views
37

Sto provando a creare una classe astratta che definisce una proprietà con un getter. Voglio lasciarlo alle classi derivate per decidere se vogliono implementare un setter per la proprietà o meno. È possibile?Proprietà astratta con getter pubblico, definire il setter privato nella classe concreta possibile?

Quello che ho finora:

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

In ConcreteClass1, ottengo un errore sul set. Non può eseguire l'override di set_Value perché in Astroclass non sono presenti accessori di accesso sovrascrivibili.

In ConcreteClass2, viene visualizzato un errore su entrambi Value perché un membro con lo stesso nome è già dichiarato.

ConcreteClass3 non dà un errore, ma anche se di accesso set di valore sarebbe compilato in SET_VALUE, non funziona il contrario. La definizione di set_Value non significa che Value ottiene un accesso di configurazione. Quindi non posso assegnare un valore a una proprietà ConcreteClass3.Value. I può utilizzare ConcreteClass3.set_Value ("valore"), ma non è quello che sto cercando di ottenere qui.

È possibile che la classe astratta richieda un getter pubblico, pur consentendo la definizione di un setter opzionale in una classe derivata?

Nel caso ve lo stiate chiedendo, questa è solo una domanda teorica. Non ho una situazione reale in cui è necessaria una cosa del genere. Ma posso immaginare una classe astratta a cui non importa come viene impostata una proprietà, ma che deve essere in grado di ottenere la proprietà.

risposta

28

Sfortunatamente, non è possibile fare esattamente ciò che si desidera. È possibile farlo con le interfacce però:

public interface IInterface { 
    string MyProperty { get; } 
} 

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

Il modo in cui lo farei è quello di avere un metodo SetProperty separata nelle classi concrete:

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

Utilizzando 'interface', non posso implementare il metodo' DoSomething' nella mia classe base (non esiste una classe base, solo un'interfaccia). Usare 'SetValue' è lo stesso di' set_Value' nel mio 'ConcreteClass3'. Ma se questa è la strada da percorrere, nominarla 'SetValue' è probabilmente meglio di' set_Value'. – comecme

+0

Il motivo set_Value non è collegato alla proprietà c'è una definizione 'PropertyDef' esplicita nell'assembly che collega i metodi' get_' e 'set_'; semplicemente nominare un metodo 'set_' non lo collega a una proprietà. Non c'è modo di fare esattamente quello che vuoi in C#; dovrai scendere a compromessi. – thecoop

+0

È possibile implementare 'DoSomething' come metodo di estensione su' IInterface'. Vedi la mia modifica. – piedar

0
Non

molto elegante, ma è il più vicino si può ottenere senza fare qualcosa di simile che avete in 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

Non vedo perché si definisce un 'nuovo DoSomething' nella classe concreta. Inoltre, la tua soluzione genererà un'eccezione in fase di runtime, in fase di compilazione l'assenza di un'implementazione Value non verrà notata affatto. – comecme

Problemi correlati