// Cannot change source code
class Base
{
public virtual void Say()
{
Console.WriteLine("Called from Base.");
}
}
// Cannot change source code
class Derived : Base
{
public override void Say()
{
Console.WriteLine("Called from Derived.");
base.Say();
}
}
class SpecialDerived : Derived
{
public override void Say()
{
Console.WriteLine("Called from Special Derived.");
base.Say();
}
}
class Program
{
static void Main(string[] args)
{
SpecialDerived sd = new SpecialDerived();
sd.Say();
}
}
Das Ergebnis ist:
Wird von Special Derived aufgerufen.
Von Derived aufgerufen. / * dies wird nicht erwartet * /
Wird von der Basis aufgerufen.
Wie kann ich die SpecialDerived-Klasse so umschreiben, dass die Methode "Derived" der Mittelklasse nicht aufgerufen wird?
UPDATE:
Der Grund, warum ich von Derived anstelle von Base erben möchte, ist, dass die Derived-Klasse viele andere Implementierungen enthält. Da ich base.base.method()
hier nicht kann , denke ich, ist der beste Weg, Folgendes zu tun?
// Quellcode kann nicht geändert werden
class Derived : Base
{
public override void Say()
{
CustomSay();
base.Say();
}
protected virtual void CustomSay()
{
Console.WriteLine("Called from Derived.");
}
}
class SpecialDerived : Derived
{
/*
public override void Say()
{
Console.WriteLine("Called from Special Derived.");
base.Say();
}
*/
protected override void CustomSay()
{
Console.WriteLine("Called from Special Derived.");
}
}
c#
polymorphism
AZ.
quelle
quelle
Antworten:
Ich möchte dies hier nur hinzufügen, da die Leute auch nach langer Zeit noch auf diese Frage zurückkommen. Natürlich ist es eine schlechte Praxis, aber es ist (im Prinzip) immer noch möglich, das zu tun, was der Autor will:
quelle
Func<stuff>
stattAction
Dies ist eine schlechte Programmierpraxis und in C # nicht zulässig. Es ist eine schlechte Programmierpraxis, weil
Die Details der Grandbase sind Implementierungsdetails der Basis; Sie sollten sich nicht auf sie verlassen. Die Basisklasse bietet eine Abstraktion über der Basis; Sie sollten diese Abstraktion verwenden und keinen Bypass erstellen, um dies zu vermeiden.
Um ein spezifisches Beispiel für den vorherigen Punkt zu veranschaulichen: Wenn dies zulässig ist, wäre dieses Muster eine weitere Möglichkeit, Code für Fehler der spröden Basisklasse anfällig zu machen. Angenommen,
C
leitet sich ab, vonB
denen abgeleitet wirdA
. Code inC
verwendetbase.base
, um eine Methode von aufzurufenA
. DannB
erkennt der Autor von , dass er zu viel Ausrüstung in den Unterricht gesteckt hatB
, und ein besserer Ansatz besteht darin, eine Zwischenklasse zu erstellenB2
, die vonA
undB
abgeleitet istB2
. Nach dieser ÄnderungC
ruft Code in eine Methode inB2
und nicht in aufA
, daC
der Autor davon ausgegangen ist, dass die ImplementierungsdetailsB
nämlich die direkte Basisklasse sindA
würde sich nie ändern. Viele Entwurfsentscheidungen in C # dienen dazu, die Wahrscheinlichkeit verschiedener Arten von spröden Basisfehlern zu verringern. Die Entscheidung,base.base
illegal zu machen, verhindert diesen besonderen Geschmack dieses Versagensmusters vollständig.Sie haben von Ihrer Basis abgeleitet, weil Ihnen das gefällt, was es tut, und Sie es wiederverwenden und erweitern möchten. Wenn Ihnen das, was es tut, nicht gefällt und Sie es umgehen möchten, anstatt damit zu arbeiten, warum haben Sie es dann überhaupt abgeleitet? Leiten Sie von der Grandbase selbst ab, ob dies die Funktionalität ist, die Sie verwenden und erweitern möchten.
Die Basis erfordert möglicherweise bestimmte Invarianten für Sicherheits- oder semantische Konsistenzzwecke, die durch die Details der Verwendung der Methoden der Grandbase durch die Basis aufrechterhalten werden. Wenn eine abgeleitete Klasse der Basis den Code überspringen kann, der diese Invarianten verwaltet, kann die Basis in einen inkonsistenten, beschädigten Zustand versetzt werden.
quelle
Sie können nicht von C #. Von IL wird dies tatsächlich unterstützt. Sie können jede Ihrer Elternklassen nicht virtuell anrufen ... aber bitte nicht. :) :)
quelle
Die Antwort (von der ich weiß, dass sie nicht das ist, wonach Sie suchen) lautet:
Die Wahrheit ist, dass Sie nur eine direkte Interaktion mit der Klasse haben, von der Sie erben. Stellen Sie sich diese Klasse als eine Ebene vor, die ihren abgeleiteten Klassen so viel oder so wenig davon oder die Funktionalität ihrer Eltern zur Verfügung stellt, wie sie möchte.
BEARBEITEN:
Ihre Bearbeitung funktioniert, aber ich denke, ich würde so etwas verwenden:
In einer realen Implementierung können Sie natürlich aus Gründen der Erweiterbarkeit und Wartbarkeit etwas Ähnliches tun:
Abgeleitete Klassen können dann den Zustand ihrer Eltern angemessen steuern.
quelle
Derived
derBase.Say
aufgerufen wird, damit sie aufgerufen werden kannSpecialDerived
? Einfacher, nein?Warum nicht einfach die untergeordnete Klasse in eine bestimmte übergeordnete Klasse umwandeln und dann die bestimmte Implementierung aufrufen? Dies ist eine Sonderfallsituation, und es sollte eine Sonderfalllösung verwendet werden. Sie müssen das
new
Schlüsselwort jedoch in den untergeordneten Methoden verwenden.quelle
quelle
Sie können auch eine einfache Funktion in einer abgeleiteten Klasse der ersten Ebene erstellen, um die Grand-Base-Funktion aufzurufen
quelle
Mein 2c dafür ist, die Funktionalität zu implementieren, die Sie benötigen, um in einer Toolkit-Klasse aufgerufen zu werden, und diese von jedem Ort aus aufzurufen, den Sie benötigen:
Dies erfordert einige Überlegungen zum Zugriff auf Berechtigungen. Möglicherweise müssen Sie einige Zugriffsmethoden hinzufügen
internal
, um die Funktionalität zu vereinfachen.quelle
In Fällen, in denen Sie keinen Zugriff auf die abgeleitete Klassenquelle haben, aber neben der aktuellen Methode die gesamte Quelle der abgeleiteten Klasse benötigen, würde ich empfehlen, dass Sie auch eine abgeleitete Klasse erstellen und die Implementierung der abgeleiteten Klasse aufrufen.
Hier ist ein Beispiel:
quelle
Wie aus früheren Beiträgen hervorgeht, kann man argumentieren, dass etwas in der Klassenarchitektur nicht stimmt, wenn die Klassenfunktionalität umgangen werden muss. Das mag wahr sein, aber man kann die Klassenstruktur eines großen, ausgereiften Projekts nicht immer umstrukturieren oder umgestalten. Die verschiedenen Ebenen des Änderungsmanagements mögen ein Problem sein, aber es ist nicht immer eine triviale Aufgabe, vorhandene Funktionen nach dem Refactoring gleich zu halten, insbesondere wenn zeitliche Einschränkungen gelten. Bei einem ausgereiften Projekt kann es ein ziemliches Unterfangen sein, zu verhindern, dass verschiedene Regressionstests nach einer Code-Umstrukturierung bestanden werden. Es gibt oft obskure "Kuriositäten", die auftauchen. Wir hatten ein ähnliches Problem. In einigen Fällen sollte die geerbte Funktionalität nicht ausgeführt werden (oder etwas anderes ausführen). Der Ansatz, den wir unten verfolgten, war es, den Basiscode, der ausgeschlossen werden muss, in eine separate virtuelle Funktion zu setzen. Diese Funktion kann dann in der abgeleiteten Klasse überschrieben und die Funktionalität ausgeschlossen oder geändert werden. In diesem Beispiel kann verhindert werden, dass "Text 2" in der abgeleiteten Klasse ausgegeben wird.
quelle
Es scheint viele dieser Fragen zu geben, eine Mitgliedsmethode von einer Großelternklasse zu erben, sie in einer zweiten Klasse zu überschreiben und ihre Methode dann erneut von einer Enkelklasse aufzurufen. Warum nicht einfach die Mitglieder der Großeltern bis zu den Enkelkindern erben?
Scheint einfach ... das Enkelkind erbt hier die Methode der Großeltern. Denken Sie darüber nach ..... so werden "Object" und seine Mitglieder wie ToString () an alle Klassen in C # vererbt. Ich denke, Microsoft hat die grundlegende Vererbung nicht gut erklärt. Es wird zu viel Wert auf Polymorphismus und Implementierung gelegt. Wenn ich ihre Dokumentation durchforste, gibt es keine Beispiele für diese sehr grundlegende Idee. :((
quelle
Wenn Sie auf Basisklassendaten zugreifen möchten, müssen Sie das Schlüsselwort "this" verwenden oder dieses Schlüsselwort als Referenz für die Klasse verwenden.
quelle