Виртуальные методы C# переопределяют возвращаемые аргументы типа и метода
Я хочу инициализировать виртуальный метод с точным именем в абстрактном классе.
И в классе, который является методом переопределения наследника таким, что я могу переопределить:
- возвращаемый тип базового метода
- аргументы метода
Чтобы показать вам, что я действительно хочу сделать, вот что:
abstract class A
{
public virtual void Func1() { }
}
class B : A
{
override string Func1(int a, int b)
{
return (a + b).ToString();
}
}
Я знаю, что C# требует использовать возвращаемый тип / args как в базовом классе, но, может быть, в этой ситуации есть какие-то подсказки с ключевым словом new
?
5 ответов:
Вы можете только
Я думаю,что в вашей ситуации вы либо захотите создать перегрузки для всех возможных комбинаций, либо создадите один базовый абстрактный метод, который принимает один тип, который может содержать аргументы, которые вы хотите.override
точное имя и аргументы. Вы можетеnew
все, что хотите, но это не переопределение-просто скрытие в случае точного совпадения.Пример:
public abstract void Func1( MyArgumentsType input );
Теперь производные классы вынуждены переопределять метод, но вы можете передать надежный набор аргументов к методу, который может обрабатывать больше сценариев.
Здесь полиморфизм работает в вашу пользу, так как вы можете передать производные типы аргументов методу с ситуационными свойствами. Конечно, это требует, чтобы метод реализации понимал более производный тип аргумента.
Переопределение метода
Означает изменение виртуальнойреализации наследуемого члена, а не егосигнатуры . Как вы указали, ключевое слово
new
скроет реализацию базового класса члена с тем же именем. Однако это только необязательно, взгляните на это
преимущество использования нового ключевого слова в производном члене класса, имеющем то же имя, что и член базового класса
Похоже, что вы хотите добиться поведения, аналогичного методу
ToString
, который имеет много разных вкусов для разных типов (например,.ToString()
иfloat.ToString("c")
).В этом случае различные реализации
Обратите внимание, что в C# тип результата больше учитывается во времени разрешения функции, поэтому вы не можете действительно иметь 2 функции с одинаковым именем и одинаковыми аргументами и ожидать, что одна из них будет "правильно" выбрана. Если оба видны одновременно, вы получите ошибку времени компиляции. Ключевое словоToString
не являются реализациямиObject.ToString
, а скорее обычным дополнительным методом на производных объектах, которые разрешаются соответствующим образом на основе аргументов. Все производные классы заканчиваются одним виртуальным методомToString
(исходящим из базового класса и потенциально реализуемым в текущем классе) и необязательно другим аналогично именованные методы, которые не являются виртуальными.new
Перед методом делает видимым только этот метод для этого класса (и производных от него) и скрывает метод базового класса с той же сигнатурой. К сожалению делаю это в значительной степени гарантирует большую путаницу, когда для вызова этого метода используется переменная базового класса, содержащая производный класс - виртуальный из базового класса будет вызван, несмотря на все усилия скрыть его.
Твой Кант так бы и сделал. Переопределение метода требует наличия точно такой же сигнатуры, которая включает параметры и тип возвращаемого значения. Вы не можете попросить компилятор переопределить метод с различными параметрами и типом возвращаемого значения.
Если вы хотите полиморфное поведение, вам нужно иметь совместимые сигнатуры. В противном случае компилятор не может гарантировать, что искомый метод будет найден полиморфно.
Нет никакого приемлемого способа рассматривать сигнатуры
void Func1()
иstring Func1(int a, int b)
Как полиморфный. Вы можете обобщить их с помощью параметровout
лямбд внутри, но в любом случае-чтобы воспользоваться полиморфным поведением, вам нужно привести их к одной общей сигнатуре.
Думаю об этом...как это будет работать? Допустим, у вас есть ссылка, статический тип которой
A
, а динамический тип -B
, следующим образом:Идея переопределения заключается в том, что вы вызываете метод на super/base, и он разрешается в переопределенную реализацию. По этой логике вы должны быть в состоянии, вfoo(B b) { bar(b); } bar(A a) { }
bar
, вызватьa.Func1()
и он должен вызвать метод вB
:a.Func1(???)
Но здесь это невозможно из-за отсутствия параметров.
Существуют понятия параметр contravariance и возвращаемый тип ковариации; здесь - интересный ответ в SO, со ссылкой на сообщение Эрика Липперта, которое должно быть интересным чтением.