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 override
utö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
, dc
och bcdc
.
bc
är av typenBaseClass
och dess värde är av typenBaseClass
.dc
är av typenDerivedClass
och dess värde är av typenDerivedClass
.bcdc
är av typenBaseClass
och dess värde är av typenDerivedClass
. Det här är variabeln att vara uppmärksam på.
Eftersom bc
och bcdc
har typen BaseClass
kan de bara komma åt Method1
direkt , 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 new
Method2
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 new
kö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 BaseClass
i , 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 new
bekrä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 override
lä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 ConvertibleCar
Minivan
. 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
, ConvertibleCar
och 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 TestCars1
eller 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.");
}
}
}