Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
In C# kann eine Methode in einer abgeleiteten Klasse denselben Namen wie eine Methode in der Basisklasse haben. Sie können angeben, wie die Methoden interagieren, indem Sie die neuen Schlüsselwörter verwenden und diese überschreiben . Der override
Modifizierer erweitert die Basisklassenmethode virtual
, und der new
Modifizierer blendet eine barrierefreie Basisklassenmethode aus. Der Unterschied wird in den Beispielen in diesem Thema veranschaulicht.
Deklarieren Sie in einer Konsolenanwendung die folgenden beiden Klassen BaseClass
und DerivedClass
.
DerivedClass
erbt von BaseClass
.
class BaseClass
{
public void Method1()
{
Console.WriteLine("Base - Method1");
}
}
class DerivedClass : BaseClass
{
public void Method2()
{
Console.WriteLine("Derived - Method2");
}
}
Deklarieren Sie in der Main
Methode Variablen bc
, dc
, und bcdc
.
bc
ist vom TypBaseClass
, und sein Wert ist vom TypBaseClass
.dc
ist vom TypDerivedClass
, und sein Wert ist vom TypDerivedClass
.bcdc
ist vom TypBaseClass
, und sein Wert ist vom TypDerivedClass
. Dies ist die Variable, auf die sie achten soll.
Da bc
und bcdc
vom Typ BaseClass
sind, können sie nur direkt auf Method1
zugreifen, es sei denn, sie verwenden Umwandlungen. Variable dc
kann auf sowohl Method1
als auch Method2
zugreifen. Diese Beziehungen werden im folgenden Code angezeigt.
class Program
{
static void Main(string[] args)
{
BaseClass bc = new BaseClass();
DerivedClass dc = new DerivedClass();
BaseClass bcdc = new DerivedClass();
bc.Method1();
dc.Method1();
dc.Method2();
bcdc.Method1();
}
// Output:
// Base - Method1
// Base - Method1
// Derived - Method2
// Base - Method1
}
Fügen Sie als Nächstes die folgende Method2
Methode zu BaseClass
. Die Signatur dieser Methode entspricht der Signatur der Method2
Methode in DerivedClass
.
public void Method2()
{
Console.WriteLine("Base - Method2");
}
Da BaseClass
jetzt eine Method2
Methode vorhanden ist, kann eine zweite aufrufende Anweisung für die Variablen BaseClass
, bc
und bcdc
hinzugefügt werden, wie im folgenden Code dargestellt.
bc.Method1();
bc.Method2();
dc.Method1();
dc.Method2();
bcdc.Method1();
bcdc.Method2();
Wenn Sie das Projekt erstellen, sehen Sie, dass das Hinzufügen der Method2
Methode in BaseClass
eine Warnung verursacht. Die Warnung besagt, dass die Methode Method2
in DerivedClass
die Methode Method2
in BaseClass
versteckt. Sie werden empfohlen, das new
Schlüsselwort in der Method2
Definition zu verwenden, wenn Sie dieses Ergebnis verursachen möchten. Alternativ können Sie eine der Method2
Methoden umbenennen, um die Warnung zu beheben, aber das ist nicht immer praktisch.
Führen Sie vor dem Hinzufügen von new
das Programm aus, um die von den zusätzlichen Anrufbefehlen erzeugte Ausgabe anzuzeigen. Die folgenden Ergebnisse werden angezeigt.
// Output:
// Base - Method1
// Base - Method2
// Base - Method1
// Derived - Method2
// Base - Method1
// Base - Method2
Das new
Schlüsselwort behält die Beziehungen bei, die diese Ausgabe erzeugen, unterdrückt jedoch die Warnung. Die Variablen, die den Typ BaseClass
haben, greifen weiterhin auf die Member von BaseClass
zu, und die Variable, die den Typ DerivedClass
hat, greift zuerst auf Member in DerivedClass
zu und berücksichtigt dann die von BaseClass
geerbten Member.
Um die Warnung zu unterdrücken, fügen Sie den new
Modifizierer zur Definition von Method2
"in DerivedClass
" hinzu, wie im folgenden Code dargestellt. Der Modifizierer kann vor oder nach public
hinzugefügt werden.
public new void Method2()
{
Console.WriteLine("Derived - Method2");
}
Führen Sie das Programm erneut aus, um sicherzustellen, dass sich die Ausgabe nicht geändert hat. Überprüfen Sie außerdem, ob die Warnung nicht mehr angezeigt wird. Mithilfe von new
bestätigen Sie, dass Sie sich bewusst sind, dass das Mitglied, das es modifiziert, ein geerbtes Mitglied der Basisklasse verdeckt. Weitere Informationen zum Ausblenden von Namen durch Vererbung finden Sie unter Neuer Modifikator.
Um dieses Verhalten mit den Effekten der Verwendung override
zu vergleichen, fügen Sie die folgende Methode hinzu DerivedClass
. Der override
Modifizierer kann vor oder nach public
hinzugefügt werden.
public override void Method1()
{
Console.WriteLine("Derived - Method1");
}
Fügen Sie den virtual
Modifizierer der Definition von Method1
in BaseClass
hinzu. Der virtual
Modifizierer kann vor oder nach public
hinzugefügt werden.
public virtual void Method1()
{
Console.WriteLine("Base - Method1");
}
Führen Sie das Projekt erneut aus. Achten Sie besonders auf die letzten beiden Zeilen der folgenden Ausgabe.
// Output:
// Base - Method1
// Base - Method2
// Derived - Method1
// Derived - Method2
// Derived - Method1
// Base - Method2
Die Verwendung des override
-Modifizierers ermöglicht bcdc
den Zugriff auf die Method1
-Methode, die in DerivedClass
definiert ist. In der Regel ist dies das gewünschte Verhalten in Vererbungshierarchien. Sie möchten Objekte mit Werten, die aus der abgeleiteten Klasse erstellt werden, die Methoden verwenden, die in der abgeleiteten Klasse definiert sind. Sie erreichen dieses Verhalten, indem Sie die Basisklassenmethode mit override
erweitern.
Der folgende Code enthält das vollständige Beispiel.
using System;
using System.Text;
namespace OverrideAndNew
{
class Program
{
static void Main(string[] args)
{
BaseClass bc = new BaseClass();
DerivedClass dc = new DerivedClass();
BaseClass bcdc = new DerivedClass();
// The following two calls do what you would expect. They call
// the methods that are defined in BaseClass.
bc.Method1();
bc.Method2();
// Output:
// Base - Method1
// Base - Method2
// The following two calls do what you would expect. They call
// the methods that are defined in DerivedClass.
dc.Method1();
dc.Method2();
// Output:
// Derived - Method1
// Derived - Method2
// The following two calls produce different results, depending
// on whether override (Method1) or new (Method2) is used.
bcdc.Method1();
bcdc.Method2();
// Output:
// Derived - Method1
// Base - Method2
}
}
class BaseClass
{
public virtual void Method1()
{
Console.WriteLine("Base - Method1");
}
public virtual void Method2()
{
Console.WriteLine("Base - Method2");
}
}
class DerivedClass : BaseClass
{
public override void Method1()
{
Console.WriteLine("Derived - Method1");
}
public new void Method2()
{
Console.WriteLine("Derived - Method2");
}
}
}
Im folgenden Beispiel wird ein ähnliches Verhalten in einem anderen Kontext veranschaulicht. Im Beispiel werden drei Klassen definiert: eine Basisklasse mit dem Namen Car
und zwei Klassen, die daraus abgeleitet werden, ConvertibleCar
und Minivan
. Die Basisklasse enthält eine DescribeCar
Methode. Die Methode zeigt eine grundlegende Beschreibung eines Autos an und ruft dann auf ShowDetails
, um zusätzliche Informationen bereitzustellen. Jede der drei Klassen definiert eine ShowDetails
Methode. Der new
Modifikator wird verwendet, um ShowDetails
in der ConvertibleCar
Klasse zu definieren. Der override
Modifikator wird verwendet, um ShowDetails
in der Minivan
Klasse zu definieren.
// Define the base class, Car. The class defines two methods,
// DescribeCar and ShowDetails. DescribeCar calls ShowDetails, and each derived
// class also defines a ShowDetails method. The example tests which version of
// ShowDetails is selected, the base class method or the derived class method.
class Car
{
public void DescribeCar()
{
System.Console.WriteLine("Four wheels and an engine.");
ShowDetails();
}
public virtual void ShowDetails()
{
System.Console.WriteLine("Standard transportation.");
}
}
// Define the derived classes.
// Class ConvertibleCar uses the new modifier to acknowledge that ShowDetails
// hides the base class method.
class ConvertibleCar : Car
{
public new void ShowDetails()
{
System.Console.WriteLine("A roof that opens up.");
}
}
// Class Minivan uses the override modifier to specify that ShowDetails
// extends the base class method.
class Minivan : Car
{
public override void ShowDetails()
{
System.Console.WriteLine("Carries seven people.");
}
}
Im Beispiel wird getestet, welche Version ShowDetails
aufgerufen wird. Die folgende Methode TestCars1
deklariert eine Instanz jeder Klasse und ruft dann für jede Instanz auf DescribeCar
.
public static void TestCars1()
{
System.Console.WriteLine("\nTestCars1");
System.Console.WriteLine("----------");
Car car1 = new Car();
car1.DescribeCar();
System.Console.WriteLine("----------");
// Notice the output from this test case. The new modifier is
// used in the definition of ShowDetails in the ConvertibleCar
// class.
ConvertibleCar car2 = new ConvertibleCar();
car2.DescribeCar();
System.Console.WriteLine("----------");
Minivan car3 = new Minivan();
car3.DescribeCar();
System.Console.WriteLine("----------");
}
TestCars1
erzeugt die folgende Ausgabe. Beachten Sie insbesondere die Ergebnisse für car2
, die wahrscheinlich nicht das sind, was Sie erwartet haben. Der Typ des Objekts ist ConvertibleCar
, aber DescribeCar
greift nicht auf die Version von ShowDetails
zu, die in der ConvertibleCar
-Klasse definiert ist, da diese Methode mit dem new
-Modifizierer und nicht mit dem override
-Modifizierer deklariert wird. Daher zeigt ein ConvertibleCar
Objekt dieselbe Beschreibung wie ein Car
Objekt an. Vergleichen Sie die Ergebnisse für car3
, das ein Minivan
-Objekt ist. In diesem Fall setzt die ShowDetails
in der Minivan
Klasse deklarierte Methode die ShowDetails
in der Car
Klasse deklarierte Methode außer Kraft, und die beschreibung, die angezeigt wird, beschreibt einen Minivan.
// TestCars1
// ----------
// Four wheels and an engine.
// Standard transportation.
// ----------
// Four wheels and an engine.
// Standard transportation.
// ----------
// Four wheels and an engine.
// Carries seven people.
// ----------
TestCars2
erstellt eine Liste von Objekten mit Typ Car
. Die Werte der Objekte werden instanziiert aus den Klassen Car
, ConvertibleCar
und Minivan
.
DescribeCar
wird für jedes Element der Liste aufgerufen. Der folgende Code zeigt die Definition von TestCars2
.
public static void TestCars2()
{
System.Console.WriteLine("\nTestCars2");
System.Console.WriteLine("----------");
var cars = new List<Car> { new Car(), new ConvertibleCar(),
new Minivan() };
foreach (var car in cars)
{
car.DescribeCar();
System.Console.WriteLine("----------");
}
}
Die folgende Ausgabe wird angezeigt. Beachten Sie, dass es mit der Ausgabe identisch ist, die von TestCars1
angezeigt wird. Die ShowDetails
Methode der ConvertibleCar
Klasse wird nicht aufgerufen, unabhängig davon, ob der Typ des Objekts ConvertibleCar
wie in TestCars1
, oder Car
wie in TestCars2
. Im Gegensatz dazu ruft car3
in beiden Fällen die Methode ShowDetails
aus der Klasse Minivan
auf, unabhängig davon, ob sie Typ Minivan
oder Typ Car
hat.
// TestCars2
// ----------
// Four wheels and an engine.
// Standard transportation.
// ----------
// Four wheels and an engine.
// Standard transportation.
// ----------
// Four wheels and an engine.
// Carries seven people.
// ----------
Methoden TestCars3
und TestCars4
vervollständigen das Beispiel. Diese Methoden rufen ShowDetails
direkt auf, zuerst von Objekten, die vom Typ ConvertibleCar
und Minivan
(TestCars3
) deklariert wurden, und dann von Objekten, die vom Typ Car
(TestCars4
) deklariert wurden. Der folgende Code definiert diese beiden Methoden.
public static void TestCars3()
{
System.Console.WriteLine("\nTestCars3");
System.Console.WriteLine("----------");
ConvertibleCar car2 = new ConvertibleCar();
Minivan car3 = new Minivan();
car2.ShowDetails();
car3.ShowDetails();
}
public static void TestCars4()
{
System.Console.WriteLine("\nTestCars4");
System.Console.WriteLine("----------");
Car car2 = new ConvertibleCar();
Car car3 = new Minivan();
car2.ShowDetails();
car3.ShowDetails();
}
Die Methoden erzeugen die folgende Ausgabe, die den Ergebnissen aus dem ersten Beispiel in diesem Abschnitt entspricht.
// TestCars3
// ----------
// A roof that opens up.
// Carries seven people.
// TestCars4
// ----------
// Standard transportation.
// Carries seven people.
Der folgende Code zeigt das vollständige Projekt und dessen Ausgabe.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace OverrideAndNew2
{
class Program
{
static void Main(string[] args)
{
// Declare objects of the derived classes and test which version
// of ShowDetails is run, base or derived.
TestCars1();
// Declare objects of the base class, instantiated with the
// derived classes, and repeat the tests.
TestCars2();
// Declare objects of the derived classes and call ShowDetails
// directly.
TestCars3();
// Declare objects of the base class, instantiated with the
// derived classes, and repeat the tests.
TestCars4();
}
public static void TestCars1()
{
System.Console.WriteLine("\nTestCars1");
System.Console.WriteLine("----------");
Car car1 = new Car();
car1.DescribeCar();
System.Console.WriteLine("----------");
// Notice the output from this test case. The new modifier is
// used in the definition of ShowDetails in the ConvertibleCar
// class.
ConvertibleCar car2 = new ConvertibleCar();
car2.DescribeCar();
System.Console.WriteLine("----------");
Minivan car3 = new Minivan();
car3.DescribeCar();
System.Console.WriteLine("----------");
}
// Output:
// TestCars1
// ----------
// Four wheels and an engine.
// Standard transportation.
// ----------
// Four wheels and an engine.
// Standard transportation.
// ----------
// Four wheels and an engine.
// Carries seven people.
// ----------
public static void TestCars2()
{
System.Console.WriteLine("\nTestCars2");
System.Console.WriteLine("----------");
var cars = new List<Car> { new Car(), new ConvertibleCar(),
new Minivan() };
foreach (var car in cars)
{
car.DescribeCar();
System.Console.WriteLine("----------");
}
}
// Output:
// TestCars2
// ----------
// Four wheels and an engine.
// Standard transportation.
// ----------
// Four wheels and an engine.
// Standard transportation.
// ----------
// Four wheels and an engine.
// Carries seven people.
// ----------
public static void TestCars3()
{
System.Console.WriteLine("\nTestCars3");
System.Console.WriteLine("----------");
ConvertibleCar car2 = new ConvertibleCar();
Minivan car3 = new Minivan();
car2.ShowDetails();
car3.ShowDetails();
}
// Output:
// TestCars3
// ----------
// A roof that opens up.
// Carries seven people.
public static void TestCars4()
{
System.Console.WriteLine("\nTestCars4");
System.Console.WriteLine("----------");
Car car2 = new ConvertibleCar();
Car car3 = new Minivan();
car2.ShowDetails();
car3.ShowDetails();
}
// Output:
// TestCars4
// ----------
// Standard transportation.
// Carries seven people.
}
// Define the base class, Car. The class defines two virtual methods,
// DescribeCar and ShowDetails. DescribeCar calls ShowDetails, and each derived
// class also defines a ShowDetails method. The example tests which version of
// ShowDetails is used, the base class method or the derived class method.
class Car
{
public virtual void DescribeCar()
{
System.Console.WriteLine("Four wheels and an engine.");
ShowDetails();
}
public virtual void ShowDetails()
{
System.Console.WriteLine("Standard transportation.");
}
}
// Define the derived classes.
// Class ConvertibleCar uses the new modifier to acknowledge that ShowDetails
// hides the base class method.
class ConvertibleCar : Car
{
public new void ShowDetails()
{
System.Console.WriteLine("A roof that opens up.");
}
}
// Class Minivan uses the override modifier to specify that ShowDetails
// extends the base class method.
class Minivan : Car
{
public override void ShowDetails()
{
System.Console.WriteLine("Carries seven people.");
}
}
}