Override and Method Selection



When a method is named on a class, the C# compiler selects the best method to call if more than one method is compatible with the call, such as when there are two methods with the same name, and parameters that are compatible with the parameter passed. The following methods would be compatible:

public class Derived : Base { public override void DoWork(int param) { } public void DoWork(double param) { } }

When DoWork is called on an instance of Derived, the C# compiler will first try to make the call compatible with the versions of DoWork declared originally on Derived. Override methods are not considered as declared on a class, they are new implementations of a method declared on a base class. Only if the C# compiler cannot match the method call to an original method on Derived will it try to match the call to an overridden method with the same name and compatible parameters. For example:

int val = 5; Derived d = new Derived(); d.DoWork(val); // Calls DoWork(double).

Because the variable val can be converted to a double implicitly, the C# compiler calls DoWork(double) instead of DoWork(int). There are two ways to avoid this. First, avoid declaring new methods with the same name as virtual methods. Second, you can instruct the C# compiler to call the virtual method by making it search the base class method list by casting the instance of Derived to Base. Because the method is virtual, the implementation of DoWork(int) on Derived will be called. For example:

((Base)d).DoWork(val); // Calls DoWork(int) on Derived.

 


Переопределение и выбор метода[29]

При вызове метода класса компилятор C# выбирает наилучший из методов, совместимых с вызовом (например, если имеются два метода с одинаковыми именами), и параметров, которые совместимы с переданным параметром. Следующие методы будут совместимы:

public class Derived : Base { public override void DoWork(int param) { } public void DoWork(double param) { } }

Если выполняется вызов DoWork из экземпляра Derived, компилятор C# сначала попытается обеспечить совместимость вызова с версиями DoWork, первоначально объявленными в Derived. Переназначенные методы не рассматриваются как объявленные в классе. Они являются новыми реализациями метода, объявленного в базовом классе. Только в том случае, если компилятор C# не смог сопоставить вызов метода с исходным методом в классе Derived, он попытается сопоставить вызов с переназначенным методом с тем же именем и совместимыми параметрами. Пример.

int val = 5; Derived d = new Derived(); d.DoWork(val); // Calls DoWork(double).

Поскольку переменную val можно неявно преобразовать в тип "double", компилятор C# вызовет DoWork(double) вместо DoWork(int). Чтобы избежать этого, существует два способа. Во-первых, избегайте объявления новых методов с одинаковыми именами в качестве виртуальных. Во-вторых, можно сделать так, чтобы компилятор C# вызвал виртуальный метод, заставив его выполнить поиск в списке методов базового класса за счет приведения экземпляра Derived к Base. Поскольку метод является виртуальным, будет вызвана реализация DoWork(int) в классе Derived. Пример.

((Base)d).DoWork(val); // Calls DoWork(int) on Derived.

 


Knowing When to Use Override and New Keywords

C# enables methods in derived classes to have the same name as methods in base classes—as long as you are very specific about how the new method should be treated. The following example demonstrates the use of the new and override keywords.

First we declare three classes: a base class called Car, and two classes that derive from it, ConvertibleCar and Minivan. The base class contains a single method, DescribeCar, which sends a description of the car to the console. The derived class methods also include a method called DescribeCar, which displays their unique properties. These methods also call the base class DescribeCar method to demonstrate how they have inherited the properties of the Car class.

In order to highlight the difference, the ConvertibleCar class is defined with the new keyword, while the Minivan class is defined with override.

// Define the base class class Car { public virtual void DescribeCar() {    System.Console.WriteLine("Four wheels and an engine."); } } // Define the derived classes class ConvertibleCar : Car { public new virtual void DescribeCar() {    base.DescribeCar();    System.Console.WriteLine("A roof that opens up."); } } class Minivan : Car { public override void DescribeCar() {    base.DescribeCar();    System.Console.WriteLine("Carries seven people."); } }

 


Использование ключевых слов "Override" и "New"

В C# методы в производных классах могут иметь такие же имена, как и методы в базовых классах (если четко соблюдаются различия в использовании новых методов). В следующем примере демонстрируется использование ключевых слов new и override.

Сначала объявим три класса: базовый класс Car и два класса, производных от него: ConvertibleCar и Minivan. Базовый класс содержит один метод с именем DescribeCar, отправляющий описание автомобиля на консоль. Методы производных классов также включают метод с именем DescribeCar, отображающий уникальные свойства этих классов. Эти методы также вызывают базовый класс DescribeCar, чтобы продемонстрировать, каким образом они унаследовали свойства класса Car.

