zl程序教程

您现在的位置是:首页 >  IT要闻

当前栏目

异步、同步委托解析(一)

2023-02-18 16:38:17 时间

    委托的定义想必大家都知道,它本质上是一个类,我们定义一个委托:

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方法,这就是同步委托的调用过程。