Ich habe mir diesen Blog-Beitrag angesehen und folgende Fragen gestellt:
- Warum brauchen wir das
new
Schlüsselwort, um nur anzugeben, dass eine Basisklassenmethode ausgeblendet wird. Ich meine, warum brauchen wir das? Wenn wir dasoverride
Schlüsselwort nicht verwenden, verstecken wir dann nicht die Basisklassenmethode? - Warum wird in C # standardmäßig ausgeblendet und nicht überschrieben? Warum haben die Designer das so umgesetzt?
c#
overriding
Sandkasten
quelle
quelle
Antworten:
Gute Fragen. Lassen Sie mich sie noch einmal sagen.
Lassen Sie mich diese Frage mit einem Beispiel beantworten. Sie haben eine Schnittstelle von CLR v1:
interface IEnumerable { IEnumerator GetEnumerator(); }
Super. Jetzt in CLR v2 haben Sie Generika und Sie denken "Mann, wenn wir nur Generika in v1 gehabt hätten, hätte ich dies zu einer generischen Schnittstelle gemacht. Aber ich habe es nicht getan. Ich sollte jetzt etwas damit kompatibles machen, das generisch ist, damit Ich bekomme die Vorteile von Generika, ohne die Abwärtskompatibilität mit Code zu verlieren, der IEnumerable erwartet. "
interface IEnumerable<T> : IEnumerable { IEnumerator<T> .... uh oh
Wie werden Sie die GetEnumerator-Methode aufrufen
IEnumerable<T>
? Denken Sie daran, dass GetEnumerator auf der nicht generischen Basisschnittstelle ausgeblendet werden soll. Sie möchten niemals, dass dieses Ding aufgerufen wird, es sei denn, Sie befinden sich explizit in einer abwärtskompatiblen Situation.Das allein rechtfertigt das Verstecken von Methoden. Weitere Gedanken zu Begründungen des Versteckens von Methoden finden Sie in meinem Artikel zu diesem Thema .
Weil wir Sie darauf aufmerksam machen möchten, dass Sie etwas verstecken und es möglicherweise versehentlich tun. Denken Sie daran, dass Sie möglicherweise versehentlich etwas verstecken, weil die Basisklasse von einer anderen Person bearbeitet wurde, anstatt dass Sie Ihre abgeleitete Klasse bearbeitet haben.
Gleicher Grund. Möglicherweise verstecken Sie versehentlich etwas, weil Sie gerade eine neue Version einer Basisklasse ausgewählt haben. Das passiert die ganze Zeit. FooCorp erstellt eine Basisklasse B. BarCorp erstellt eine abgeleitete Klasse D mit einer Methodenleiste, da ihre Kunden diese Methode mögen. FooCorp sieht das und sagt, hey, das ist eine gute Idee, wir können diese Funktionalität auf die Basisklasse übertragen. Sie tun dies und liefern eine neue Version von Foo.DLL aus. Wenn BarCorp die neue Version aufnimmt, wäre es schön, wenn ihnen mitgeteilt würde, dass ihre Methode jetzt die Basisklassenmethode verbirgt.
Wir möchten, dass diese Situation eine Warnung und kein Fehler ist, da dies bedeutet, dass dies eine andere Form des Problems der spröden Basisklasse ist . C # wurde sorgfältig entwickelt, damit bei einer Änderung an einer Basisklasse die Auswirkungen auf Code, der eine abgeleitete Klasse verwendet, minimiert werden.
Weil virtuelles Überschreiben gefährlich ist . Durch die virtuelle Überschreibung können abgeleitete Klassen das Verhalten von Code ändern, der für die Verwendung von Basisklassen kompiliert wurde. Etwas Gefährliches wie eine Außerkraftsetzung zu tun, sollte etwas sein, das Sie bewusst und absichtlich tun , nicht zufällig.
quelle
Wenn der Methode in der abgeleiteten Klasse das neue Schlüsselwort vorangestellt wird, wird die Methode als unabhängig von der Methode in der Basisklasse definiert
Wenn Sie jedoch weder neu noch Überschreibungen angeben, ist die resultierende Ausgabe dieselbe wie bei der Angabe von neu, es wird jedoch eine Compiler-Warnung angezeigt (da Sie möglicherweise nicht wissen, dass Sie eine Methode in der Basisklassenmethode ausblenden). oder Sie wollten es vielleicht überschreiben und haben nur vergessen, das Schlüsselwort anzugeben).
So können Sie Fehler vermeiden und explizit zeigen, was Sie tun möchten, und der Code ist besser lesbar, sodass Sie Ihren Code leicht verstehen können.
quelle
Es ist erwähnenswert, dass der einzige Effekt
new
in diesem Zusammenhang darin besteht, eine Warnung zu unterdrücken. Die Semantik ändert sich nicht.Eine Antwort lautet also: Wir müssen
new
dem Compiler signalisieren, dass das Verstecken beabsichtigt ist, und die Warnung entfernen.Die folgende Frage lautet: Wenn Sie eine Methode nicht überschreiben können / können, warum sollten Sie dann eine andere Methode mit demselben Namen einführen? Weil das Verstecken im Wesentlichen ein Namenskonflikt ist. Und Sie würden es natürlich in den meisten Fällen vermeiden.
Der einzige gute Grund, warum ich mir vorstellen kann, absichtlich zu verstecken, ist, wenn Ihnen ein Name von einer Schnittstelle aufgezwungen wird.
quelle
In C # sind Mitglieder standardmäßig versiegelt, was bedeutet, dass Sie sie nicht überschreiben können (es sei denn, sie sind mit den Schlüsselwörtern
virtual
oder gekennzeichnetabstract
), und dies aus Leistungsgründen . Der neue Modifikator wird verwendet, um ein geerbtes Mitglied explizit auszublenden.quelle
Wenn das Überschreiben standardmäßig ohne Angabe des
override
Schlüsselworts war, können Sie versehentlich eine Methode Ihrer Basis überschreiben, nur aufgrund der Namensgleichheit.Die Strategie des .Net-Compilers besteht darin, Warnungen auszugeben, wenn etwas schief gehen könnte, um sicher zu gehen. Wenn in diesem Fall das Überschreiben standardmäßig aktiviert ist, muss für jede Überschreibungsmethode eine Warnung angezeigt werden - etwa "Warnung: Überprüfen Sie, ob Sie dies wirklich möchten." überschreiben'.
quelle
Meine Vermutung wäre hauptsächlich auf die Vererbung mehrerer Schnittstellen zurückzuführen. Bei Verwendung diskreter Schnittstellen ist es sehr wahrscheinlich, dass zwei unterschiedliche Schnittstellen dieselbe Methodensignatur verwenden. Wenn Sie die Verwendung des
new
Schlüsselworts zulassen, können Sie diese verschiedenen Implementierungen mit einer Klasse erstellen, anstatt zwei unterschiedliche Klassen erstellen zu müssen.Aktualisiert ... Eric gab mir eine Idee, wie ich dieses Beispiel verbessern kann.
public interface IAction1 { int DoWork(); } public interface IAction2 { string DoWork(); } public class MyBase : IAction1 { public int DoWork() { return 0; } } public class MyClass : MyBase, IAction2 { public new string DoWork() { return "Hi"; } } class Program { static void Main(string[] args) { var myClass = new MyClass(); var ret0 = myClass.DoWork(); //Hi var ret1 = ((IAction1)myClass).DoWork(); //0 var ret2 = ((IAction2)myClass).DoWork(); //Hi var ret3 = ((MyBase)myClass).DoWork(); //0 var ret4 = ((MyClass)myClass).DoWork(); //Hi } }
quelle
new
Schlüsselwort können Sie ab diesem Zeitpunkt auch die Vererbungsbasis für alle untergeordneten Elemente ändern.Wie bereits erwähnt, ermöglicht das Ausblenden von Methoden / Eigenschaften das Ändern von Dingen an einer Methode oder Eigenschaft, die ansonsten nicht ohne weiteres geändert werden könnten. Eine Situation, in der dies nützlich sein kann, besteht darin, einer geerbten Klasse Lese- / Schreibeigenschaften zuzuweisen, die in der Basisklasse schreibgeschützt sind. Angenommen, eine Basisklasse verfügt über eine Reihe von schreibgeschützten Eigenschaften namens Value1-Value40 (natürlich würde eine echte Klasse bessere Namen verwenden). Ein versiegelter Nachkomme dieser Klasse hat einen Konstruktor, der ein Objekt der Basisklasse nimmt und die Werte von dort kopiert. Die Klasse erlaubt nicht, dass sie danach geändert werden. Ein anderer, vererbbarer Nachkomme deklariert eine Lese- / Schreibeigenschaft namens Value1-Value40, die sich beim Lesen genauso verhält wie die Basisklassenversionen, beim Schreiben jedoch das Schreiben der Werte ermöglicht.
Ein Ärger bei diesem Ansatz - vielleicht kann mir jemand helfen - ist, dass ich keine Möglichkeit kenne, eine bestimmte Eigenschaft innerhalb derselben Klasse zu beschatten und zu überschreiben. Erlaubt eine der CLR-Sprachen dies (ich verwende vb 2005)? Es wäre nützlich, wenn das Basisklassenobjekt und seine Eigenschaften abstrakt sein könnten, aber dies würde eine Zwischenklasse erfordern, um die Eigenschaften Value1 bis Value40 zu überschreiben, bevor eine untergeordnete Klasse sie beschatten könnte.
quelle