2017-02-06 4 views
1

Ich habe eine Situation, in der ich möchte, dass die normale Eigenschaft schreibgeschützt in der abgeleiteten Klasse mit dem Standardwert ist. Ich bin mit Stichwort neue zu diesem Zweck in der folgenden Art und Weise:Ändern der BaseClass-Eigenschaft in readonly in DerivedClass mit new und override

public abstract class BaseClass 
{ 
    public virtual string SomeInfo { get; set; } 
} 
public class DerivedClass1 : BaseClass 
{ 
    public new string SomeInfo => "ChildInfo1"; // C# 6.0 equivalent of { get { return "ChildInfo1"; } } 
} 

Es funktioniert gut, und new DerivedClass1().SomeInfo kann nicht zugewiesen werden - es ist nur lesbar. Ich bin mir bewusst, dass man es durch Basisklasse zugreifen konnte:

BaseClass b1 = new DerivedClass1(); 
b1.SomeInfo = "ChildInfo1 changed"; 

ich nur nicht in der Lage Benutzer möge es versehentlich zu ändern, und durch Basisklasse wäre es absichtlich sein, in welchem ​​Fall es acceptible ist.

Allerdings, wenn Abgeleitete Klasse wie folgt sein würde:

public class DerivedClass2 : BaseClass 
{ 
    public override string SomeInfo => "ChildInfo2"; 
} 

Dann ist diese Eigenschaft wäre zugänglich und man kann es scheinbar ändern, aber es würde nicht geändert werden, und ich möchte verstehen, warum?

var d2 = new DerivedClass2(); 
d2.SomeInfo = "ChildInfo2 changed"; 
Console.WriteLine(d2.SomeInfo); // output: ChildInfo2 

UPDATE:
Ich habe neue Antwort als dritte Option hinzugefügt, wahrscheinlich die beste.

+1

* „Ich will nur nicht in der Lage Benutzer versehentlich ändern, und durch Basisklasse wäre es absichtlich sein, in welchem ​​Fall es acceptible ist“ * Ist es "absichtlich", wenn der Programmierer eine Methode aufruft, die einen "BaseClass" -Parameter akzeptiert, wobei - unbemerkt vom Programmierer - diese Methode "SomeInfo" ändert? In jedem Fall verstößt das, was Sie vorschlagen, gegen das [Liskov-Substitutionsprinzip] (https://en.wikipedia.org/wiki/Liskov_substitution_principle) und sollte mit Argwohn betrachtet werden. –

+0

Ich dachte, dass dies LSP verletzen könnte. Gibt es einen anderen (besseren) Weg, dies zu erreichen, ohne es zu verletzen? – borisdj

+0

Nun, Sie könnten eine Schnittstelle erstellen, die schreibgeschützt ist und diese weitergeben, aber das würde natürlich erfordern, vorhandene Methoden zu ändern, so dass es möglicherweise keine Option ist. –

Antwort

0

Sie sollten vermeiden, in dieser Situation "neu" zu verwenden. in der abgeleiteten Klasse definieren, stattdessen eine Nur-Lese-Eigenschaft auf diese Weise:

public override string SomeInfo { get { return "ChildInfo"; } } 

Sie können noch Ihre Eigenschaft festgelegt, aber es wird immer den Standardwert „ChildInfo“ zurückzukehren.

+0

Ist es nicht das Gleiche? Dies gibt eine Warnung aus, dass vererbte Elemente ausgeblendet werden, und schlägt vor, neue hinzuzufügen oder zu überschreiben, wenn dies beabsichtigt ist. Hinzufügen von neuen nur explizit bestätigt zu verbergen, aber das Verhalten ist das gleiche? Also LSP ist immer noch verletzt. – borisdj

+0

@Boris, Sie haben Recht. Ich hatte vergessen, "override" zu schreiben. Jetzt behoben. Ja, in diesem Fall erhalten Sie mit "new" oder "override" das gleiche Ergebnis. Aber wie Sie wissen, verletzt die Verwendung von "new" LSP. – jacktric

+0

"neu" und "überschreiben" sind nicht gleich. Ihr ursprüngliches Post hatte kein Schlüsselwort von diesen zwei, und das bedeutet implizit zu verbergen, so "neu" ist das gleiche wie keine. "override" wie Sie jetzt aktualisiert haben, ist wie meine zweite Option, und in diesem Fall haben Sie Zugriff auf den Setter aber Getter ignoriert es, so dass es nicht eingängig ist. Sie denken, Sie haben Eigentum geändert, aber Sie nicht. Deshalb ist die dritte Option, die ich als eine andere Antwort hinzugefügt habe, am besten. – borisdj

1

In Ihrer Basisklasse haben Sie

public virtual string SomeInfo { get; set; } 

Es ist nur eine schöne Definition:

private string _someInfo; 
public string SomeInfo 
{ 
    get {return _someInfo;} 
    set {_someInfo = value;} 
} 

, wenn Sie es mit einem Ausdruck-Bodied Eigenschaft überschreiben Sie die bekommen Eigenschaft überschreiben mit

public string SomeInfo 
{ 
    get {return "ChildInfo2";} 
} 

Sie überschreiben jedoch die Eigenschaft set nicht, sodass Sie die private Variable immer noch festlegen können , aber es ändert nichts anderes.

wenn man sich auf dem ersten Beispiel:

BaseClass b1 = new DerivedClass1(); 
b1.SomeInfo = "ChildInfo1 changed"; 

es passiert genau das gleiche, Sie Eigenschaft könnte, da die Basisklasse Setter hat und setzt eine private Variable, aber wenn Sie auf Ausgabewert versuchen von SomeProperty, sehen Sie, dass es nicht geändert wird und immer noch "ChildInfo1" ist

+0

So legt Setter private Feld dahinter, aber Getter gibt zurück, was in Get-Teil der Property-Methode ist, die dieses Feld tatsächlich ignoriert. Ich verstehe jetzt. – borisdj

+0

@Boris ja, diese Ausdruck-Eigenschaft bedeutet nur: "immer diesen konstanten Wert zurückgeben" –

0

Ich habe jetzt dritte Optionen, die die besten sein könnten, setzen Standardwert in Constructor. Dank @MatthewWatson für die Aufmerksamkeit auf LSP und @MaksimSimkin für die Erklärung.

public abstract class BaseClass 
{ 
    public string SomeInfo { get; set; } 
} 

public class DerivedClass1 : BaseClass 
{ 
    public DerivedClass1() 
    { 
     base.SomeInfo = "ChildInfo1"; 
    } 
    public new string SomeInfo => base.SomeInfo; 
} 

Dies macht SomeInfo readonly, wenn sie von DerivedClass zugegriffen und abgerufen, wenn durch Baseclass es ist editierbar und ändern gilt regelmäßig und ist aus beiden Klassen sichtbar. Es gibt also kein "unbekanntes" Verhalten.

PS Bei älteren Versionen von C# dies entspricht:

public abstract class BaseClass 
{ 
    protected string _someInfo; 
    public string SomeInfo 
    { 
     get { return _someInfo; } 
     set { _someInfo = value; } 
    } 
} 

public class DerivedClass1 : BaseClass 
{ 
    public DerivedClass1() 
    { 
     _someInfo = "ChildInfo1"; 
    } 
    public new string SomeInfo 
    { 
     get { return _someInfo; } 
    } 
} 
Verwandte Themen