Znalost, kdy použít klíčová slova override a new (Průvodce programováním v C#)

V jazyce C# může mít metoda v odvozené třídě stejný název jako metoda v základní třídě. Způsob interakce metod můžete určit pomocí nových klíčových slov a přepsat je. override Modifikátor rozšiřuje metodu základní třídy virtual a new modifikátor skryje přístupnou metodu základní třídy. Rozdíl je znázorněn v příkladech v tomto tématu.

V konzolové aplikaci deklarujte následující dvě třídy BaseClass a DerivedClass. DerivedClass dědí z BaseClass.

class BaseClass  
{  
    public void Method1()  
    {  
        Console.WriteLine("Base - Method1");  
    }  
}  
  
class DerivedClass : BaseClass  
{  
    public void Method2()  
    {  
        Console.WriteLine("Derived - Method2");  
    }  
}  

Main V metodě deklarujte proměnné bc, dca bcdc.

  • bc je typu BaseClassa jeho hodnota je typu BaseClass.

  • dc je typu DerivedClassa jeho hodnota je typu DerivedClass.

  • bcdc je typu BaseClassa jeho hodnota je typu DerivedClass. Jedná se o proměnnou, na které je potřeba věnovat pozornost.

Protože bc a bcdc mají typ BaseClass, mohou mít pouze přímý přístup Method1, pokud nepoužíváte přetypování. Proměnná dc má přístup k oběma Method1 a Method2. Tyto relace se zobrazují v následujícím kódu.

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  
}  

Dále přidejte následující Method2 metodu do BaseClasssouboru . Podpis této metody odpovídá podpisu Method2 metody v DerivedClass.

public void Method2()  
{  
    Console.WriteLine("Base - Method2");  
}  

Vzhledem k tomu BaseClass , že nyní má metodu Method2 , lze druhý volající příkaz přidat pro BaseClass proměnné bc a bcdc, jak je znázorněno v následujícím kódu.

bc.Method1();  
bc.Method2();  
dc.Method1();  
dc.Method2();  
bcdc.Method1();  
bcdc.Method2();  

Když projekt sestavíte, uvidíte, že přidání Method2 metody způsobí BaseClass upozornění. Upozornění říká, že Method2 metoda v DerivedClass skrytí Method2 metody v BaseClass. Pokud chcete tento výsledek způsobit, doporučujeme použít new klíčové slovo v Method2 definici. Alternativně můžete přejmenovat některou z Method2 metod pro vyřešení upozornění, ale to není vždy praktické.

Před přidáním newspusťte program a zobrazte výstup vytvořený dalšími příkazy volání. Zobrazí se následující výsledky.

// Output:  
// Base - Method1  
// Base - Method2  
// Base - Method1  
// Derived - Method2  
// Base - Method1  
// Base - Method2  

Klíčové new slovo zachovává relace, které tento výstup vytvoří, ale potlačí upozornění. Proměnné, které mají typ BaseClass , nadále přistupují ke členům BaseClassa proměnná, která má typ DerivedClass , nejprve přistupuje k členům DerivedClass a pak zvažte členy zděděné z BaseClass.

Chcete-li potlačit upozornění, přidejte new modifikátor do definice Method2 in DerivedClass, jak je znázorněno v následujícím kódu. Modifikátor lze přidat před nebo za public.

public new void Method2()  
{  
    Console.WriteLine("Derived - Method2");  
}  

Spusťte program znovu a ověřte, že se výstup nezměnil. Ověřte také, že se upozornění už nezobrazuje. Pomocí , newtvrdíte, že víte, že člen, který upravuje skryje člen, který je zděděný ze základní třídy. Další informace o skrytí názvu prostřednictvím dědičnosti naleznete v tématu nový modifikátor.

Chcete-li toto chování kontrastovat s účinky použití override, přidejte následující metodu do DerivedClass. override Modifikátor lze přidat před nebo za public.

public override void Method1()  
{  
    Console.WriteLine("Derived - Method1");  
}  

