2010-05-05 2 views
1

я делал некоторые копаться в делегат дисперсии после прочтения на следующий вопрос SO: Delegate.CreateDelegate() and generics: Error binding to target methodC# Делегат под капотом вопрос

Я нашел очень хороший кусок кода от Барри Келли на 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. как можно вызвать вызов без прохождения параметров требуемых статической функции.
  2. Когда происходят под капотом, когда вы назначаете возвращаемое значение от вызова вызов
  3. Что Барри означает, экстренная косвенность (в комментарии)

ответ

9

Он не называет Invoke (обратите внимание на отсутствие из ()), он использует неявное создание делегата для установки b, равного новому экземпляру derivedClassDelegate, который указывает на метод Invokea. Дополнительным направлением является то, что при вызове 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, и он будет компилироваться, но это не проиллюстрировало бы точку.

+0

Спасибо Адаму очень хороший ответ Я только что получил его ... – Ted

+0

@Ted: Если это ответили на ваш вопрос, пожалуйста, примите его в качестве ответа. Благодаря! –

+0

oops извините. сделанный :-) – Ted

Смежные вопросы