C # делегат под капотом вопрос - PullRequest
2 голосов
/ 05 мая 2010

Я немного покопался в дисперсии делегатов после прочтения следующего вопроса в 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());
        }
    }
}

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

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

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

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

1 Ответ

9 голосов
/ 05 мая 2010

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

...