2010-05-05 65 views
1

我做了一些周圍挖成的委託方閱讀SO以下問題後:Delegate.CreateDelegate() and generics: Error binding to target method引擎蓋問題在C#委託

我發現從巴里·凱利代碼一個非常不錯位在 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等於指向aInvoke方法的新的derivedClassDelegate實例。額外的間接是當調用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 2010-05-06 00:12:59

+0

@Ted:如果這回答了您的問題,請接受它作爲答案。謝謝! – 2010-05-06 04:06:22

+0

抱歉。完成:-) – Ted 2010-05-06 05:40:25