2010-11-11 5 views
9

Ich habe Hinzufügen einer Situation wie folgt aus:einen Setter auf ein virtuelles Objekt in C#

public abstract class BaseClass 
{ 
    public abstract string MyProp { get; } 
} 

Jetzt für einige der abgeleiteten Klassen, ist die Eigenschaften Wert ein synthetisiertes Werte, so gibt es keine Setzer:

public class Derived1 : BaseClass 
{ 
    public override string MyProp { get { return "no backing store"; } } 
} 

Dies funktioniert gut. Einige der abgeleiteten Klassen erforderten jedoch einen traditionelleren Hintergrundspeicher. Aber egal, wie ich es schreiben, wie die automatischen Eigenschaft oder mit einem expliziten Zusatzspeicher, erhalte ich eine Fehlermeldung:

public class Derived2 : BaseClass 
{ 
    public override string MyProp { get; private set;} 
} 

public class Derived3 : BaseClass 
{ 
    private string myProp; 
    public override string MyProp 
    { 
     get { return myProp;} 
     private set { myProp = value;} 
    } 
} 

Derived2.MyProp.set ': kann nicht außer Kraft setzen, weil ‚BaseClass.MyProp‘ tut hat einen überwindbaren set-Accessor nicht

Wie bekomme ich diese Arbeit ??

+1

Es würde funktionieren, wenn Baseclass eine Schnittstelle eher als eine abstrakte Klasse ist, die für dieses erfundene Beispiel geeignet wäre, aber vielleicht nicht in Ihrem aktuellen Code. – Mud

+0

True, BaseClass muss eine Klasse sein. Es hat Methoden implementiert, die ich nicht gezeigt habe. –

+0

Mögliche Duplikat [Warum ist es unmöglich, einen Getter geschützte Eigenschaft außer Kraft zu setzen und einen Setter hinzufügen?] (Https://stackoverflow.com/questions/82437/why-is-it-impossible-to-override-a-getter -only-property-and-add-a-setter) –

Antwort

10

Das Beste, was Sie tun können, ist die Implementierung der Eigenschaft als virtual anstelle von abstract. Nehmen Sie die get und set Blöcke für jeden Wurf NotSupportedException in der Basisklasse und außer Kraft setzen entsprechend das Verhalten in abgeleiteten Klassen:

public virtual string MyProp { 
    get { 
     throw new NotSupportedException(); 
    } 
    set { 
     throw new NotSupportedException(); 
    } 
} 
+2

Was Sie nicht dazu bringen, ist eine Kompilierzeitnachricht, wenn Sie vergessen haben, sie in der abgeleiteten Klasse zu implementieren. Sie können get und set in abstract implementieren und throw nicht explizit in der abgeleiteten Klasse implementieren, um zu zeigen, dass sie berücksichtigt wurde. – Chris

3

Grundsätzlich können Sie nicht. Wenn Sie einen Setter hinzufügen, ändern Sie die Definition der Eigenschaft, sodass die Basiseigenschaft nicht wirklich überschrieben wird. Es ist dasselbe, als ob Sie versucht hätten, eine Methode zu überschreiben und einen weiteren Parameter hinzuzufügen - sie würden als unterschiedliche Methoden (überladen) behandelt werden. Da Eigenschaften nicht überladen werden können, funktioniert dies nicht.

Sie müssen nur eine andere Methode hinzufügen, um den Wert zu setzen (vielleicht mit protected Zugänglichkeit).

+1

Ich denke nicht, dass das analog ist. Es ist eher so, als wenn 'BaseClass' eine abstrakte' GetFoo() 'Methode deklariert und die abgeleitete Klasse eine' SetFoo() 'Methode hinzufügt - sie erweitert sie, ändert sie aber nicht so, dass sie den LSP verletzt (im Gegensatz zum Ändern Methodensignaturen). –

+0

Ich stimme dir theoretisch zu, aber die Art und Weise, wie es in .NET implementiert wird, ist, dass * eine Änderung ist, weil die Eigenschaft definiert, welche Accessoren sie hat, getrennt von den Definitionen der Methoden get_ und set_, die diese implementieren Accessoren. – EMP

+1

@Ian: Ich stimme nicht zu. Die Abstraktion, die Eigenschaften geben, besteht darin, Eigenschaften einer Klasse mit der Syntax des Feldzugriffs zu erhalten/setzen. Intern werden sie als Methoden implementiert, aber das ist nebensächlich. Wenn Sie eine Eigenschaft definieren, geben Sie an, ob sie einen Wert mit unterschiedlicher Zugänglichkeit erhalten und festlegen kann. Es verletzt LSP, da in einer Klasse eine Eigenschaft so definiert ist, dass sie nur einen Get Accessor hat, dann in einer abgeleiteten Klasse dieselbe Eigenschaft wie ein anderer Accessor. –

0

Bradley Vorschlag ist gut, aber eine Sache, die ich habe in Fällen geschehen, wo nur sollte der Setter sein virtuell ist dies etwas, dies zu tun:

public class Root 
{ 
    private string _MyProp; 
    public string MyProp 
    { 
     get { return _MyProp;} 
     set { _MyProp = SetMyProp(value); } 
    } 
    protected virtual string SetMyProp(string suggestedValue) 
    { 
     return suggestedValue; 
    } 
} 
public class Child 
    : Root 
{ 
    protected override string SetMyProp(string suggestedValue) 
    { 
     string oReturn = base.SetMyProp(suggestedValue); 
     // Do some sort of cleanup here? 
     return oReturn; 
    } 
} 

es erfordert ein wenig zusätzliche Arbeit nach vorne, aber es scheint, einen höheren Grad der Verkapselung zu erhalten (zB Sie Subklassen von Überschreiben der Getter Verhalten verhindern können, und Ihre Unterklasse doesn Sie müssen sich des dahinter liegenden Mitglieds bewusst sein das Eigentum).

+0

Obwohl ich zustimme, dass dies im Allgemeinen eine bessere Vorgehensweise ist, spricht James 'Frage speziell von Eigenschaften, die möglicherweise kein zugrunde liegendes Mitglied haben. Die Bereitstellung von einem in der Basisklasse ist in seinem Szenario verschwenderisch, da nicht alle abgeleiteten Klassen dies erfordern. –

+0

Sie haben Recht. Ich lese seine Frage noch einmal, und ich glaube, ich habe die Dinge beim ersten Mal falsch verstanden. Ich dachte, er würde nur fragen, wie man einen virtuellen Setter hat ... Ich habe den Teil vermisst, dass ich nicht unbedingt einen exponierten Setter hatte. – Steven

0

Ich würde vorschlagen, virtuelle oder abstrakte Eigenschaften zu vermeiden. Verwenden Sie stattdessen eine nicht virtuelle Eigenschaft, die zu geschützten virtuellen oder abstrakten get/set-Methoden kettet. Dadurch können abgeleitete Klassen die Methoden überschreiben und die Eigenschaft auch mit einer Eigenschaft überschreiben, die über andere Zugriffsmodifizierer verfügt. Da die Basiseigenschaft selbst nicht virtuell ist, wird sie nie überschrieben werden müssen, so dass der Namenskonflikt mit der neuen Version keine Rolle spielt.

Verwandte Themen