virtual Přidejte modifikátor do definice Method1 in BaseClass. virtual Modifikátor lze přidat před nebo za public.

public virtual void Method1()  
{  
    Console.WriteLine("Base - Method1");  
}  

Spusťte projekt znovu. Všimněte si zejména posledních dvou řádků následujícího výstupu.

// Output:  
// Base - Method1  
// Base - Method2  
// Derived - Method1  
// Derived - Method2  
// Derived - Method1  
// Base - Method2  

Použití modifikátoru override umožňuje bcdc přístup k Method1 metodě, která je definována v DerivedClass. Obvykle se jedná o požadované chování v hierarchiích dědičnosti. Chcete, aby objekty, které mají hodnoty vytvořené z odvozené třídy, používaly metody definované v odvozené třídě. Toto chování dosáhnete použitím override k rozšíření metody základní třídy.

Následující kód obsahuje úplný příklad.

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");  
        }  
    }  
}  

Následující příklad ukazuje podobné chování v jiném kontextu. Příklad definuje tři třídy: základní třídu pojmenovanou Car a dvě třídy odvozené z ní ConvertibleCar a Minivan. Základní třída obsahuje metodu DescribeCar . Tato metoda zobrazí základní popis auta a potom zavolá ShowDetails další informace. Každá ze tří tříd definuje metodu ShowDetails . new Modifikátor se používá k definování ShowDetails ve ConvertibleCar třídě. override Modifikátor se používá k definování ShowDetails ve Minivan třídě.

// 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.");  
    }  
}  

Ukázkové testy, které verze ShowDetails je volána. Následující metoda , TestCars1deklaruje instanci každé třídy a potom volá DescribeCar na každou instanci.

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 vytvoří následující výstup. Všimněte si zejména výsledků car2, které pravděpodobně nejsou to, co jste očekávali. Typ objektu je ConvertibleCar, ale DescribeCar nemá přístup k verziShowDetails, která je definována ve ConvertibleCar třídě, protože tato metoda je deklarována s new modifikátorem, nikoli modifikátor.override V důsledku toho ConvertibleCar objekt zobrazí stejný popis jako Car objekt. Porovnejte výsledky , car3což je Minivan objekt. V tomto případě metoda deklarovaná ShowDetails ve Minivan třídě přepíše ShowDetails metodu deklarovanou ve Car třídě a popis zobrazený popis popisuje 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 vytvoří seznam objektů, které mají typ Car. Hodnoty objektů jsou vytvořena z objektu Car, ConvertibleCara Minivan třídy. DescribeCar je volána pro každý prvek seznamu. Následující kód ukazuje definici .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("----------");  
    }  
}  

Zobrazí se následující výstup. Všimněte si, že je to stejné jako výstup, který je zobrazen TestCars1. Metoda ShowDetailsConvertibleCar třídy není volána bez ohledu na to, zda typ objektu je ConvertibleCar, jako v TestCars1, nebo Car, jako v TestCars2. car3 Naopak volá metodu ShowDetailsMinivan z třídy v obou případech, zda má typ Minivan nebo typ Car.

// TestCars2  
// ----------  
// Four wheels and an engine.  
// Standard transportation.  
// ----------  
// Four wheels and an engine.  
// Standard transportation.  
// ----------  
// Four wheels and an engine.  
// Carries seven people.  
// ----------  

Metody TestCars3 a TestCars4 dokončení příkladu Tyto metody volají ShowDetails přímo, nejprve z objektů deklarovaných jako typ ConvertibleCar a Minivan (TestCars3), pak z objektů deklarovaných jako typ Car (TestCars4). Následující kód definuje tyto dvě metody.

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();  
}  

Metody vytvoří následující výstup, který odpovídá výsledkům z prvního příkladu v tomto tématu.

// TestCars3  
// ----------  
// A roof that opens up.  
// Carries seven people.  
  
// TestCars4  
// ----------  
// Standard transportation.  
// Carries seven people.  

Následující kód ukazuje úplný projekt a jeho výstup.

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.");  
        }  
    }  
  
}  

Viz také