异步、同步委托解析(一)
委托的定义想必大家都知道,它本质上是一个类,我们定义一个委托:
经过编译后,编译器自动生成一个从MultiCastDelegate继承下来的密封类:
2 {
3 }
那么,Decrement这个类中应该包含哪些成员呢?经过分析,编译器给我们生成的完整的Decrement类应该是这样的:
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委托的真实面貌之后,我们再来分析我们“从创建委托变量,到调用委托方法”的过程。
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方法它是怎样阻塞的!!
为了更好分析这个问题,我们再稍微改一下上面的那个委托应用实例:
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方法,这就是同步委托的调用过程。