Versionsverwaltung mit den Schlüsselwörtern "override" und "new" (C#-Programmierhandbuch)

Die C#-Sprache wurde entwickelt, damit die Versionierung von base- (Basis-) und abgeleiteten Klassen in unterschiedlichen Bibliotheken weiterentwickelt und die Abwärtskompatibilität aufrechterhalten werden kann. Das bedeutet z.B., dass die Einführung eines neuen Members in einer Basisklasse mit demselben Name wie ein Member in einer abgeleiteten Klasse von C# vollständig unterstützt wird und nicht zu unerwartetem Verhalten führt. Das bedeutet auch, dass eine Klasse explizit angeben muss, ob eine Methode für das außer Kraft setzen einer geerbten Methode vorgesehen ist, oder ob eine Methode eine neue Methode ist, die eine Methode mit ähnlichem Namen verbirgt.

In C# können abgeleitete Klassen Methoden mit dem gleichen Namen wie Basisklassen-Methoden enthalten.

  • Die Basisklasse muss als virtual definiert werden.

  • Wenn der Methode in der abgeleiteten Klasse nicht die Schlüsselwörter new oder override vorangestellt sind, gibt der Compiler eine Warnung aus, und die Methode verhält sich, als ob das Schlüsselwort new vorhanden wäre.

  • Wenn der Methode in der abgeleiteten Klasse das Schlüsselwort new vorangestellt ist, wird die Methode als unabhängig von der Methode in der Basisklasse definiert.

  • Wenn der Methode in der abgeleiteten Klasse das Schlüsselwort override vorangestellt ist, rufen Objekte der abgeleiteten Klasse diese Methode anstatt der Methode der Basisklasse auf.

  • Die Methode der Basisklasse kann mithilfe des Schlüsselworts base aus der Basisklasse heraus aufgerufen werden.

  • Die Schlüsselwörter override, virtual und new können auch auf Eigenschaften, Indexer und Ereignisse angewendet werden.

Standardmäßig sind C#-Methoden nicht virtuell. Wenn eine Methode als virtuell deklariert wird, kann jede Klasse, die die Methode erbt, ihre eigene Version implementieren. Um eine Methode in eine virtuelle Methode zu transformieren, wird der Modifizierer virtual in der Methodendeklaration der Basisklasse verwendet. Die abgeleitete Klasse kann anschließend die virtuelle Methode der Basisklasse mithilfe des Schlüsselworts override überschreiben oder die virtuelle Methode in der Basisklasse mithilfe des Schlüsselworts new verbergen. Wenn weder das Schlüsselwort override noch das Schlüsselwort new angegeben ist, gibt der Compiler eine Warnung aus, und die Methode in der abgeleiteten Klasse verbirgt die Methode in der Basisklasse.

Nehmen wir zur Veranschaulichung dieser Vorgehensweise für einen Moment an, dass die Firma A eine Klasse mit dem Namen GraphicsClass erstellt, die Ihr Programm benutzt. Die folgende Datei ist GraphicsClass:

class GraphicsClass
{
    public virtual void DrawLine() { }
    public virtual void DrawPoint() { }
}

Ihr Unternehmen verwendet diese Klasse, und Sie verwenden sie zum Ableiten einer Klasse oder zum Hinzufügen einer neuen Methode:

class YourDerivedGraphicsClass : GraphicsClass
{
    public void DrawRectangle() { }
}

Ihre Anwendung wird ohne Probleme verwendet, bis Firma A eine neue Version von GraphicsClass herausgibt, die dem folgenden Code ähnelt:

class GraphicsClass
{
    public virtual void DrawLine() { }
    public virtual void DrawPoint() { }
    public virtual void DrawRectangle() { }
}

Die neue Version von GraphicsClass enthält jetzt eine Methode namens DrawRectangle. Anfänglich geschieht nichts. Die neue Version ist immer noch binärkompatibel mit der alten Version. Jede Software, die Sie entwickelt haben, funktioniert weiterhin, sogar wenn die neue Klasse auf diesen Computersystemen installiert ist. Aufgrund vorhandener Aufrufe der Methode verweist DrawRectangle weiterhin auf Ihre Version in Ihrer abgeleiteten Klasse.

Sobald Sie Ihre Anwendung aber mit der neuen Version von GraphicsClass neu kompilieren, erhalten Sie vom Compiler eine Warnung, CS0108. Diese Warnung informiert Sie darüber, dass Sie das gewünschte Verhalten der DrawRectangle-Methode in Ihrer Anwendung bestimmen müssen.

Wenn Sie möchten, dass Ihre Methode die neue Basisklassenmethode außer Kraft setzt, verwenden Sie das Schlüsselwort override:

class YourDerivedGraphicsClass : GraphicsClass
{
    public override void DrawRectangle() { }
}

Das Schlüsselwort override stellt sicher, dass alle Objekte, die von YourDerivedGraphicsClass abgeleitet sind, die Version von DrawRectangle der abgeleiteten Klasse verwenden. Objekte, die von YourDerivedGraphicsClass abgeleitet sind, können auf die Basisklassenversion von DrawRectangle mithilfe des base-Schlüsselworts zugreifen:

base.DrawRectangle();

Wenn Sie nicht möchten, dass Ihre Methode die neue Basisklassenmethode außer Kraft setzt, gelten die folgenden Überlegungen. Sie können Ihre Methode umbenennen, um Verwechslungen zwischen den beiden Methoden zu vermeiden. Dies kann zeitaufwändig und fehleranfällig sein und ist in einigen Fällen einfach nicht praktikabel. Wenn das Projekt aber relativ klein ist, können Sie die Refactoring-Optionen von Visual Studio verwenden, um die Methode umzubenennen. Weitere Informationen finden Sie unter Refactoring von Klassen und Typen (Klassen-Designer).

Alternativ können Sie die Warnung vermeiden, indem Sie in der Definition Ihrer abgeleiteten Klasse das Schlüsselwort new verwenden:

class YourDerivedGraphicsClass : GraphicsClass
{
    public new void DrawRectangle() { }
}

Mit dem Schlüsselwort new teilt der Compiler mit, dass Ihre Definition die Definition ausblendet, die in der Basisklasse enthalten ist. Dies ist das Standardverhalten.

Überschreiben und Methodenauswahl

Wenn eine Methode in einer Klasse benannt wird, wählt der C#-Compiler die beste Methode zum Aufrufen aus, wenn mehr als eine Methode mit dem Aufruf kompatibel ist, z.B. wenn es zwei Methoden mit dem gleichen Namen und Parameter gibt, die mit dem übergebenen Parameter kompatibel sind. Die folgenden Methoden wären kompatibel:

public class Derived : Base
{
    public override void DoWork(int param) { }
    public void DoWork(double param) { }
}

Wenn DoWork für eine Instanz von Derived aufgerufen wird, versucht der C#-Compiler zuerst, den Aufruf mit den Versionen von DoWork kompatibel zu machen, die ursprünglich für Derived deklariert wurden. Override-Methoden werden nicht als Methoden angesehen, die für eine Klasse deklariert sind. Stattdessen sind sie neue Implementierungen einer Methode, die für eine Basisklasse deklariert wurde. Nur wenn der C#-Compiler keine Übereinstimmung des Methodenaufrufs mit dem Aufruf einer ursprünglichen Methode in Derived feststellen kann, versucht er, den Aufruf mit einer überschriebenen Methode mit dem gleichen Namen und kompatiblen Parametern übereinzustimmen. Beispiel:

int val = 5;
Derived d = new Derived();
d.DoWork(val);  // Calls DoWork(double).

Da die Variable val implizit in einen Double-Wert konvertiert werden kann, ruft der C#-Compiler DoWork(double) anstelle von DoWork(int) auf. Es gibt zwei Möglichkeiten, das zu vermeiden. Vermeiden Sie zuerst das Deklarieren neuer Methoden mit dem gleichen Namen wie virtuelle Methoden. Zweitens können Sie den C#-Compiler anweisen, die virtuelle Methode aufzurufen, indem Sie eine Suche nach der Liste der Basisklassenmethode durchführen lassen. Dies geschieht durch umwandeln der Instanz von Derived in Base. Da es sich um eine virtuelle Methode handelt, wird die Implementierung von DoWork(int) auf Derived aufgerufen. Beispiel:

((Base)d).DoWork(val);  // Calls DoWork(int) on Derived.

Weitere Beispiele für new und override finden Sie unter Wann müssen die Schlüsselwörter „override“ und „new“ verwendet werden?.

Siehe auch

C#-Programmierhandbuch
Klassen und Strukturen
Methoden
Vererbung