Шаблон, который вы реализуете, называется двойная виртуальная отправка .
A одиночная виртуальная отправка выбирает, какой метод вызывать на основе типа времени выполнения получателя и типа времени компиляции аргументов , Это традиционная виртуальная рассылка:
abstract class Animal {}
class Tiger : Animal {}
class Giraffe : Animal {}
class B
{
public virtual void M(Tiger x) {}
public virtual void M(Animal x) {}
}
class D : B
{
public override void M(Tiger x) {}
public override void M(Animal x) {}
}
...
B b = whatever;
Animal a = new Tiger();
b.M(a);
Какой метод вызывается? B.M(Tiger)
и D.M(Tiger)
не выбраны; мы отклоняем их, основываясь на типе аргумента время компиляции , то есть Animal. Но мы выбираем, вызывать ли B.M(Animal)
или D.M(Animal)
во время выполнения, в зависимости от того, whatever
равен new B()
или new D()
.
Двойная виртуальная диспетчеризация выбирает метод для вызова на основе типов времени выполнения двух вещей . Если C # поддерживает двойную виртуальную диспетчеризацию, чего не происходит, тогда диспетчеризация во время выполнения переходит к B.M(Tiger)
или D.M(Tiger)
, даже если тип аргумента во время компиляции - Animal .
Однако
C # 4 поддерживает динамическую диспетчеризацию. Если вы скажете
dynamic b = whatever;
dynamic a = new Tiger();
b.M(a);
Тогда анализ M будет выполнен полностью во время выполнения с использованием типов времени выполнения b
и a
. Это значительно медленнее, но работает.
В качестве альтернативы, если вы хотите сделать двойную виртуальную диспетчеризацию и получить как можно больше анализа во время компиляции, тогда стандартным способом для этого является реализация Visitor Pattern , который вы можете легко найти в интернете.