委托对象的调用列表中只有一个方法(我们通常称之为 引用方法 )时,可以进行异步执行。委托类有两个方法:BeginInvoke和EndInvoke就是用来实现这一效果的。
通常我们在实际使用过程中,这种异步执行的方法常常采用三种模式:
1. BeginInvoke和EndInvoke方法
首先我们需要了解BeginInvoke的一些重要事项:
delegate long MyDel(int first, int second);
static long Sum (int x,int y){...}
MyDel del=new MyDel(Sum);
IAsyncResult iar = del.BeginInvoke(3,5,null,null);
EndInvoke 用来获取异步方法调用返回的值,并且清除释放线程中使用的资源。特征如下:
它接受BeginInvoke返回的IAsyncResult对象,并由此找到关联的线程;
如果线程池中的线程已经退出,则做如下两件事:
清理线程状态并释放其资源;
如果引用方法有返回值,则将其返回。
如果线程仍在运行,EndInvoke将停止并等待,直到方法完成,然后清理线程并获取返回值。因为EndInvoke负责线程清理工作,因此每一个BeginInvoke都必须有对应的EndInvoke相匹配。
如果异步方法触发了异常,将在调用EndInvoke方法时抛出。
如下代码示例了一个EndInvoke的调用,它必须以IAsyncResult对象的引用为参数:
long result = del.EndInvoke(iar);
EndInvoke提供了从异步方法返回的所有输出,包括ref和out参数。如果委托的引用方法有ref和out参数,它们就必须包含在EndInvoke的参数列表中。例如:
long result = del.EndInvoke(out int someInt, iar);
2. 等待完成模式
在这种模式下,原始线程发起一个异步方法的调用,做一些事情处理,然后停止并等待,直到开启线程结束。
using System;
using System.Threading;
delegate long MyDel (int first, int second);
class Program
static long Sum(int x, int y)
Console.WriteLine(“ Inside Sum”);
Thread.Sleep(100);
return x+y;
static void Main()
MyDel del=new MyDel(Sum);
Console.WriteLine(“Before BeginInvoke”);
IAsyncResult iar=del.BeginInvoke(3, 5, null, null);
Console.WriteLine(“ After BeginInvoke”);
Console.WriteLine(“Doing stuff”);
long result = del.EndInvoke(iar);
Console.WriteLine(“After EndInvoke:{0}”, result);
3.AsyncResult类
AsyncResult 是方法的必要部分,BeginInvoke 返回一个IAsyncResult接口的引用(内部是AsyncResult类的对象)。AsyncResult类表现了异步方法的状态。
当我们调用委托对象的BeginInvoke方法时,系统创建一个AsyncResult类的对象,然后它不返回类对象的引用,而是返回对象中包含的IAsyncResult接口的引用。
AsyncResult对象包含一个叫做AsyncDelegate的属性,它返回一个指向被调用来开启异步方法的委托的引用。注意,这个属性是类对象的一部分而不是接口的一部分。
IsCompleted 属性返回异步方法是否完成的布尔值。
AsyncState返回一个对象引用,做为BeginInvoke 方法调用时的state参数。它返回object类型的引用,只有在回调模式中使用。
4. 轮询模式
在轮询模式中,原始线程发起了异步方法的调用,做一些其他处理,然后使用IAsyncResult对象的IsCompleted属性定期检查开启的线程是否完成。如果完成则继续向下执行,否则继续做它的其他处理,直到下一次检查。
delegate long MyDel(int x, int y);
class program
long Sum(int x, int y)
Console.WriteLine(" Inside Sum");
Thread.Sleep(100);
return x + y;
static void Main()
MyDel del = new MyDel(Sum);
IAsyncResult iar = del.BeginInvoke(3, 5, null, null);
Console.WriteLine("After BeginInvoke");
while (!iar.IsCompleted)
Console.WriteLine("Not Done");
for (long i = 0; i < 10000000; i++) ;
Console.WriteLine("Done");
long result = del.EndInvoke(iar);
Console.WriteLine("Result:{0}", result);
4. 回调模式
在之前的等待结束模式和轮询模式中,初始线程都是继续自己的控制流程,直到它知道开启的线程已经完成,然后获取结果并继续。
回调模式则与之不同,一旦初始线程发起了异步方法,由它自己管理,就不再进行管理。异步方法调用结束后,系统自动调用一个用户自定义的方法来自行处理结果,并且调用委托的EndInvoke方法。这个用户自定义的方法做做回调方法或简称回调。
BeginInvoke的参数列表中最后两个额外参数就是供回调方法使用的。
第一个参数callback,是回调方法的名字;
第二个参数state,可以是null或要传入回调方法的一个对象引用。我们可以通过使用IAsyncResult参数的AsyncState属性来获取这个对象,参数类型是object。
1)回调方法
回调方法的签名和返回类型必须与AsyncCallback委托类型所描述的形式一致。它需要方法接受一个IAsyncResult作为参数并且返回类型是void,如下所示
void AsyncCallback(IAsysnResult iar)
我们有多种方式可以为BeginInvoke方法提供回调方法。由于BeginInvoke中的callback参数是AsyncCallback类型的委托,我们可以以委托形式提供,或者,我们也可以只提供回调方法的名称,让编译器为我们创建委托,两种方法是完全等价的。
IAsyncResult iar1=del.BeginInvoke(3,5,new AsyncCallback(CallWhenDone),null)
IAsyncResult iar2=del.BeginInvoke(3,5,CallWhenDone,null)
BeginInvoke的另外一个参数是发送给回调方法的对象。它可以是任何类型的对象,但是参数类型是object。所以在回调方法中,我们必须转换成正确的类型。
2)在回调方法中调用EndInvoke
在回调方法内,我们的代码应该调用委托的EndInvoke方法来处理异步方法执行后的输出值。要调用委托的EndInvoke方法,我们肯定需要委托对象的引用,而它在初始线程中,不在开启的线程中。如果不使用state参数作为其他用途,可以使用它发送委托的引用给回调方法。
IAsyncResult iar = del,BeginInvoke(3,5,CallWhenDone,del);
给回调方法的参数只有一个,就是刚结束的异步方法的IAsyncResult接口的引用。请记住:IAsyncResult接口对象在内部就是AsyncResult类对象。
尽管IAsyncResult接口没有委托对象的引用,而封装它的AsyncResult类对象却有委托对象的引用。所以可以通过转换接口引用为类类型来获取类对象的引用。
有了类对象的引用,我们现在就可以调用类对象的AsyncDelegate属性并且把它转换为合适的委托类型。这样就得到了委托引用,我们可以用它来调用EndInvoke方法。
using System.Runtime.Remoting.Messaging; //包含AsyncResult类
void CallWhenDone(IAsyncResult iar)
AsyncResult ar = (AsyncResult)iar; // 获取类对象的引用
MyDel del = (MyDel)ar.AsyncDelegate; // 获取委托的引用
long sum = del.EndInvoke(iar); // 调用EndInvoke方法
如此我们就完成了一个使用回调模式的完整示例。为了方便阅读,我们把所有知识点放在一起:
using System;
using System.Threading;
using System.Runtime.Remoting.Messaging; //包含AsyncResult类
namespace YbydjyLibrary
delegate long MyDel(int first, int second);
class Program
static long Sum(int x, int y)
Console.WriteLine(" Inside Sum");
Thread.Sleep(100);
return x + y;
static void CallWhenDone(IAsyncResult iar)
Console.WriteLine(" Inside CallWhenDone");
AsyncResult ar = (AsyncResult)iar; // 获取类对象的引用
MyDel del = (MyDel)ar.AsyncDelegate; // 获取委托的引用
long sum = del.EndInvoke(iar); // 调用EndInvoke方法
Console.WriteLine($"Result:{sum}");
static void Main()
MyDel del = new MyDel(Sum);
Console.WriteLine("Before BeginInvoke");
IAsyncResult iar = del.BeginInvoke(3, 5, new AsyncCallback(CallWhenDone), null);
Console.WriteLine("Doing more work in Main");
Thread.Sleep(500);