詳解C#委託和事件(二)

  1、當咱們使用關鍵字delegate聲明一個自定義委託類型時,其實是聲明瞭一個該名稱的類類型,繼承自抽象類System.MulticastDelegate,還包含實例方法Invoke、BeginInvoke、EndInvoke:異步

  public delegate void MyDelegate();

  

  其中的構造函數中第二個參數是native int類型的,這個是什麼呢?咱們接着看:函數

  咱們知道在C#中任何方法均可以直接賦值給簽名一致的委託實例,這個過程看似並不合理,按理來講C#中不支持直接獲取函數的指針,其實這裏是由編譯器進行了取址操做,查看IL代碼可知:spa

  MyDelegate myDelegate = myObj.MyFunc;

  

  能夠看到由編譯器爲咱們進行了構建委託實例的過程,並且這裏調用了ldftn命令將實例方法MyFunc()的native int類型的非託管指針推到棧中,從而將該方法的指針傳到委託的構造函數中;線程

  因爲上面的構造函數存在C#中不支持的函數指針類型void(),因此不能在運行時使用Activator類中的方法建立委託實例,但在委託基類Delegate中存在靜態方法CreateDelegate()調用非託管代碼用於動態建立委託實例,命名空間System.Reflection中的方法信息類MethodInfo的實例方法CreateDelegate()也提供了相似的方式以在運行時動態構建委託實例:3d

    Type delegateType = typeof(MyDelegate);  //這裏以可訪問到的委託類型舉例
    Delegate @delegate = Delegate.CreateDelegate(delegateType, myObj, "MyFunc");
    //@delegate = typeof(MyClass).GetMethod("MyFunc").CreateDelegate(delegateType, myObj);
    //添加其它委託實例
    @delegate = Delegate.Combine(@delegate, otherDelegate);
    //調用委託
    @delegate.DynamicInvoke();
    //當指定的委託類型可訪問時,能夠將委託實例顯式轉換爲指定的委託類型後使用()或Invoke()正常調用
    //MyDelegate myDelegate = @delegate as MyDelegate;
    //myDelegate();

  對委託實例或方法的+、+=操做實際上也是調用基類Delegate中的靜態方法Combine()並將合成後的委託強制轉換爲原類型後返回,-、-=操做則是調用靜態方法Remove();指針

   

  2、委託的異步調用:經過委託類型的實例方法BeginInvoke開啓子線程並在該子線程中執行委託實例中的方法,以此種方式調用的委託實例中有且只能有一個方法,若是包含多個方法,會拋出異常ArgumentException:code

  myDelegate.BeginInvoke(null, null); //其中第一個參數爲AsyncCallback類型的回調函數

  若是須要異步調用一個委託實例中方法列表中的全部方法,須要先獲取方法列表,再依次進行異步調用:blog

  Delegate[] delegates = myDelegate.GetInvocationList();
  for (int i = 0; i < delegates.Length; i++)
  {
    (delegates[i] as MyDelegate).BeginInvoke(null, null);
  }

  3、當調用委託時,若是方法列表中某個方法內引起異常且未在該方法體內捕獲時,該異常將傳遞給委託的調用方,而且再也不調用方法列表中的後面的方法,所以在方法體內捕獲異常顯得尤其重要;繼承

  4、泛型中的委託:自定義泛型委託(Generic Delegate),將類型參數用做參數列表或返回值的類型:get

  delegate void MyDelegate<T>(T obj); //聲明具備一個類型參數的泛型委託,參數列表中有一個參數
  void MyGenericFunc<T>(T obj) //聲明一個泛型方法,參數列表中有一個參數
  {
    //do…
  }
  void MyFunc(string str)
  {
    //do…
  }
  //聲明泛型委託的實例,指定類型參數爲string類型,此時可匹配的方法簽名爲void myFunc(string str)
  MyDelegate<string> myDelegate;
  //賦值一個指定類型參數爲string的泛型方法
  myDelegate = MyGenericFunc<string>;
  //添加一個參數列表爲string類型的具體方法
  myDelegate += MyFunc;

  ※泛型委託同泛型類同樣,須要在實例化時指定類型參數的類型;

  ※泛型委託的實例同具體委託的實例同樣,只須要方法的參數列表和返回值類型相同便可進行匹配,所以無論目標方法是指定了符合要求類型的泛型方法仍是具體方法均可以進行匹配;

 


若是您以爲閱讀本文對您有幫助,請點一下「推薦」按鈕,您的承認是我寫做的最大動力!

做者:Minotauros
出處:https://www.cnblogs.com/minotauros/

本文版權歸做者和博客園共有,歡迎轉載,但未經做者贊成必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接,不然保留追究法律責任的權利。

相關文章
相關標籤/搜索