委託的定義想必大家都知道,它本質上是一個類,我們定義一個委託:
1 delegate int Decrement(int x,int y);
經過編譯後,編譯器自動產生一個從MultiCastDelegate繼承下來的密封類:
1 sealed class Decrement:MultiCastDelegate
2 {
3 }
那麼,Decrement這個類中應該包含哪些成員呢?經過分析,編譯器給我們產生的完整的Decrement類應該是這樣的:
完整的Decrement類
1 sealed class Decrement:MultiCastDelegate
2 {
3 public Decrement(object target,uint functionAddresss);//建構函式
4 public int Invoke(int x,int y);//同步調用委託方法
5 public IAsyncResult BeginInvoke(int x,int y,AsyncCallBack cb,object state);//非同步呼叫委託方法
6 public int EndInvoke(IAsyncResult ar);//非同步結束委託方法的調用
7
8 }
我們知道,MultiCastDelegate類從Delegate類繼承而來,他們都是abstract的,但是我們不能顯示從他們派生新的類,只能由編譯器做這個事情,查看MSDN,我們知道Delegate類有兩個重要的公開屬性:target 、method,其中target是Object類型的,method是System.Reflection.MethodInfo類型的(這個類型通常指一個方法,如果大家熟悉反射,就應該很清楚了),其中,method指該委託所綁定的方法,即建立委託變數時,傳給建構函式的參數,這個參數通常是一個函數名,target指與method綁定的對象,如果我們這樣建立一個委託變數:Decrement d=new Decrement(obj.function);其中obj是一個對象,function是obj的成員函數,完了後,target就指obj對象了,method就指function函數了。
好了,知道Decrement委託的真實面貌之後,我們再來分析我們“從建立委託變數,到調用委託方法”的過程。
完整的委託應用執行個體
1 using System;
2 using System.Threading;//關於線程操作的命名空間(新加)
3 namespace ConsoleApplication3
4 {
5 delegate int Decrement(int x,int y);//定義委託
6 class Program
7 {
8 static void Main(string[] args)
9 {
10
11 Decrement MyDelegate=new Decrement(function);//建立委託變數,參數為function
12 int result=MyDelegate(10,8);//調用
13
14 console.readline();
15 }
16
17 static int function(int x,int y)
18 {
19
20 return x-y;
21 }
22
23 }
24 }
以上是一個委託非常簡單但普遍的運用方法,下面我們來分析一下該過程:
1)、第一步,我們定義一個委託:delegate int Decrement(int x,int y);編譯器為我們定義一個類:sealed class Decrement:MultiCastDelegate;
2)、第二步,我們建立一個委託變數:Decrement MyDelegate=new Decrement(function);相當於定義一個Decrement類的對象,同時調用它的建構函式,將function賦給method成員,target為null,當然,如果我們傳給建構函式的是一個執行個體方法,也即這樣傳參:Decrement MyDelegate=new Decrement(obj.function)的,那麼target就為obj;
3)、第三步,建立完委託變數之後,我們就要運用它了:int result=MyDelegate(10,8),其實,當我們寫下這一句代碼時,實際調用的是MyDelegate.Invoke(10,8)這個成員函數,該方法是一個同步阻塞的,即直到function方法執行完之後,該方法才返回,同時返回function執行的結果。
好了,三步剛好,我們要研究的是這個Invoke方法它是怎樣阻塞的!!
為了更好分析這個問題,我們再稍微改一下上面的那個委託應用執行個體:
修改後的委託應用執行個體
1 using System;
2 using System.Threading;//關於線程操作的命名空間(新加)
3 namespace ConsoleApplication3
4 {
5 delegate int Decrement(int x,int y);//定義委託
6 class Program
7 {
8 static void Main(string[] args)
9 {
10 Console.Write("Main方法所線上程ID:{0}\n",Thread.CurrentThread.ManagedThreadID);//輸出Main方法所線上程ID,亦即主線程ID (新加)
11
12 Decrement MyDelegate=new Decrement(function);//建立委託變數,參數為function
13 int result=MyDelegate(10,8);//調用
14
15 console.readline();
16 }
17
18 static int function(int x,int y)
19 {
20 Console.Write("function方法所線上程ID:{0}\n",Thread.CurrentThread.ManagedThreadID);//輸出function方法所線上程ID(新加) // Thread.Sleep(10000);
21 return x-y;
22 }
23
24 }
25 }
在原來的基礎上,我們分別在Main方法中輸出該方法所線上程ID,function方法所線上程ID,運行之後,我們會發現,輸出的兩個ID相等,這說明,通過MyDelegate(10,8)這樣調用委託方法時,系統並沒有為我們開啟一個新的線程來執行function方法,這就是同步委託的調用過程。