Freigeben über


Wissen, wann Überschreibung und neue Schlüsselwörter verwendet werden sollen (C#-Programmierhandbuch)

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 Typ BaseClass, und sein Wert ist vom Typ BaseClass.

  • dc ist vom Typ DerivedClass, und sein Wert ist vom Typ DerivedClass.

  • bcdc ist vom Typ BaseClass, und sein Wert ist vom Typ DerivedClass. 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 overridezu 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 BaseClasshinzu. 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 TestCars1deklariert 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 ConvertibleCarwie in TestCars1, oder Carwie 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.");  
        }  
    }  
  
}  

Siehe auch