Ich habe eine abstrakte Klasse, die a definiert get
, aber nicht set
, weil diese abstrakte Klasse nur a benötigt get
.
public abstract BaseClass
{
public abstract double MyPop
{get;}
}
In einigen der abgeleiteten Klassen benötige ich jedoch eine set
Eigenschaft, daher sehe ich mir diese Implementierung an
public class DClass: BaseClass
{
public override double MyPop
{get;set;}
}
Das Problem ist, dass ich einen Kompilierungsfehler habe, der das sagt
* .set: kann nicht überschrieben werden, weil *. hat keinen überschreibbaren Set-Accessor.
Auch wenn ich denke, dass die obige Syntax absolut legitim ist.
Irgendeine Idee dazu? Problemumgehung oder warum ist das so?
Bearbeiten: Der einzige Ansatz, den ich mir vorstellen kann, besteht darin, beide get
und set
wie in der abstrakten Klasse zu setzen und die Unterklasse ein NotImplementedException
if auslösen zu lassen, das set
aufgerufen wird und nicht notwendig ist. Das mag ich nicht, zusammen mit einer speziellen Setter-Methode .
double
Werts verfügbar machen, der speziell in jeder Klasse implementiert wird. Manchmal muss dieser Wert festgelegt werden, daher sollten einige dieser Klassen eine Möglichkeit zum Festlegen dieses Werts bereitstellen. Ist das richtig? Wie viele Vererbungsstufen müssen Sie verwenden?Antworten:
Neu in C # 6.0:
Wenn Sie den Setter nur in Ihrem Konstruktor aufrufen, können Sie dieses Problem mithilfe schreibgeschützter Eigenschaften beheben.
void Main() { BaseClass demo = new DClass(3.6); } public abstract class BaseClass { public abstract double MyPop{ get; } } public class DClass : BaseClass { public override double MyPop { get; } public DClass(double myPop) { MyPop = myPop;} }
quelle
Eine mögliche Antwort wäre, den Getter zu überschreiben und dann eine separate Setter-Methode zu implementieren. Wenn Sie nicht möchten, dass der Eigenschaftssetzer in der Basis definiert wird, haben Sie nicht viele andere Optionen.
public override double MyPop { get { return _myPop; } } public void SetMyPop(double value) { _myPop = value; }
quelle
Es ist nicht möglich zu tun, was Sie wollen. Sie müssen den Setter in der abstrakten Eigenschaft definieren, sonst können Sie ihn nicht richtig überschreiben.
Der einzige Fall, in dem ich weiß, wo ein Getter definiert und ein Getter / Setter implementiert ist, ist die Verwendung einer Schnittstelle:
public interface IBaseInterface { double MyPop { get; } } public class DClass : IBaseInterface { public double MyPop { get; set; } }
quelle
Wenn Sie
BaseClass
sich in Ihrer eigenen Codebasis befinden, können Sie Folgendes tun:abstract public class BaseClass { abstract public double MyPop { get; protected set; } } public class DClass : BaseClass { private double _myProp; public override double MyProp { get { return _myProp; } protected set { _myProp = value; } } }
BEARBEITEN: Sie können dann eine öffentliche Methode in DClass
SetMyProp(double myProp)
oder dergleichen erstellen . Das Klassendesign für Ihr Domänenmodell sollte klar sein oder für sich selbst sprechen, warum Sie die Eigenschaft nicht direkt in der Basisklasse festlegen können und warum Sie dies in der abgeleiteten Klasse tun können.quelle
MyPop
?is a
Beziehung vorbehalten sein , um eine Sprachbeschränkung nicht zu umgehen. Außerdem verwende ich die Vererbung für andere realistischere Zwecke in der Anwendung hier.Sind Sie sicher, dass das, was Sie versuchen, ein gutes Design wäre, wenn Sie einen Weg finden würden, dies zu tun?
Es würde Objekten der Unterklasse ermöglichen, Statusänderungen vorzunehmen, die Objekte der übergeordneten Klasse nicht vornehmen können. Würde das nicht gegen das Liskov-Substitutionsprinzip verstoßen?
quelle
Sie könnten so etwas tun:
abstract class TestBase { public abstract int Int { get; } }
class TestDerivedHelper : TestBase { private int _Int; public override int Int { get { return _Int; } } protected void SetInt(int value) { this._Int = value; } } class TestDerived : TestDerivedHelper { public new int Int { get { return base.Int; } set { base.SetInt(value); } } }
Die Verwendung von TestDerived bietet die Funktionalität, die Sie suchen. Der einzige Nachteil, den ich an dieser Methode erkennen kann, ist, dass Sie jede abstrakte Methode in TestDerivedHelper implementieren müssen, aber Sie erhalten später mehr Kontrolle.
Hoffe das hilft. ;)
quelle
Der Grund, warum dies nicht möglich ist, liegt in der Art und Weise, wie Parameter von C # "magicked" werden. Wenn Sie einen Parameter definieren, erstellt C # einen privaten Feld, das vom impliziten Getter und Setter bearbeitet wird. Wenn die Basisklasse keinen Setter enthält, kann diese Variable nicht von einer in eine Unterklasse geschriebenen Methode geändert werden (da das private Flag sogar Unterklassen den Zugriff darauf untersagt). Normalerweise wird stattdessen der implizite Setter der Basisklasse verwendet.
Ich würde nicht empfehlen, die Menge in die Basisklasse aufzunehmen, wenn dies nicht alle Unterklassen können, da dies gegen das gesamte Prinzip der polymorphen Programmierung verstößt (jede in der abstrakten Klasse definierte abstrakte Methode muss von einer Unterklasse implementiert werden). Das Erstellen einer speziellen Setter-Methode, wie in anderen Antworten beschrieben, ist wahrscheinlich der beste Weg.
quelle
Belagerung
abstract class TestBase { public abstract int Int { get; } } class TestDerivedHelper : TestBase { private int _Int; public override int Int { get { return _Int; } } protected void SetInt(int value) { this._Int = value; } } class TestDerived : TestDerivedHelper { public new int Int { get { return base.Int; } set { base.SetInt(value); } } }
Ich benutze diesen Ansatz und funktioniert sehr gut für mich. Außerdem habe ich meine "TestDerivedHelper" -Klasse abstrakt gemacht, dann müssen alle Methoden in der "TestDerived" -Klasse implementiert werden.
quelle
Obwohl dieser Thread alt ist, stelle ich meine Lösung auf, falls es jemandem hilft. Es ist nicht mein eigenes, sondern basiert auf Antworten in anderen SO-Themen.
public abstract BaseClass { public double MyPoP { get { return GetMyPoP; } } protected abstract double GetMyPoP { get; } } public class DClass: BaseClass { public new double MyPoP { get; set; } protected override double GetMyPop { get { return MyPoP; } } }
Diese Lösung fügt eine zusätzliche Codezeile für jede solche Eigenschaft hinzu, für die ein Accessor geändert werden muss. Die externe Sichtbarkeit wird jedoch nicht geändert und bietet die erforderlichen Funktionen.
quelle
public abstract class BaseClass { public abstract double MyPop { get; } } public class DClass: BaseClass { private double _myPop = 0; public override double MyPop { get { return _myPop; } } // some other methods here that use the _myPop field }
Wenn Sie die Eigenschaft von außen festlegen müssen, ist
DClass
es möglicherweise besser, den Setter in die Basisklasse einzufügen.quelle
BEARBEITEN:
OK, ich war vielleicht voreilig mit dieser Antwort, aber ich habe jetzt noch etwas darüber nachgedacht.
Müssen Sie eine abstrakte Basisklasse verwenden? Wenn dies nicht erforderlich ist, versuchen Sie Folgendes:
public interface ISomeRelevantName { double MyPop { get; } } public class DClass : ISomeRelevantName { public double MyPop { get; set; } }
quelle
MyPop
vonBaseClass
nicht in der abgeleiteten Klasse implementiert ist.Warum nicht einfach eine Eigenschaft in der Basisklasse haben, die einen privaten Setter hat, dann in Ihrer Unterklasse, die den Setter benötigt, diese überschreiben und öffentlich machen.
quelle
abstract
Eigenschaftget
oder einesset
Accessorsprivate
istprotected
. Also in der Basisklasse wollen Sie:public abstract MyProp { get; protected set; }
Sie können den Set-Accessor nicht überschreiben, da für die Basisklasse kein Set-Accessor definiert ist.
Sie können das
new
Schlüsselwort verwenden, um die Implementierung der Basisklassen auszublenden. Dies ist jedoch möglicherweise nicht das, was Sie möchten.quelle
new
kann daher nicht funktionieren.