Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
В C#метод в производном классе может иметь то же имя, что и метод в базовом классе. Вы можете указать, как методы взаимодействуют с помощью новых и переопределения ключевых слов. Модификатор override
расширяет метод базового класса virtual
, а new
модификатор скрывает доступный метод базового класса. Разница показана в примерах в этом разделе.
В консольном приложении объявите следующие два класса BaseClass
и DerivedClass
.
DerivedClass
наследует от BaseClass
.
class BaseClass
{
public void Method1()
{
Console.WriteLine("Base - Method1");
}
}
class DerivedClass : BaseClass
{
public void Method2()
{
Console.WriteLine("Derived - Method2");
}
}
В методе объявите переменные Main
, bc
, dc
и bcdc
.
bc
имеет типBaseClass
, и его значение имеет типBaseClass
.dc
имеет типDerivedClass
, и его значение имеет типDerivedClass
.bcdc
имеет типBaseClass
, и его значение имеет типDerivedClass
. Это переменная, на которые следует обратить внимание.
Так как bc
и bcdc
имеют тип BaseClass
, они могут обращаться к Method1
напрямую только в том случае, если вы не используете приведение. Переменная dc
может получить доступ к обоим Method1
и Method2
. Эти связи показаны в следующем коде.
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
}
Затем добавьте следующий Method2
метод в BaseClass
. Сигнатура этого метода соответствует сигнатуре Method2
метода в DerivedClass
.
public void Method2()
{
Console.WriteLine("Base - Method2");
}
Так как BaseClass
теперь имеет Method2
метод, можно добавить вторую вызывающую инструкцию для переменных BaseClass
bc
и bcdc
, как показано в следующем коде.
bc.Method1();
bc.Method2();
dc.Method1();
dc.Method2();
bcdc.Method1();
bcdc.Method2();
При сборке проекта вы увидите, что добавление метода в Method2
в BaseClass
вызывает предупреждение. Предупреждение говорит, что метод Method2
в DerivedClass
скрывает метод Method2
в BaseClass
. Рекомендуется использовать ключевое new
слово в Method2
определении, если вы планируете вызвать этот результат. Кроме того, можно переименовать один из Method2
методов разрешения предупреждения, но это не всегда практически.
Перед добавлением new
запустите программу, чтобы просмотреть результаты, созданные дополнительными вызовами. Отображаются следующие результаты.
// Output:
// Base - Method1
// Base - Method2
// Base - Method1
// Derived - Method2
// Base - Method1
// Base - Method2
Ключевое слово new
сохраняет связи, которые создают этот результат, но оно подавляет предупреждение. Переменные, имеющие тип BaseClass
, продолжают получать доступ к членам BaseClass
, и переменная, которая имеет тип DerivedClass
, в первую очередь продолжает получать доступ к членам в DerivedClass
, а затем рассматривает элементы, унаследованные от BaseClass
.
Чтобы отключить предупреждение, добавьте модификатор new
в определение Method2
в DerivedClass
, как показано в следующем коде. Модификатор можно добавить до или после public
.
public new void Method2()
{
Console.WriteLine("Derived - Method2");
}
Запустите программу еще раз, чтобы убедиться, что выходные данные не изменились. Кроме того, убедитесь, что предупреждение больше не отображается. При использовании new
вы утверждаете, что вы знаете, что элемент, который он изменяет, скрывает элемент, унаследованный от базового класса. Для получения более подробной информации о скрытии имен через наследование см. New Modifier.
Чтобы сравнить это поведение с последствиями использования override
, добавьте следующий метод в DerivedClass
.
override
Модификатор можно добавить до или послеpublic
.
public override void Method1()
{
Console.WriteLine("Derived - Method1");
}
Добавьте модификатор virtual
к определению Method1
в BaseClass
.
virtual
Модификатор можно добавить до или послеpublic
.
public virtual void Method1()
{
Console.WriteLine("Base - Method1");
}
Снова запустите проект. Обратите внимание на последние две строки следующих выходных данных.
// Output:
// Base - Method1
// Base - Method2
// Derived - Method1
// Derived - Method2
// Derived - Method1
// Base - Method2
Использование override
модификатора позволяет bcdc
получить доступ к Method1
методу, определенному в DerivedClass
. Как правило, это требуемое поведение в иерархиях наследования. Необходимо, чтобы объекты, имеющие значения, созданные из производного класса, использовали методы, определенные в производном классе. Чтобы достичь этого поведения, используйте override
, чтобы расширить метод базового класса.
Следующий код содержит полный пример.
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");
}
}
}
В следующем примере показано аналогичное поведение в другом контексте. В примере определяются три класса: базовый класс с именем Car
и двумя классами, производными от него, ConvertibleCar
и Minivan
. Базовый DescribeCar
класс содержит метод. В методе отображается базовое описание автомобиля, а затем вызывается ShowDetails
для предоставления дополнительных сведений. Каждый из трех классов определяет ShowDetails
метод.
new
Модификатор используется для определения ShowDetails
в ConvertibleCar
классе.
override
Модификатор используется для определения ShowDetails
в Minivan
классе.
// 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.");
}
}
В примере проверяется, какая версия ShowDetails
вызывается. Следующий метод TestCars1
создаёт экземпляр каждого класса, а затем вызывает DescribeCar
для каждого экземпляра.
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
создает следующие выходные данные. Особенно обратите внимание на результаты для car2
, которые, вероятно, не такие, как вы ожидали. Тип объекта — ConvertibleCar
, но DescribeCar
не обращается к версии ShowDetails
, определенной в классе ConvertibleCar
, так как этот метод объявлен с модификатором new
, а не с модификатором override
. В результате объект ConvertibleCar
отображает то же описание, что и объект Car
. Сравните результаты для car3
, который является объектом Minivan
. В этом случае метод ShowDetails
, объявленный в классе Minivan
, переопределяет метод ShowDetails
, объявленный в классе Car
, и отображаемое описание минивэна.
// TestCars1
// ----------
// Four wheels and an engine.
// Standard transportation.
// ----------
// Four wheels and an engine.
// Standard transportation.
// ----------
// Four wheels and an engine.
// Carries seven people.
// ----------
TestCars2
создает список объектов с типом Car
. Значения объектов создаются экземплярами классов Car
, ConvertibleCar
и Minivan
.
DescribeCar
вызывается для каждого элемента списка. В следующем коде показано определение 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("----------");
}
}
Отображаются следующие выходные данные. Обратите внимание, что оно совпадает с выходными данными, отображаемыми TestCars1
.
ShowDetails
метод класса ConvertibleCar
не вызывается, независимо от того, является ли тип объекта ConvertibleCar
, как в TestCars1
, или Car
, как в TestCars2
. И наоборот, car3
вызывает метод ShowDetails
из класса Minivan
в обоих случаях, независимо от типа Minivan
или типа Car
.
// TestCars2
// ----------
// Four wheels and an engine.
// Standard transportation.
// ----------
// Four wheels and an engine.
// Standard transportation.
// ----------
// Four wheels and an engine.
// Carries seven people.
// ----------
Методы TestCars3
и TestCars4
завершают пример. Эти методы вызывают ShowDetails
непосредственно из объектов, объявленных типом ConvertibleCar
и Minivan
(TestCars3
), а затем из объектов, объявленных типом Car
(TestCars4
). Следующий код определяет эти два метода.
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();
}
Методы создают следующие выходные данные, соответствующие результатам первого примера в этом разделе.
// TestCars3
// ----------
// A roof that opens up.
// Carries seven people.
// TestCars4
// ----------
// Standard transportation.
// Carries seven people.
В следующем коде показан полный проект и его выходные данные.
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.");
}
}
}