Veta när du ska använda åsidosättning och nya nyckelord (C#-programmeringsguide)

I C# kan en metod i en härledd klass ha samma namn som en metod i basklassen. Du kan ange hur metoderna interagerar med hjälp av de nya och åsidosättningsnyckelorden . Modifieraren overrideutökar basklassmetoden virtual och new modifieraren döljer en tillgänglig basklassmetod. Skillnaden visas i exemplen i det här avsnittet.

Deklarera följande två klasser BaseClass i ett konsolprogram och DerivedClass. DerivedClass ärver från BaseClass.

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

Main I -metoden deklarerar du variablerna bc, dcoch bcdc.

  • bc är av typen BaseClassoch dess värde är av typen BaseClass.

  • dc är av typen DerivedClassoch dess värde är av typen DerivedClass.

  • bcdc är av typen BaseClassoch dess värde är av typen DerivedClass. Det här är variabeln att vara uppmärksam på.

Eftersom bc och bcdc har typen BaseClasskan de bara komma åt Method1direkt , såvida du inte använder gjutning. Variabeln dc kan komma åt både Method1 och Method2. Dessa relationer visas i följande kod.

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  
}  

Lägg sedan till följande Method2 metod i BaseClass. Signaturen för den här metoden matchar signaturen för Method2 metoden i DerivedClass.

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

Eftersom BaseClass nu har en Method2 metod kan en andra anropande instruktion läggas till för BaseClass variabler bc och bcdc, som visas i följande kod.

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

När du skapar projektet ser du att tillägget av Method2 metoden i BaseClass orsakar en varning. Varningen säger att Method2 metoden i DerivedClass döljer Method2 metoden i BaseClass. Du rekommenderas att använda nyckelordet newMethod2 i definitionen om du tänker orsaka det resultatet. Du kan också byta namn på en av Method2 metoderna för att lösa varningen, men det är inte alltid praktiskt.

Innan du lägger till newkör du programmet för att se utdata som genereras av de ytterligare anropssatserna. Följande resultat visas.

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

Nyckelordet new bevarar de relationer som producerar utdata, men den undertrycker varningen. Variablerna som har typen BaseClass fortsätter att komma åt medlemmarna BaseClassi , och variabeln som har typen DerivedClass fortsätter att komma åt medlemmar i DerivedClass först och sedan att överväga medlemmar som ärvts från BaseClass.

Om du vill ignorera varningen lägger du till new modifieraren i definitionen av Method2 i DerivedClass, enligt följande kod. Modifieraren kan läggas till före eller efter public.

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

Kör programmet igen för att kontrollera att utdata inte har ändrats. Kontrollera också att varningen inte längre visas. Med hjälp av newbekräftar du att du är medveten om att medlemmen som den ändrar döljer en medlem som ärvs från basklassen. Mer information om namn som döljs genom arv finns i ny modifierare.

Om du vill jämföra det här beteendet med effekterna av att använda overridelägger du till följande metod i DerivedClass. Modifieraren override kan läggas till före eller efter public.

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

virtual Lägg till modifieraren i definitionen av Method1 i BaseClass. Modifieraren virtual kan läggas till före eller efter public.

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

Kör projektet igen. Observera särskilt de två sista raderna i följande utdata.

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

Med hjälp av override modifieraren kan bcdc du komma åt metoden Method1 som definieras i DerivedClass. Det är vanligtvis det önskade beteendet i arvshierarkier. Du vill att objekt som har värden som skapas från den härledda klassen ska använda de metoder som definieras i den härledda klassen. Du uppnår det beteendet med hjälp override av för att utöka basklassmetoden.

Följande kod innehåller det fullständiga exemplet.

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

I följande exempel visas liknande beteende i en annan kontext. Exemplet definierar tre klasser: en basklass med namnet Car och två klasser som härleds från den och ConvertibleCarMinivan. Basklassen innehåller en DescribeCar metod. Metoden visar en grundläggande beskrivning av en bil och anropar ShowDetails sedan för att ange ytterligare information. Var och en av de tre klasserna definierar en ShowDetails metod. Modifieraren new används för att definiera ShowDetails i ConvertibleCar klassen. Modifieraren override används för att definiera ShowDetails i Minivan klassen.

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

Exemplet testar vilken version av ShowDetails som anropas. Följande metod, TestCars1, deklarerar en instans av varje klass och anropar DescribeCar sedan varje instans.

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 genererar följande utdata. Observera särskilt resultaten för car2, som förmodligen inte är vad du förväntade dig. Typen av objekt är ConvertibleCar, men DescribeCar har inte åtkomst till den version av ShowDetails som definieras i ConvertibleCar klassen eftersom den metoden deklareras med new modifieraren, inte override modifieraren. Därför visar ett ConvertibleCar objekt samma beskrivning som ett Car objekt. Kontrastera resultatet för car3, som är ett Minivan objekt. I det här fallet åsidosätter metoden ShowDetails som deklareras i Minivan klassen metoden ShowDetails som deklareras i Car klassen, och beskrivningen som visas beskriver en 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 skapar en lista över objekt som har typen Car. Objektens värden instansieras från klasserna Car, ConvertibleCaroch Minivan . DescribeCar anropas på varje element i listan. Följande kod visar definitionen av 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("----------");  
    }  
}  

Följande utdata visas. Observera att det är samma som utdata som visas av TestCars1. Metoden ShowDetails för ConvertibleCar klassen anropas inte, oavsett om objektets typ är ConvertibleCar, som i TestCars1eller Car, som i TestCars2. Omvänt car3 anropar ShowDetails metoden från Minivan klassen i båda fallen, oavsett om den har typ Minivan eller 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.  
// ----------  

Metoder TestCars3 och TestCars4 slutför exemplet. Dessa metoder anropar ShowDetails direkt, först från objekt som deklarerats ha typ ConvertibleCar och Minivan (TestCars3), sedan från objekt som deklarerats ha typ Car (TestCars4). Följande kod definierar dessa två metoder.

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

Metoderna genererar följande utdata, vilket motsvarar resultatet från det första exemplet i det här avsnittet.

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

Följande kod visar hela projektet och dess utdata.

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

Se även