Он не вызывает Invoke
(обратите внимание на отсутствие ()
), он использует неявное создание делегата для установки b
равным новому derivedClassDelegate
экземпляру, который указывает на Invoke
метод a
. Дополнительная косвенность заключается в том, что когда вызывается b
, он вызывает a.Invoke(new Derived())
, а не просто a(new Derived())
.
Чтобы сделать то, что на самом деле происходит, более явным:
baseClassDelegate a = Foo1; // works fine
derivedClassDelegate b = Foo2; // works fine
b = new derivedClassDelegate(a.Invoke); // the easy way to assign delegate using variance, adds layer of indirection though
b(new Derived());
b = CastDelegate<derivedClassDelegate>(a); // the hard way, avoids indirection
b(new Derived());
Первый вызов b
приводит к такой цепочке (параметры для простоты исключены):
b() -> a.Invoke() -> Foo1()
Второй вызов b
приводит к этому:
b() -> Foo1()
Тем не менее
Это необходимо, только если вам нужен делегат одной подписи для вызова делегата другой (менее строгой) подписи. В его примере вы можете просто установить b = Foo1
, и он скомпилируется, но это не проиллюстрирует смысл.