Это связано с разрешением перегруженных методов.
Фактически (несколько упрощенно), компилятор сначала просматривает объявленный тип выражения (B) в этом случае и ищет подходящие методы , которые сначала объявлены в этом типе . Если есть какие-либо подходящие методы (то есть, где все аргументы могут быть преобразованы в типы параметров метода), тогда он не смотрит на родительские типы. Это означает, что переопределенные методы, в которых начальное объявление относится к родительскому типу, не проверяются, если в производном типе есть какие-либо «недавно объявленные» соответствующие методы.
Вот немного более простой пример:
using System;
class Base
{
public virtual void Foo(int x)
{
Console.WriteLine("Base.Foo(int)");
}
}
class Derived : Base
{
public override void Foo(int x)
{
Console.WriteLine("Derived.Foo(int)");
}
public void Foo(double d)
{
Console.WriteLine("Derived.Foo(double)");
}
}
class Test
{
static void Main()
{
Derived d = new Derived();
d.Foo(10);
}
}
Это печатает Derived.Foo(double)
- даже если компилятор знает, что существует метод сопоставления с параметром типа int
, и аргумент имеет тип int
, и преобразование из int
в int
равно " лучше, чем преобразование из int
в double
, тот факт, что только метод Foo(double)
изначально объявлен в Derived
, означает, что компилятор игнорирует Foo(int)
.
Это очень удивительно, ИМО. Я понимаю, почему так будет, если Derived
не переопределит Foo
- иначе введение нового, более конкретного метода в базовый класс может неожиданно изменить поведение - но ясно, что Derived
здесь знает о Base.Foo(int)
, поскольку это переопределяет его. Это один из (относительно немногих) моментов, когда я считаю, что разработчики C # приняли неверное решение.