Использование ключевых слов "Override" и "New" (Руководство по программированию в C#)Knowing When to Use Override and New Keywords (C# Programming Guide)

В C# метод в производном классе может иметь то же имя, что и метод в базовом классе.In C#, a method in a derived class can have the same name as a method in the base class. Можно задать способ взаимодействия методов, воспользовавшись ключевыми словами new и override.You can specify how the methods interact by using the new and override keywords. Модификатор override расширяет метод virtual базового класса, а модификатор new скрывает доступный метод базового класса.The override modifier extends the base class virtual method, and the new modifier hides an accessible base class method. Эта разница показана в примере в этой статье.The difference is illustrated in the examples in this topic.

В консольном приложении объявите два класса — BaseClass и DerivedClass.In a console application, declare the following two classes, BaseClass and DerivedClass. ТипDerivedClass наследуется от типа BaseClass.DerivedClass inherits from BaseClass.

class BaseClass  
{  
    public void Method1()  
    {  
        Console.WriteLine("Base - Method1");  
    }  
}  
  
class DerivedClass : BaseClass  
{  
    public void Method2()  
    {  
        Console.WriteLine("Derived - Method2");  
    }  
}  

В методе Main объявите переменные bc, dc и bcdc.In the Main method, declare variables bc, dc, and bcdc.

  • Параметр bc имеет тип BaseClass и его значение — тип BaseClass.bc is of type BaseClass, and its value is of type BaseClass.

  • Параметр dc имеет тип DerivedClass и его значение — тип DerivedClass.dc is of type DerivedClass, and its value is of type DerivedClass.

  • Параметр bcdc имеет тип BaseClass и его значение — тип DerivedClass.bcdc is of type BaseClass, and its value is of type DerivedClass. Это переменная, на которую следует обратить внимание.This is the variable to pay attention to.

Поскольку bc и bcdc имеют тип BaseClass, они могут только напрямую обращаться к методу Method1 (если не используется приведение).Because bc and bcdc have type BaseClass, they can only directly access Method1, unless you use casting. Переменная dc может обращаться к Method1 и Method2.Variable dc can access both Method1 and Method2. Эти связи показаны в следующем коде.These relationships are shown in the following code.

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.Next, add the following Method2 method to BaseClass. Сигнатура этого метода соответствует сигнатуре метода Method2 в DerivedClass.The signature of this method matches the signature of the Method2 method in DerivedClass.

public void Method2()  
{  
    Console.WriteLine("Base - Method2");  
}  

Поскольку BaseClass теперь имеет метод Method2, можно добавить второй оператор вызова для переменных bc и bcdc класса BaseClass, как показано в следующем коде.Because BaseClass now has a Method2 method, a second calling statement can be added for BaseClass variables bc and bcdc, as shown in the following code.

bc.Method1();  
bc.Method2();  
dc.Method1();  
dc.Method2();  
bcdc.Method1();  
bcdc.Method2();  

При построении проекта видно, что добавление метода Method2 в BaseClass вызывает предупреждение.When you build the project, you see that the addition of the Method2 method in BaseClass causes a warning. Предупреждение говорит, что метод Method2 в DerivedClass скрывает метод Method2 в BaseClass.The warning says that the Method2 method in DerivedClass hides the Method2 method in BaseClass. Рекомендуется использовать ключевое слово new в определении Method2, если требуется получить такой результат.You are advised to use the new keyword in the Method2 definition if you intend to cause that result. Другой вариант — переименовать один из методов Method2 для разрешения предупреждения, но это не всегда целесообразно.Alternatively, you could rename one of the Method2 methods to resolve the warning, but that is not always practical.

Прежде чем добавлять new, запустите программу, чтобы увидеть выходные данные дополнительных операторов вызова.Before adding new, run the program to see the output produced by the additional calling statements. Отобразятся следующие результаты.The following results are displayed.

// Output:  
// Base - Method1  
// Base - Method2  
// Base - Method1  
// Derived - Method2  
// Base - Method1  
// Base - Method2  

Ключевое слово new сохраняет связи, дающие этот результат, однако подавляет предупреждение.The new keyword preserves the relationships that produce that output, but it suppresses the warning. Переменные, имеющие тип BaseClass, продолжают обращаться к элементам класса BaseClass, а переменная, имеющая тип DerivedClass, продолжает обращаться к элементам класса DerivedClass в первую очередь, а затем к элементам, унаследованным от BaseClass.The variables that have type BaseClass continue to access the members of BaseClass, and the variable that has type DerivedClass continues to access members in DerivedClass first, and then to consider members inherited from BaseClass.

Чтобы подавить предупреждение, добавьте модификатор new в определение Method2 в классе DerivedClass, как показано в следующем коде.To suppress the warning, add the new modifier to the definition of Method2 in DerivedClass, as shown in the following code. Модификатор можно добавить перед или после public.The modifier can be added before or after public.

public new void Method2()  
{  
    Console.WriteLine("Derived - Method2");  
}  

Запустите программу еще раз, чтобы убедиться, что выходные данные не изменились.Run the program again to verify that the output has not changed. Также убедитесь, что предупреждение больше не появляется.Also verify that the warning no longer appears. Используя ключевое слово new, вы утверждаете, что вам известно, что модифицируемый им член скрывается членом, который наследуется от базового класса.By using new, you are asserting that you are aware that the member that it modifies hides a member that is inherited from the base class. Дополнительные сведения о скрытии имен через наследование см. в разделе Модификатор new.For more information about name hiding through inheritance, see new Modifier.

Чтобы противопоставить это поведение эффекту использования override, добавьте в DerivedClass следующий метод.To contrast this behavior to the effects of using override, add the following method to DerivedClass. Модификатор override можно добавить перед или после public.The override modifier can be added before or after public.

public override void Method1()  
{  
    Console.WriteLine("Derived - Method1");  
}  

Добавьте модификатор virtual в определение Method1 в BaseClass.Add the virtual modifier to the definition of Method1 in BaseClass. Модификатор virtual можно добавить перед или после public.The virtual modifier can be added before or after public.

public virtual void Method1()  
{  
    Console.WriteLine("Base - Method1");  
}  

Снова запустите проект.Run the project again. Обратите особое внимание на последние две строки следующих выходных данных.Notice especially the last two lines of the following output.

// Output:  
// Base - Method1  
// Base - Method2  
// Derived - Method1  
// Derived - Method2  
// Derived - Method1  
// Base - Method2  

Использование модификатора override позволяет bcdc осуществлять доступ к методу Method1, который определен в DerivedClass.The use of the override modifier enables bcdc to access the Method1 method that is defined in DerivedClass. Как правило, это требуемое поведение в иерархиях наследования.Typically, that is the desired behavior in inheritance hierarchies. Требуется, чтобы объекты со значениями, созданными из производного класса, использовали определенные в производном классе методы.You want objects that have values that are created from the derived class to use the methods that are defined in the derived class. Это поведение достигается с использованием override для расширения метода базового класса.You achieve that behavior by using override to extend the base class method.

Следующий код содержит полный пример.The following code contains the full example.

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");  
        }  
    }  
}  

