Użycie przesłonięć i nowych słów kluczowych (Przewodnik programowania w języku C#)
W języku C# metoda w klasie pochodnej może mieć taką samą nazwę jak metoda w klasie bazowej. Możesz określić sposób interakcji metod przy użyciu nowych słów kluczowych i przesłaniania . override
Modyfikator rozszerza metodę klasy virtual
bazowej, a new
modyfikator ukrywa dostępną metodę klasy bazowej. Różnica jest pokazana w przykładach w tym temacie.
W aplikacji konsolowej zadeklaruj następujące dwie klasy i BaseClass
DerivedClass
. DerivedClass
dziedziczy z BaseClass
.
class BaseClass
{
public void Method1()
{
Console.WriteLine("Base - Method1");
}
}
class DerivedClass : BaseClass
{
public void Method2()
{
Console.WriteLine("Derived - Method2");
}
}
W metodzie zadeklaruj Main
zmienne bc
, dc
i bcdc
.
bc
jest typuBaseClass
, a jego wartość jest typuBaseClass
.dc
jest typuDerivedClass
, a jego wartość jest typuDerivedClass
.bcdc
jest typuBaseClass
, a jego wartość jest typuDerivedClass
. Jest to zmienna, na która należy zwrócić uwagę.
Ponieważ bc
i bcdc
mają typ BaseClass
, mogą uzyskiwać bezpośredni dostęp tylko do Method1
metody , chyba że używasz rzutu. Zmienna może uzyskiwać dostęp zarówno do zmiennej dc
, jak Method1
i Method2
. Te relacje są wyświetlane w poniższym kodzie.
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
}
Następnie dodaj następującą Method2
metodę do BaseClass
metody . Podpis tej metody jest zgodny z podpisem Method2
metody w pliku DerivedClass
.
public void Method2()
{
Console.WriteLine("Base - Method2");
}
Ponieważ BaseClass
teraz ma metodę, można dodać drugą instrukcję wywołującą Method2
dla BaseClass
zmiennych bc
i bcdc
, jak pokazano w poniższym kodzie.
bc.Method1();
bc.Method2();
dc.Method1();
dc.Method2();
bcdc.Method1();
bcdc.Method2();
Podczas kompilowania projektu zobaczysz, że dodanie Method2
metody w BaseClass
elemecie powoduje ostrzeżenie. Ostrzeżenie informuje, że metoda w elemecie Method2
ukrywa metodę Method2
w BaseClass
pliku .DerivedClass
Zaleca się użycie słowa kluczowego new
Method2
w definicji, jeśli zamierzasz spowodować ten wynik. Alternatywnie można zmienić nazwę jednej z Method2
metod, aby rozwiązać to ostrzeżenie, ale nie zawsze jest to praktyczne.
Przed dodaniem new
uruchom program , aby wyświetlić dane wyjściowe wygenerowane przez dodatkowe instrukcje wywołujące. Zostaną wyświetlone następujące wyniki.
// Output:
// Base - Method1
// Base - Method2
// Base - Method1
// Derived - Method2
// Base - Method1
// Base - Method2
Słowo new
kluczowe zachowuje relacje, które generują te dane wyjściowe, ale pomija ostrzeżenie. Zmienne, które mają typ BaseClass
, nadal uzyskują dostęp do elementów członkowskich BaseClass
, a zmienna, która ma typ DerivedClass
, nadal uzyskuje dostęp do elementów członkowskich w DerivedClass
pierwszej kolejności, a następnie należy wziąć pod uwagę elementy członkowskie dziedziczone z BaseClass
klasy .
Aby pominąć ostrzeżenie, dodaj new
modyfikator do definicji Method2
w DerivedClass
pliku , jak pokazano w poniższym kodzie. Modyfikator można dodać przed lub po public
.
public new void Method2()
{
Console.WriteLine("Derived - Method2");
}
Uruchom ponownie program, aby sprawdzić, czy dane wyjściowe nie uległy zmianie. Sprawdź również, czy ostrzeżenie nie jest już wyświetlane. Używając metody new
, stwierdzasz, że wiesz, że element członkowski, który modyfikuje, ukrywa element członkowski dziedziczony z klasy bazowej. Aby uzyskać więcej informacji na temat ukrywania nazwy przez dziedziczenie, zobacz nowy modyfikator.
Aby porównać to zachowanie z efektami używania metody override
, dodaj następującą metodę do DerivedClass
metody . override
Modyfikator można dodać przed lub po public
.
public override void Method1()
{
Console.WriteLine("Derived - Method1");
}
virtual
Dodaj modyfikator do definicji Method1
w pliku .BaseClass
virtual
Modyfikator można dodać przed lub po public
.
public virtual void Method1()
{
Console.WriteLine("Base - Method1");
}
Uruchom ponownie projekt. Zwróć szczególną uwagę na dwa ostatnie wiersze następujących danych wyjściowych.
// Output:
// Base - Method1
// Base - Method2
// Derived - Method1
// Derived - Method2
// Derived - Method1
// Base - Method2
Użycie override
modyfikatora umożliwia bcdc
dostęp do metody zdefiniowanej Method1
w pliku DerivedClass
. Zazwyczaj jest to pożądane zachowanie w hierarchiach dziedziczenia. Obiekty, które mają wartości utworzone na podstawie klasy pochodnej, mają używać metod zdefiniowanych w klasie pochodnej. To zachowanie można osiągnąć za pomocą polecenia override
w celu rozszerzenia metody klasy bazowej.
Poniższy kod zawiera pełny przykład.
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");
}
}
}
Poniższy przykład ilustruje podobne zachowanie w innym kontekście. W przykładzie zdefiniowano trzy klasy: klasę bazową o nazwie Car
i dwie klasy, które pochodzą z niej, ConvertibleCar
i Minivan
. Klasa bazowa zawiera metodę DescribeCar
. Metoda wyświetla podstawowy opis samochodu, a następnie wywołuje metodę ShowDetails
w celu podania dodatkowych informacji. Każda z trzech klas definiuje metodę ShowDetails
. Modyfikator new
służy do definiowania ShowDetails
w ConvertibleCar
klasie . Modyfikator override
służy do definiowania ShowDetails
w Minivan
klasie .
// 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.");
}
}
Przykład sprawdza, która wersja programu jest wywoływana ShowDetails
. Poniższa metoda TestCars1
deklaruje wystąpienie każdej klasy, a następnie wywołuje DescribeCar
każde wystąpienie.
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
generuje następujące dane wyjściowe. Zwróć szczególną uwagę na wyniki funkcji car2
, które prawdopodobnie nie są oczekiwane. Typ obiektu to ConvertibleCar
, ale DescribeCar
nie uzyskuje dostępu do wersji zdefiniowanej ShowDetails
ConvertibleCar
w klasie, ponieważ ta metoda jest zadeklarowana za pomocą new
modyfikatora, a nie override
modyfikatora. W związku ConvertibleCar
z tym obiekt wyświetla ten sam opis co Car
obiekt. Skontrastuj wyniki dla car3
elementu , który jest obiektem Minivan
. W tym przypadku ShowDetails
metoda zadeklarowana w Minivan
klasie zastępuje ShowDetails
metodę zadeklarowaną w Car
klasie, a wyświetlany opis opisuje 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
Tworzy listę obiektów, które mają typ Car
. Wartości obiektów są tworzone z Car
klas , ConvertibleCar
i Minivan
. DescribeCar
element jest wywoływany dla każdego elementu listy. Poniższy kod przedstawia definicję elementu 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("----------");
}
}
Zostaną wyświetlone następujące dane wyjściowe. Zwróć uwagę, że jest on taki sam jak dane wyjściowe wyświetlane przez TestCars1
element . Metoda ShowDetails
klasy nie jest wywoływana, niezależnie od tego, czy typ obiektu to ConvertibleCar
, jak w , lub Car
, jak w TestCars1
TestCars2
.ConvertibleCar
car3
Z drugiej strony wywołuje metodę ShowDetails
z Minivan
klasy w obu przypadkach, niezależnie od tego, czy ma typMinivan
, czy 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
i TestCars4
uzupełnij przykład. Metody te są wywoływane ShowDetails
bezpośrednio, najpierw z obiektów zadeklarowanych jako typ ConvertibleCar
i Minivan
(TestCars3
), a następnie z obiektów zadeklarowanych jako typ Car
(TestCars4
). Poniższy kod definiuje te dwie 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 generują następujące dane wyjściowe, które odpowiadają wynikam z pierwszego przykładu w tym temacie.
// TestCars3
// ----------
// A roof that opens up.
// Carries seven people.
// TestCars4
// ----------
// Standard transportation.
// Carries seven people.
Poniższy kod przedstawia kompletny projekt i jego dane wyjściowe.
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.");
}
}
}