Вопрос о делегате С# под капотом

Я немного покопался в дисперсии делегатов после прочтения следующего вопроса в SO: Delegate.CreateDelegate() и дженерики: ошибка привязки к целевому методу

Я нашел очень хороший фрагмент кода от Барри Келли по адресу https://www.blogger.com/comment.g?blogID=8184237816669520763&postID=2109708553230166434

Вот он (в подслащенном виде :-)

using System;

namespace ConsoleApplication4
{
    internal class Base
    {
    }

    internal class Derived : Base
    {
    }

    internal delegate void baseClassDelegate(Base b);

    internal delegate void derivedClassDelegate(Derived d);


    internal class App
    {
        private static void Foo1(Base b)
        {
            Console.WriteLine("Foo 1");
        }

        private static void Foo2(Derived b)
        {
            Console.WriteLine("Foo 2");
        }

        private static T CastDelegate<T>(Delegate src)
            where T : class
        {
            return (T) (object) Delegate.CreateDelegate(
                                    typeof (T),
                                    src.Target,
                                    src.Method,
                                    true); // throw on fail
        }

        private static void Main()
        {
            baseClassDelegate a = Foo1; // works fine

            derivedClassDelegate b = Foo2; // works fine

            b = 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());
        }
    }
}

Я все понимаю, кроме этой (выглядящей очень простой) строчки.

б = а.Invoke; // простой способ назначить делегата с помощью дисперсии, хотя и добавляет уровень косвенности

Может ли кто-нибудь сказать мне:

  1. как можно вызвать invoke без передачи параметра, требуемого статической функцией.
  2. Когда происходит под капотом, когда вы назначаете возвращаемое значение при вызове вызова
  3. Что Барри имеет в виду под дополнительной косвенностью (в своем комментарии)

person Ted    schedule 05.05.2010    source источник


Ответы (1)


Он не вызывает 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, и он скомпилировался бы, но это не иллюстрировало бы суть.

person Adam Robinson    schedule 05.05.2010
comment
@Ted: Если это ответило на ваш вопрос, примите это как ответ. Спасибо! - person Adam Robinson; 06.05.2010