В следующем примере показано подобное поведение в другом контексте.The following example illustrates similar behavior in a different context. В примере определяются три класса: базовый класс Car и два класса, производных от него: ConvertibleCar и Minivan.The example defines three classes: a base class named Car and two classes that are derived from it, ConvertibleCar and Minivan. Базовый класс содержит метод DescribeCar.The base class contains a DescribeCar method. Этот метод отображает общее описание автомобиля, а затем вызывает ShowDetails для предоставления дополнительных сведений.The method displays a basic description of a car, and then calls ShowDetails to provide additional information. Каждый из трех классов определяет метод ShowDetails.Each of the three classes defines a ShowDetails method. Для определения метода ShowDetails в классе ConvertibleCar используется модификатор new.The new modifier is used to define ShowDetails in the ConvertibleCar class. Для определения метода ShowDetails в классе Minivan используется модификатор override.The override modifier is used to define ShowDetails in the Minivan class.

// 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.The example tests which version of ShowDetails is called. Следующий метод, TestCars1, объявляет экземпляр каждого класса, а затем вызывает DescribeCar на каждом экземпляре.The following method, TestCars1, declares an instance of each class, and then calls DescribeCar on each instance.

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 формирует следующие выходные данные.TestCars1 produces the following output. Обратите особое внимание на результаты для car2, который, вероятно, не соответствует ожидаемым.Notice especially the results for car2, which probably are not what you expected. Тип объекта — ConvertibleCar, но DescribeCar не получает доступа к версии ShowDetails, определенной в классе ConvertibleCar, так как этот метод объявлен с модификатором new, а не override.The type of the object is ConvertibleCar, but DescribeCar does not access the version of ShowDetails that is defined in the ConvertibleCar class because that method is declared with the new modifier, not the override modifier. В результате объект ConvertibleCar отображает то же описание, что и объект Car.As a result, a ConvertibleCar object displays the same description as a Car object. Сравните результаты для car3, который является объектом Minivan.Contrast the results for car3, which is a Minivan object. В этом случае метод ShowDetails, объявленный в классе Minivan, переопределяет метод ShowDetails, объявленный в классе Car, и отображается описание микроавтобуса.In this case, the ShowDetails method that is declared in the Minivan class overrides the ShowDetails method that is declared in the Car class, and the description that is displayed describes a 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 создает список объектов, имеющих тип Car.TestCars2 creates a list of objects that have type Car. Значения объектов создаются из классовCar, ConvertibleCar и Minivan.The values of the objects are instantiated from the Car, ConvertibleCar, and Minivan classes. DescribeCar вызывается для каждого элемента списка.DescribeCar is called on each element of the list. В следующем коде показано определение TestCars2.The following code shows the definition of 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("----------");  
    }  
}  

