Megosztás a következőn keresztül:


Mikor kell felülbírálni és új kulcsszavakat használni (C# programozási útmutató)

A C#-ban egy származtatott osztály metódusának neve megegyezhet az alaposztály metódusával. Az új és felülbírálási kulcsszavak használatával megadhatja, hogyan működnek a metódusok. A override módosító kibővíti az alaposztály virtual metódusát, a new módosító pedig elrejt egy akadálymentes alaposztály-metódust. A különbséget a jelen témakör példái szemléltetik.

Egy konzolalkalmazásban deklarálja a következő két osztályt és BaseClassDerivedClass. DerivedClass örököl BaseClass-től.

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

A metódusban deklarálja a Main változókat bc, dcés bcdc.

  • bc egy BaseClass típus, és értéke BaseClass típusú.

  • dc egy DerivedClass típus, és értéke DerivedClass típusú.

  • bcdc egy BaseClass típus, és értéke DerivedClass típusú. Erre a változóra kell figyelni.

Mivel bc és bcdc az BaseClass típusba tartoznak, csak közvetlenül férhetnek hozzá a Method1-hoz, kivéve, ha típuskonverziót használ. A dc változó hozzáfér mind a Method1-hoz, mind a Method2-hoz. Ezek a kapcsolatok az alábbi kódban jelennek meg.

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  
}  

Ezután adja hozzá a következő Method2 metódust a következőhöz BaseClass. A módszer szignatúrája megegyezik a Method2 módszer szignatúrájával a DerivedClass-ben.

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

Mivel BaseClass most már van egy Method2 metódusa, egy második hívási utasítás is hozzáadható a változókhoz BaseClassbc , és bcdcaz alábbi kódban látható módon.

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

A projekt létrehozásakor láthatja, hogy a Method2 metódus BaseClass hozzáadása figyelmeztetést okoz. A figyelmeztetés azt jelzi, hogy a Method2 metódus a DerivedClass elrejti a Method2 metódust a BaseClass. Javasoljuk, hogy használja a kulcsszót new a Method2 definícióban, ha ezt az eredményt szeretné eredményezni. Másik lehetőségként átnevezheti az egyik metódust a Method2 figyelmeztetés feloldásához, de ez nem mindig praktikus.

A hozzáadás new előtt futtassa a programot a további hívási utasítások által előállított kimenet megtekintéséhez. A következő eredmények jelennek meg.

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

A new kulcsszó megőrzi azokat a kapcsolatokat, amelyek ezt a kimenetet eredményezik, de elnyomja a figyelmeztetést. A típussal BaseClass rendelkező változók továbbra is hozzáférnek a tagokhoz BaseClass, a típussal DerivedClass rendelkező változó pedig először továbbra is a tagokhoz DerivedClass fér hozzá, majd figyelembe veszi az örökölt BaseClasstagokat.

A figyelmeztetés elnyomásához adja hozzá a new módosítót a Method2 fájlbeli DerivedClass definícióhoz, ahogy az a következő kódban látható. A módosító a következő előtt vagy után publicadható hozzá.

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

Futtassa újra a programot annak ellenőrzéséhez, hogy a kimenet nem változott-e. Ellenőrizze azt is, hogy a figyelmeztetés már nem jelenik-e meg. A(z) new használatával azt állítja, hogy tisztában van azzal, hogy az általa módosított tag elrejt egy az alaposztályból örökölt tagot. Az öröklés során elrejtett névvel kapcsolatos további információkért lásd az új módosítót.

Ha ezt a viselkedést a használat overridehatásaival szeretné ellentétbe helyezni, adja hozzá a következő metódust.DerivedClass A override módosító hozzáadható a public elé vagy mögé.

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

Adja hozzá a virtual módosítót a(z) Method1 definícióhoz BaseClass. A virtual módosító hozzáadható a public elé vagy mögé.

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

Futtassa újra a projektet. Figyelje meg különösen az alábbi kimenet utolsó két sorát.

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

A override módosító használata lehetővé teszi bcdc számára, hogy hozzáférjen a Method1 által definiált DerivedClass metódushoz. Általában ez a kívánt viselkedés az öröklési hierarchiákban. Azt szeretné, hogy a származtatott osztályból létrehozott értékekkel rendelkező objektumok a származtatott osztályban definiált metódusokat használják. Ezt a viselkedést úgy éri el, hogy a override-t használja az alaposztály-metódus kibővítéséhez.

Az alábbi kód a teljes példát tartalmazza.

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

Az alábbi példa egy másik kontextus hasonló viselkedését szemlélteti. A példa három osztályt határoz meg: egy névvel ellátott Car alaposztályt és két abból származtatott osztályt és ConvertibleCarMinivan . Az alaposztály tartalmaz egy metódust DescribeCar . A metódus megjeleníti az autó alapszintű leírását, majd meghívja ShowDetails a további információk megadására. A három osztály mindegyike meghatároz egy metódust ShowDetails . A new módosítót arra használják, hogy meghatározzák a ShowDetails-t a ConvertibleCar osztályban. A override módosítót arra használják, hogy meghatározzák a ShowDetails-t a Minivan osztályban.

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

A példa teszteli, hogy melyik verziót hívják meg a ShowDetails kapcsán. Az alábbi metódus TestCars1az egyes osztályok egy-egy példányát deklarálja, majd meghívja DescribeCar az egyes példányokat.

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 a következő kimenetet állítja elő. Figyelje meg különösen a car2 eredményeit, amelyek valószínűleg nem azt mutatják, amire számított. Az objektum típusa azConvertibleCar, de DescribeCar nem éri el az osztályban ShowDetails definiált verziótConvertibleCar, mert a metódus a módosítóval new van deklarálva, nem a override módosítóval. Ennek eredményeként egy ConvertibleCar objektum ugyanazzal a leírással jelenik meg, mint egy Car objektum. Hasonlítsa össze az eredményeket a car3, amely egy Minivan objektum. Ebben az esetben az ShowDetails osztályban Minivan deklarált metódus felülírja az ShowDetails osztályban Car deklarált metódust, és a megjelenő leírás egy kisbuszt ír le.

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

TestCars2 létrehoz egy listát a típussal Carrendelkező objektumokról. Az objektumok értékeit az Car, ConvertibleCar és Minivan osztályokból példányosítják. Minden listaelemre meghívódik a DescribeCar. Az alábbi kód a definíciót TestCars2mutatja.

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

A következő kimenet jelenik meg. Figyelje meg, hogy ugyanaz, mint a TestCars1 által megjelenített kimenet. Az ShowDetails osztály ConvertibleCar metódusa nem hívódik meg, függetlenül attól, hogy az objektum típusa ConvertibleCar, mint az TestCars1, vagy Car, mint az TestCars2. Ezzel szemben car3 mindkét esetben meghívja a ShowDetails metódust az Minivan osztályból, legyen szó típusról Minivan vagy típusról Car.

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

Metódusok TestCars3 és TestCars4 teljesítik a példát. Ezek a metódusok közvetlenül hívják meg ShowDetails, először a típusnak ConvertibleCar deklarált Minivan objektumokból, majd a TestCars3 típusnak deklarált Car objektumokból TestCars4. A következő kód határozza meg ezt a két metódust.

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

A metódusok a következő kimenetet állítják elő, amely megfelel a jelen témakör első példájából származó eredményeknek.

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

Az alábbi kód a teljes projektet és annak kimenetét mutatja.

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

Lásd még