解析.Net 4.0 中委托delegate的使用詳解_.Net教程

      編輯Tag賺U幣

      推薦:深入分析XmlSerializer對象的Xml序列化與反序列化的示例詳解
      本篇文章是對XmlSerializer 對象的Xml序列化與反序列化的應用進行了詳細的分析介紹,需要的朋友參考下

      .Net中的委托從功能上講和c語言或者c++中的方法指針類似,可以像調用方法一樣調用委托完成某個功能,或返回某類結果。但是.Net畢竟是更高級的語言,委托Delegate也更高級了,委托是一種數據接口,它包含調用目標和調用方法的指針;而在.Net中定義的委托都繼承自MulticastDelegate即多播委托,所謂的多播委托是指可以包含多個調用方法的委托。
      一. 先來看下委托的定義:
      如下C#代碼定義委托
      public delegate void DoSomething(int times);
      委托的定義包含5個部分
      1) public表示委托的可訪問性
      2) delegate關鍵字表示要定義一個委托
      3) void表示委托定義方法的返回值
      4) DoSomething是委托的名字
      5) (int times) 是委托方法的參數列表,此處的參數列表可以包括ref參數,也可以有out參數,同樣也可以有parms可變數量參數;需要注意如果委托中有多個調用方法,使用out參數時只能返回委托最后執行成功的一個委托方法的計算值
      在C#中定義委托非常簡單,只比方法定義的返回值之前多一個delegate關鍵字即可。
      可是我們知道所有的用戶定義委托都繼承自MulticastDelegate;而MulticastDelegate是一個類;所以自定義的委托肯定也是一個類;看下上述代碼的IL代碼就可以證明我們的推斷:
      復制代碼 代碼如下:www.wf0088.com

      .class public auto ansi sealed delegates.DoSomething
      extends [mscorlib]System.MulticastDelegate
      {
      // Methods
      .method public hidebysig specialname rtspecialname
      instance void .ctor (
      object 'object',
      native int 'method'
      ) runtime managed
      {
      } // end of method DoSomething::.ctor

      .method public hidebysig newslot virtual
      instance void Invoke (
      int32 times
      ) runtime managed
      {

      } // end of method DoSomething::Invoke


      .method public hidebysig newslot virtual
      instance class [mscorlib]System.IAsyncResult BeginInvoke (
      int32 times,
      class [mscorlib]System.AsyncCallback callback,
      object 'object'
      ) runtime managed
      {

      } // end of method DoSomething::BeginInvoke


      .method public hidebysig newslot virtual
      instance void EndInvoke (
      class [mscorlib]System.IAsyncResult result
      ) runtime managed
      {

      } // end of method DoSomething::EndInvoke

      } // end of class delegates.DoSomething

      二. 定義了委托,當然是為了使用它,來看下如何使用委托:
      在.Net中有三種委托的形式,分別是方法、匿名方法和lambda表達式;我們用方法定義的形式看下委托的使用方法
      復制代碼 代碼如下:www.wf0088.com

      using System;

      namespace delegates
      {
      public delegate void DoSomething(int times);

      class Program
      {
      static void Main(string[] args)
      {
      //聲明委托變量并給委托變量賦值
      DoSomething @do = DoA;
      //可以使用+號或者+=給委托增加方法
      @do += DoB;
      //執行委托時將按照委托的添加順序先后執行委托中的方法
      @do(1);
      //也可以通過-號或者-= 從委托中移除方法
      @do -= DoA;
      @do(2);

      @do -= DoB;
      //將委托中的所有方法都移除掉之后,委托照樣是可以調用的,只是什么都不做
      @do(3);

      Console.Read();
      }
      //定義一個委托相同參數和返回值的方法
      static void DoA(int times)
      {
      Console.WriteLine("Do A {0}", times);
      }


      //定義一個委托相同參數和返回值的方法
      static void DoB(int times)
      {
      Console.WriteLine("Do B {0}", times);
      }
      }
      }

      如上代碼中的Main方法,首先我們定義了委托DoSomething的變量@do,并將DoA方法直接賦值給此委托變量;然后我們又使用+=符號或者+號給此委托添加了另一個方法;當然也可以使用-或者-=從委托中去掉方法。
      委托比C/C++方法指針強大的地方在于其可以容納多個方法,也可以執行+/-操作從方法列表中添加或者刪除掉方法。
      在執行委托加減運算時有幾個問題需要我們注意:
      1. 委托聲明的寫法
      委托聲明時可以用如下寫法
      復制代碼 代碼如下:www.wf0088.com

      DoSomething @do = DoA;

      這其實是一種簡短的寫法,我們知道在.Net 1.x中這樣寫是不允許的只有到.Net 2.0時才允許這么寫,在.Net 1.x中必須寫成
      復制代碼 代碼如下:www.wf0088.com

      DoSomething @do = new DoSomething(DoA);

      我們要在聲明時就給@do賦予DoA加上DoB
      復制代碼 代碼如下:www.wf0088.com

      DoSomething @do = DoA + DoB;

      這么寫是不行的,編譯器不干了;必須使用.Net 1.x中的寫法
      復制代碼 代碼如下:www.wf0088.com

      DoSomething @do = new DoSomething(DoA) + new DoSomething(DoB);

      2. 從委托中減去委托中本不存在的方式時會發生什么呢?
      請看如下代碼:
      復制代碼 代碼如下:www.wf0088.com

      DoSomething @do = DoA;
      @do -= DoB;

      第一行代碼我生命了@do并將DoA賦予它;第二行代碼我嘗試從@do中減去DoB,DoB并沒有在@do的方法列表中存在,這樣會發生什么情況呢?首先編譯器沒有報錯,程序可以正常的編譯;執行代碼發現可以程序可以正常執行,調用@do委托時正確的執行了DoA方法;這說明了.Net包容了我們程序員犯的錯,我們從委托變量中減去一個委托中并不包含的方法時,不會報錯會正常的執行。
      3. 對委托做減法,所有委托都減完了,會怎樣呢?看如下代碼
      復制代碼 代碼如下:www.wf0088.com

      DoSomething @do = new DoSomething(DoA) + new DoSomething(DoB);
      @do -= DoA;
      @do -= DoB;
      @do(1);

      這樣的代碼可以成功編譯,但是在運行時會報NullReferenceException;這顯然不是我們希望的,所以對委托做減法時要特別注意。
      復制代碼 代碼如下:www.wf0088.com

      <span style="text-decoration: line-through;">public delegate void DoIt(string task);

      class Test
      {
      static void Main(string[] args)
      {
      //DoIt聲明,賦予一個參數更寬泛的方法是合法的
      DoIt doIt = new DoIt(DoItImpl);
      doIt("hello");
      }

      //比委托定義中的參數更寬泛,string類型可以隱式轉換成object
      static void DoItImpl(object task)
      {
      Console.WriteLine("DoItImpl {0}",task);
      }
      }
      </span>

      分享:解析linq to xml操作XML的示例分析
      本篇文章是對linq to xml操作XML的示例進行了詳細的分析介紹,需要的朋友參考下

      來源:模板無憂//所屬分類:.Net教程/更新時間:2013-05-19
      相關.Net教程