C # Design: Warum ist neu / Überschreibung auf abstrakte Methoden erforderlich, aber nicht auf virtuelle Methoden?
-
30-09-2019 - |
Frage
Warum ist neu / Override auf abstrakte Methoden erforderlich, aber nicht auf virtuelle Methoden?
Beispiel 1:
abstract class ShapesClass
{
abstract public int Area(); // abstract!
}
class Square : ShapesClass
{
int x, y;
public int Area() // Error: missing 'override' or 'new'
{
return x * y;
}
}
Der Compiler wird diesen Fehler zeigen: Um das aktuelle Element überschreiben, dass die Umsetzung, das Schlüsselwort override hinzuzufügen. Ansonsten das neue Schlüsselwort hinzufügen
Beispiel 2:
class ShapesClass
{
virtual public int Area() { return 0; } // it is virtual now!
}
class Square : ShapesClass
{
int x, y;
public int Area() // no explicit 'override' or 'new' required
{
return x * y;
}
}
Diese übersetzt werden kann, indem die Methode standardmäßig versteckt.
Ich verstehe die technischen Unterschiede. Allerdings frage ich mich, warum die Sprache auf diese Weise gestaltet. Wäre es nicht besser, die gleiche Einschränkung haben, wie auch in „Probe 2“? Ich meine, in den meisten Fällen, wenn Sie eine Methode mit dem gleichen Namen wie in der übergeordneten Klasse zu erstellen, Sie in der Regel beabsichtigt, sie außer Kraft zu setzen. Also ich ausdrücklich außer Kraft setzt Angabe denken / New wäre auch sinnvoll auf virtuelle Methoden machen.
Gibt es einen Design-weise Grund für dieses Verhalten?
Update: Die zweite Probe tatsächlich bewirkt, dass eine Warnung aus. Die erste Probe zeigt einen Fehler, da die Unterklasse benötigt wird, um die abstrakte Methode zu implementieren. Ich habe die Warnung in VS nicht .. macht mir jetzt vollkommen erfassen. Danke.
Lösung
Unter Verwendung entweder die C # 3.0-Compiler wie in .NET 3.5 SP1 ausgeliefert, oder die C # 4.0-Compiler wie in .NET 4.0 ausgeliefert, erhalte ich die folgenden Fehler für Ihr erstes Beispiel:
Fehler CS0534: 'ConsoleApplication3.Square' implementiert nicht geerbt abstraktes Mitglied 'ConsoleApplication3.ShapesClass.Area ()
Und die folgende Warnung für den zweiten:
Warnung CS0114: 'ConsoleApplication3.Square.Area ()' versteckt geerbt Mitglied 'ConsoleApplication3.ShapesClass.Area ()'. Um das aktuelle Element überschreiben, dass Implementierung, fügen Sie das Schlüsselwort override. Ansonsten das neue Schlüsselwort hinzuzufügen.
Im ersten Fall ist es ein Fehler, weil Sie nicht tatsächlich die Basis Methode überschreiben, was bedeutet, es gibt keine Implementierung für die abstrakte Methode in einer konkreten Klasse. Im zweiten Fall ist es eine Warnung, da der Code ist technisch korrekt, aber der Compiler den Verdacht hegt, dass es nicht das, was Sie gemeint. Dies ist einer der Gründe, warum es in der Regel eine gute Idee, die „Warnungen als Fehler behandeln“ Compilation Einstellung zu aktivieren.
Also ich nicht Ihr Verhalten repro kann, und das Verhalten der Compiler sieht richtig für mich. Welche Version des Compilers verwenden Sie?
Andere Tipps
Hier ist die Antwort direkt aus dem C # spec.
... einen barrierefreien Namen von einem Versteck erbte Umfang bewirkt eine Warnung sein berichtet. Im Beispiel
class Base
{
public void F() {}
}
class Derived: Base
{
public void F() {} // Warning, hiding an inherited name
}
die Deklaration von F in Derived Ursachen eine Warnung gemeldet werden. Verstecken ein erbte Name ist nicht speziell ein Fehler, da dies ausschließen getrennte Entwicklung von Basisklassen. Zum Beispiel könnte die oben beschriebene Situation zustande gekommen, weil eine spätere Version of Base eingeführt, um eine F-Methode Das war nicht in einem früheren Version der Klasse. Hat das oben Situation ein Fehler aufgetreten, dann ist jede Wechsel zu einer Basisklasse in einem gemachten separat versioniert Klassenbibliothek könnte möglicherweise abgeleitet verursachen Klassen ungültig. Die Warnung verursacht durch eine vererbte Name kann versteckt werden Nutzung des neuen eliminiert durch Modifikator:
class Base
{
public void F() {}
}
class Derived: Base
{
new public void F() {}
}
Der neue Modifikator gibt an, dass der F in Abgeleitet „neu“ ist, und dass es in der Tat beabsichtigt, die geerbt zu verstecken Mitglied.
Der Unterschied besteht darin, dass die abstrakte Methode sein, außer Kraft gesetzt hat, aber die virtuelle nicht.
Es ist ein Fehler die abstrakte Klasse zu erben (in einer nicht-abstrakten Klasse) ohne alle abstrakten Mitglieder der Umsetzung, aber Sie haben nur eine Warnung erhalten, wenn sie von der Klasse erben, ohne override
oder new
für die virtuelle Methode angeben.
ich in der ersten Art und Weise denken Sie die Compiler-Fehler, weil die abstrakte Methode verborgen ist und nicht umgesetzt (so effektiv Ihre Klasse ist falsch, und es wäre schwierig, herauszufinden, warum). Im zweiten Fall, dass Sie nur eine Warnung erhalten, weil die Klasse verwendbar ist.
Versioning
Auf den ersten Blick könnte man meinen, dass Verfahren Versteck nicht besonders nützlich erscheint. Es ist eine Situation,
wo man braucht, es zu benutzen, aber. Angenommen, Sie haben eine Klasse namens MotorVehicle
verwenden möchten, dass
wurde von einem anderen Programmierer geschrieben, und Sie wollen diese Klasse verwenden, um Ihre eigene Klasse abzuleiten. Des Weiteren,
Lassen Sie uns auch annehmen, dass Sie eine Accelerate()
Methode in der abgeleiteten Klasse definieren möchten. Zum Beispiel:
public class Car : MotorVehicle
{
// define the Accelerate() method
public void Accelerate()
{
Console.WriteLine(“In Car Accelerate() method”);
Console.WriteLine(model + “ accelerating”);
}
}
Als nächstes nehmen wir an, dass der andere Programmierer später der Kraftfahrzeugklasse ändert und entscheidet
ihre eigene virtual Accelerate()
Methode hinzufügen:
public class MotorVehicle
{
// define the Accelerate() method
public virtual void Accelerate()
{
Console.WriteLine(“In MotorVehicle Accelerate() method”);
Console.WriteLine(model + “ accelerating”);
}
}
Die Zugabe dieses Accelerate()
Verfahren durch die anderen Programmierer verursacht ein Problem: Die
Accelerate()
Methode in Ihrer Car
Klasse versteckt die geerbte Accelerate()
Methode nun definiert in
ihre MotorVehicle
Klasse. Später, wenn Sie Ihre Car
Klasse zu kompilieren kommen, ist es nicht klar, an den Compiler
ob Sie sollte eigentlich Ihre Methode die geerbte Methode zu verstecken. Aus diesem Grund, die
Compiler meldet die folgende Warnung, wenn Sie versuchen, Ihre Auto-Klasse zu kompilieren:
Warnung CS0114: ‚Car.Accelerate ()‘ versteckt geerbt Mitglied ‚MotorVehicle.Accelerate ()‘. Um die aktuelle Element außer Kraft gesetzt Implementierung, fügen Sie das Schlüsselwort override. Ansonsten das neue Schlüsselwort hinzuzufügen.