Чтобы подчеркнуть разницу, класс ConvertibleCar определен с ключевым словом new, а класс Minivan — с ключевым словом override.

ß-----


We can now write some code that declares instances of these classes, and calls their methods so that the objects can describe themselves:

public static void TestCars1() { Car car1 = new Car(); car1.DescribeCar(); System.Console.WriteLine("----------");   ConvertibleCar car2 = new ConvertibleCar(); car2.DescribeCar(); System.Console.WriteLine("----------");   Minivan car3 = new Minivan(); car3.DescribeCar(); System.Console.WriteLine("----------"); }

As you might expect, the output looks like this:

Four wheels and an engine.

----------

Four wheels and an engine.

A roof that opens up.

----------

Four wheels and an engine.

Carries seven people.

----------

 


Теперь можно написать код, описывающий экземпляры этих классов и вызовы методов, чтобы объекты могли себя описывать:[30]

ß---

 

Как и предполагалось, результат выглядит следующим образом:

Four wheels and an engine.

----------

Four wheels and an engine.

A roof that opens up.

----------

Four wheels and an engine.

Carries seven people.

----------

 


However, in this next section of code, we declare an array of objects derived from the Car base class. This array can store Car, ConvertibleCar, and Minivan objects. The array is declared like this:

public static void TestCars2() { Car[] cars = new Car[3]; cars[0] = new Car(); cars[1] = new ConvertibleCar(); cars[2] = new Minivan(); }

We can then use a foreach loop to visit each Car object contained in the array, and call the DescribeCar method, like this:

foreach (Car vehicle in cars) { System.Console.WriteLine("Car object: " + vehicle.GetType()); vehicle.DescribeCar(); System.Console.WriteLine("----------"); }

The output from this loop is as follows:

Car object: YourApplication.Car

Four wheels and an engine.

----------

Car object: YourApplication.ConvertibleCar

Four wheels and an engine.

----------

Car object: YourApplication.Minivan

Four wheels and an engine.

Carries seven people.

----------

Notice how the ConvertibleCar description is not what you might expect. As the new keyword was used to define this method, the derived class method is not called—the base class method is called instead. The Minivan object correctly calls the overridden method, producing the results we expected.

If you want to enforce a rule that all classes derived from Car must implement the DescribeCar method, you should create a new base class that defines the method DescribeCar as abstract. An abstract method does not contain any code, only the method signature. Any classes derived from this base class must provide an implementation of DescribeCar.

 


Однако в следующем фрагменте кода мы объявляем массив объектов, производных от класса Car. В этом массиве могут храниться объекты Car, ConvertibleCar и Minivan. Массив объявляется следующим образом:

public static void TestCars2() { Car[] cars = new Car[3]; cars[0] = new Car(); cars[1] = new ConvertibleCar(); cars[2] = new Minivan(); }

Затем можно использовать цикл foreach для посещения каждого объекта Car в машине и вызова метода DescribeCar:

foreach (Car vehicle in cars) { System.Console.WriteLine("Car object: " + vehicle.GetType()); vehicle.DescribeCar(); System.Console.WriteLine("----------"); }

Результат выполнения этого цикла выглядит следующим образом:[31]

Car object: YourApplication.Car

Four wheels and an engine.

----------

Car object: YourApplication.ConvertibleCar

Four wheels and an engine.

----------

Car object: YourApplication.Minivan

Four wheels and an engine.

Carries seven people.

----------

Обратите внимание, что описание ConvertibleCar не такое, как ожидалось. Поскольку ключевое слово new было использовано для определения этого метода, метод производного класса не вызван, вместо него вызван метод базового класса[32]. Объект Minivan правильно вызывает переопределенный метод и выдает ожидаемый результат.

Чтобы принудительно выполнялось правило, согласно которому все классы, производные от Car, должны реализовать метод DescribeCar, нужно создать новый базовый класс, определяющий метод DescribeCar как abstract. Абстрактный метод содержит только подпись метода и не содержит никакого кода. Любые классы, производные от этого базового класса, должны предоставлять реализацию DescribeCar. Дополнительные сведения см. в разделе abstract.

 


Дата добавления: 2019-03-09; просмотров: 231; Мы поможем в написании вашей работы!

Поделиться с друзьями:






Мы поможем в написании ваших работ!