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
, dc
a bcdc
.
bc
je typuBaseClass
a jeho hodnota je typuBaseClass
.dc
je typuDerivedClass
a jeho hodnota je typuDerivedClass
.bcdc
je typuBaseClass
a jeho hodnota je typuDerivedClass
. 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 BaseClass
souboru . 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 new
spusť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 BaseClass
a 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í , new
tvrdí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 , TestCars1
deklaruje 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 , car3
což 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
, ConvertibleCar
a 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 ShowDetails
ConvertibleCar
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 ShowDetails
Minivan
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.");
}
}
}