Выводится следующий результат.The following output is displayed. Обратите внимание, что он совпадает с выходными данными, отображаемыми TestCars1.Notice that it is the same as the output that is displayed by TestCars1. Метод ShowDetails класса ConvertibleCar не вызывается, независимо от того, является ли тип объекта ConvertibleCar, как в TestCars1, или Car, как в TestCars2.The ShowDetails method of the ConvertibleCar class is not called, regardless of whether the type of the object is ConvertibleCar, as in TestCars1, or Car, as in TestCars2. И наоборот, car3 вызывает метод ShowDetails класса Minivan в обоих случаях, независимо от того, какого они типа — Minivan или Car.Conversely, car3 calls the ShowDetails method from the Minivan class in both cases, whether it has type Minivan or type 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 завершают пример.Methods TestCars3 and TestCars4 complete the example. Эти методы вызывают ShowDetails напрямую: сначала из объектов, объявленных с типом ConvertibleCar и Minivan (TestCars3), а затем из объектов, объявленных с типом Car (TestCars4).These methods call ShowDetails directly, first from objects declared to have type ConvertibleCar and Minivan (TestCars3), then from objects declared to have type Car (TestCars4). Следующий код определяет эти два метода.The following code defines these two methods.

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();  
}  

Методы производят следующий результат, который соответствует результатам из первого примера в этой теме.The methods produce the following output, which corresponds to the results from the first example in this topic.

// TestCars3  
// ----------  
// A roof that opens up.  
// Carries seven people.  
  
// TestCars4  
// ----------  
// Standard transportation.  
// Carries seven people.  

В следующем коде приведен полный проект и его результат.The following code shows the complete project and its output.

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.");  
        }  
    }  
  
}  

См. такжеSee also