C # design: почему new / override требуется для абстрактных методов, но не для виртуальных методов? - PullRequest
13 голосов
/ 03 сентября 2010

Почему для абстрактных методов требуется новое / переопределение, а не для виртуальных методов?

Пример 1:

abstract class ShapesClass
{
    abstract public int Area(); // abstract!
}

class Square : ShapesClass
{
    int x, y;

    public int Area() // Error: missing 'override' or 'new'
    {
        return x * y;
    }
}

Компилятор отобразит эту ошибку: Для создания текущегопереопределите эту реализацию, добавьте ключевое слово override.В противном случае добавьте новое ключевое слово

Пример 2:

class ShapesClass
{
    virtual public int Area() { return 0; } // it is virtual now!
}

class Square : ShapesClass
{
    int x, y;

    public int Area() // no explicit 'override' or 'new' required
    {
        return x * y;
    }
}

Это скомпилирует нормально, скрыв метод по умолчанию.

Я полностью понимаю технические различия,Однако мне интересно, почему язык был разработан таким образом.Не лучше ли иметь такое же ограничение и в «Образце 2»?Я имею в виду, что в большинстве случаев, если вы создаете метод с тем же именем, что и в родительском классе, вы обычно намерены переопределить его.Поэтому я думаю, что явное указание Override / New будет иметь смысл и для виртуальных методов.

Есть ли конструктивная причина для такого поведения?

Обновление: Второеобразец на самом деле вызывает предупреждение.В первом примере показана ошибка, поскольку подкласс необходим для реализации абстрактного метода.Я не видел предупреждение в VS .. теперь имеет смысл для меня.Спасибо.

Ответы [ 5 ]

11 голосов
/ 03 сентября 2010

Используя компилятор C # 3.0, поставляемый в .NET 3.5 SP1, или компилятор C # 4.0, поставляемый в .NET 4.0, я получаю следующую ошибку для вашего первого примера:

ошибка CS0534: «ConsoleApplication3.Square» не реализует унаследованный абстрактный член «ConsoleApplication3.ShapesClass.Area ()»

И следующее предупреждение для второго:

предупреждение CS0114: «ConsoleApplication3.Square.Area ()» скрывает унаследованный член «ConsoleApplication3.ShapesClass.Area ()». Чтобы текущий член переопределил эту реализацию, добавьте ключевое слово override. В противном случае добавьте новое ключевое слово.

В первом случае это ошибка, потому что вы на самом деле не переопределяете базовый метод, что означает, что в конкретном классе нет реализации абстрактного метода. Во втором случае это предупреждение, потому что код технически корректен, но компилятор подозревает, что это не то, что вы имели в виду. Это одна из причин, по которой обычно рекомендуется включить параметр компиляции «рассматривать предупреждения как ошибки».

Так что я не могу воспроизвести ваше поведение, и поведение компилятора выглядит мне правильным. Какую версию компилятора вы используете?

7 голосов
/ 03 сентября 2010

Вот ответ прямо из спецификации C #.

... скрытие доступного имени от унаследованная область действия вызывает предупреждение сообщили. В примере

class Base
{
    public void F() {}
}
class Derived: Base
{
    public void F() {}      // Warning, hiding an inherited name
}

объявление F в производных причинах предупреждение будет сообщено. Сокрытие унаследованное имя конкретно не ошибка, так как это исключает отдельная эволюция базовых классов. Например, приведенная выше ситуация может произошло потому, что позже версия Base представила метод F который не был представлен ранее версия класса. Если бы выше ситуация была ошибкой, то любая изменение, внесенное в базовый класс в отдельно версия библиотеки классов потенциально может вызвать производное классы становятся недействительными. Предупреждение вызванный сокрытием унаследованного имени может быть устранены с помощью нового Модификатор:

class Base
{
    public void F() {}
}
class Derived: Base
{
    new public void F() {}
}

Новый модификатор указывает, что F в производном является «новым», и что это действительно предназначен, чтобы скрыть наследственное член.

3 голосов
/ 03 сентября 2010

Разница в том, что абстрактный метод должен быть переопределен, а виртуальный - нет.

Ошибка наследовать абстрактный класс (в неабстрактном классе) без реализации всех абстрактных членов,но вы получаете предупреждение только при наследовании от класса без указания override или new для виртуального метода.

0 голосов
/ 13 марта 2014

Versioning

На первый взгляд, вы можете подумать, что скрытие методов не кажется особенно полезным.Однако может возникнуть необходимость использовать его.Допустим, вы хотите использовать класс с именем MotorVehicle, который был написан другим программистом, и вы хотите использовать этот класс для создания своего собственного класса.Далее, давайте также предположим, что вы хотите определить метод Accelerate() в своем производном классе.Например:

public class Car : MotorVehicle
{
    // define the Accelerate() method
    public void Accelerate()
    {
        Console.WriteLine(“In Car Accelerate() method”);
        Console.WriteLine(model + “ accelerating”);
    }
}

Далее, давайте предположим, что другой программист позже модифицирует класс MotorVehicle и решит добавить свой собственный метод virtual Accelerate():

public class MotorVehicle
{
    // define the Accelerate() method
    public virtual void Accelerate()
    {
        Console.WriteLine(“In MotorVehicle Accelerate() method”);
        Console.WriteLine(model + “ accelerating”);
    }
}

Добавление этого *Метод 1012 * другого программиста вызывает проблему: метод Accelerate() в вашем классе Car скрывает унаследованный метод Accelerate(), теперь определенный в их классе MotorVehicle.Позже, когда вы придете к компиляции вашего Car класса, компилятору не ясно, действительно ли вы намеревались использовать свой метод, чтобы скрыть унаследованный метод.Из-за этого компилятор сообщает следующее предупреждение при попытке скомпилировать класс Car:

warning CS0114: 'Car.Accelerate ()' скрывает унаследованный член MotorVehicle.Accelerate () '.Чтобы текущий член переопределил эту реализацию, добавьте ключевое слово override.В противном случае добавьте новое ключевое слово.

0 голосов
/ 03 сентября 2010

Я думаю, что в первом случае вы получите ошибку компилятора, потому что абстрактный метод скрыт и не реализован (поэтому ваш класс ошибочен, и было бы трудно понять, почему).Во втором случае вы получите только предупреждение, потому что класс можно использовать.

...