Share via


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

Die Programmiersprache C# ist so ausgelegt, dass die Versionen von Basis-Klassen und abgeleiteten Klassen in unterschiedlichen Bibliotheken weiterentwickelt werden können, wobei die Rückwärtskompatibilität erhalten bleibt. Daher wird z. B. die Einführung eines neuen Members in einer Basis-Klasse, der denselben Namen wie ein Member in einer abgeleiteten Klasse hat, vollständig durch C# unterstützt und führt nicht zu unerwartetem Verhalten. Dies bedeutet auch, dass in einer Klasse explizit angegeben werden muss, ob eine Methode eine geerbte Methode überschreiben soll oder ob es sich um eine neue Methode handelt, hinter der sich eine geerbte Methode mit ähnlichem Namen verbirgt.

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

  • Die Basisklassenmethode muss als virtual definiert werden.

  • Wenn vor der Methode in der abgeleiteten Klasse weder das new-Schlüsselwort noch das override-Schlüsselwort stehen, gibt der Compiler eine Warnung aus. Die Methode wird dann behandelt, als wäre das new-Schlüsselwort vorhanden.

  • Falls vor der Methode in der abgeleiteten Klasse das new-Schlüsselwort steht, wird die Methode als unabhängig von der Methode in der Basisklasse definiert.

  • Falls vor der Methode in der abgeleiteten Klasse das override-Schlüsselwort steht, rufen Objekte der abgeleiteten Klasse diese Methode anstatt der Basisklassenmethode auf.

  • Die Basisklassenmethode kann aus der abgeleiteten Klasse mit dem base-Schlüsselwort aufgerufen werden.

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

C#-Methoden sind standardmäßig nicht virtuell. Wenn eine Methode als virtuell deklariert ist, kann jede Klasse, die die Methode erbt, ihre eigene Version implementieren. Um aus einer Methode eine virtuelle Methode zu machen, wird der virtual-Modifizierer in der Methodendeklaration der Basisklasse verwendet. Anschließend kann die virtuelle Methode der Basisklasse von der abgeleiteten Klasse mit dem override-Schlüsselwort überschrieben werden oder mit dem new-Schlüsselwort in der Basisklasse verborgen werden. Wenn weder das override-Schlüsselwort noch das new-Schlüsselwort angegeben ist, gibt der Compiler eine Warnung aus, und die Basisklassenmethode wird von der Methode in der abgeleiteten Klasse verborgen.

Um dies praktisch zu demonstrieren, nehmen Sie einmal an, dass die Firma A eine Klasse mit dem Namen GraphicsClass erstellt hat, die von Ihrem Programm verwendet wird. GraphicsClass sieht folgendermaßen aus:

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

Sie verwenden diese Klasse, um eine eigene Klasse abzuleiten, und fügen eine neue Methode hinzu:

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

Die Anwendung funktioniert ohne Probleme, 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 mit dem Namen DrawRectangle. Anfänglich geschieht nichts. Die neue Version ist mit der alten immer noch binärkompatibel. Jede von Ihnen eingesetzte Software arbeitet weiter, auch wenn die neue Klasse auf diesen Computersystemen installiert wird. Aufrufe der Methode DrawRectangle verweisen weiterhin auf die Version in der abgeleiteten Klasse.

Sobald Sie jedoch die Anwendung mit der neuen Version von GraphicsClass erneut kompilieren, wird vom Compiler die Warnung CS0108 ausgegeben. Diese Warnung informiert Sie, dass Sie entscheiden müssen, wie sich die DrawRectangle-Methode in der Anwendung verhalten soll.

Wenn die Methode die neue Basisklassenmethode überschreiben soll, verwenden Sie das override-Schlüsselwort:

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

Das override-Schlüsselwort stellt sicher, dass alle von YourDerivedGraphicsClass abgeleiteten Objekte die abgeleitete Klassenversion von DrawRectangle verwenden. Von YourDerivedGraphicsClass abgeleitete Objekte können weiterhin mit dem Basisschlüsselwort auf die Basisklassenversion von DrawRectangle zugreifen:

base.DrawRectangle();

Wenn die Methode die neue Basisklassenmethode nicht überschreiben soll, müssen Sie die folgenden Aspekte berücksichtigen: Um Verwechslungen zwischen den beiden Methoden zu vermeiden, können Sie die Methode umbenennen. Dies kann zeitaufwändig und fehleranfällig sein und ist für einige Fälle einfach ungeeignet. Wenn das Projekt relativ klein ist, können Sie die Methode allerdings mithilfe der Umgestaltungsoptionen von Visual Studio umbenennen. Weitere Informationen finden Sie unter Umgestaltung von Klassen und Typen (Klassen-Designer).

Alternativ können Sie die Warnung mit dem new-Schlüsselwort in der Definition der abgeleiteten Klasse umgehen:

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

Das new-Schlüsselwort teilt dem Compiler mit, dass die in der Basisklasse enthaltene Definition durch Ihre Definition verborgen wird. Dies ist das Standardverhalten.

Überschreiben und Methodenauswahl

Wenn eine Methode von einer Klasse benannt wird, wählt der C#-Compiler die am besten geeignete Aufrufmethode, falls mehr als eine Methode mit dem Aufruf kompatibel ist. Dies ist z. B. der Fall bei zwei Methoden mit demselben Namen und Parametern, die mit den übergebenen Parametern übereinstimmen. Die folgenden Methoden wären kompatibel:

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

Wenn DoWork in einer Instanz von Derived aufgerufen wird, versucht der C#-Compiler zuerst den Aufruf mit den Versionen von DoWork kompatibel zu machen, die ursprünglich auf Derived deklariert wurden. Überschreibungsmethoden werden nicht als Klassendeklarationen betrachtet, sondern als neue Implementierungen einer Methode, die in einer Basisklasse deklariert ist. Nur wenn der C#-Compiler für den Methodenaufruf keine übereinstimmende ursprüngliche Methode auf Derived finden kann, versucht er, den Aufruf an eine überschriebene Methode zu richten, die den gleichen Namen und kompatible Parameter hat. Beispiele:

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

Da die Variable val implizit in double konvertiert werden kann, ruft der C#-Compiler DoWork(double) statt DoWork(int) auf. Es gibt zwei Möglichkeiten, dies zu vermeiden. Zum einen sollten Sie vermeiden, neue Methoden mit dem gleichen Namen wie virtuelle Methoden zu deklarieren. Zum anderen können Sie den C#-Compiler anweisen, die virtuelle Methode aufzurufen. Dazu muss die Instanz von Derived in Base umgewandelt werden, um dann die die Methodenliste der Basisklasse durchsuchen zu können. Da die Methode virtuell ist, wird die Implementierung von DoWork(int) für Derived aufgerufen. Beispiele:

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

Siehe auch

Referenz

Klassen und Strukturen (C#-Programmierhandbuch)

Methoden (C#-Programmierhandbuch)

Vererbung (C#-Programmierhandbuch)

Konzepte

C#-Programmierhandbuch