一.同步委托
委托类型可以分为同步委托和异步委托,同步委托通过Invoke来调用,如果要调用一项比较繁琐的工作时,同步委托则会阻塞,让程序停滞等待很长时间,直到委托中的工作完成后才能继续执行下去,这样的话会造成很不好的用户体检。
下例所示:
using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Remoting.Messaging; using System.Text; using System.Threading; using System.Threading.Tasks; namespace DelegateInvoke { class Program { private delegate float DelegaetAdd(float a, float b); static void Main(string[] args) { DelegaetAdd myDelegate = new DelegaetAdd(Add); float subNum = myDelegate.Invoke(5, 6); Console.WriteLine("主线程继续执行。。。。。"); Console.WriteLine("值为{0}", subNum); Console.ReadKey(); } private static float Add(float a, float b) { Console.WriteLine("正在执行。。。。。。"); Thread.Sleep(2000); return (a + b); } } }
打印结果:
二.异步委托
由于同步委托为造成程序卡顿,造成不好的用户体检,那么此时使用异步委托便是再好不过了;异步委托是通过BeginInvoke和Endinvoke调用实现的。
下例所示:
using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Remoting.Messaging; using System.Text; using System.Threading; using System.Threading.Tasks; namespace DelegateInvoke { class Program { private delegate float DelegaetAdd(float a, float b); static void Main(string[] args) { DelegaetAdd myDelegate = new DelegaetAdd(Add); IAsyncResult result = myDelegate.BeginInvoke(5, 6, null, null); Console.WriteLine("主线程继续执行。。。。。。"); float subNum = myDelegate.EndInvoke(result); Console.WriteLine("值为{0}", subNum); Console.WriteLine("执行完毕。。。。。"); Console.ReadKey(); } private static float Add(float a, float b) { Console.WriteLine("正在执行。。。。。。"); Thread.Sleep(2000); return (a + b); } } }
打印结果:
从打印结果中可以看出,主线程并没有去等待,而是直接就运行下去了,但是我们可以发现,当主线程运行到了EndInvoke,如果此时调用还没有结束的话,那么此时为了等待调用结果,线程依然会阻塞等待调用完成的。
三.异步回调
可以看出以上两种方法都不能解决调用时阻塞的问题,那么这时候,就该主角上场了,那就是异步回调了;用回调函数,当调用结束时会自动调用回调函数,能够很好地解决为了等待调用结果而导致主线程阻塞的问题。
下例所示:
using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Remoting.Messaging; using System.Text; using System.Threading; using System.Threading.Tasks; namespace DelegateInvoke { class Program { private delegate float DelegaetAdd(float a, float b); static void Main(string[] args) { DelegaetAdd myDelegate = new DelegaetAdd(Add); AsyncCallback callBack = new AsyncCallback(CallBack); IAsyncResult result = myDelegate.BeginInvoke(5, 6, callBack, "Completed"); Console.WriteLine("主线程继续执行。。。。。。"); Console.ReadKey(); } //异步回调函数 private static void CallBack(IAsyncResult result) { DelegaetAdd myDelegate = (DelegaetAdd)((AsyncResult)result).AsyncDelegate; if(result.IsCompleted) { Console.WriteLine("正在执行。。。。。"); Thread.Sleep(2000); Console.WriteLine("值为{0}", myDelegate.EndInvoke(result)); Console.WriteLine(result.AsyncState); } } private static float Add(float a, float b) { return (a + b); } } }
打印结果:
BeginInvoke() 方法用于异步委托的执行开始,EndInvoke() 方法用于结束异步委托,并获取异步委托执行完成后的返回值。IAsyncResult.IsCompleted 用于监视异步委托的执行状态(true / false),一定要等到异步委托执行完成之后,这个属性才会返回 true。BeginInvoke() 是可以接受多个参数的,它的参数个数和参数类型取决于定义委托时的参数个数和类型,但是无论它有多少个参数,最后两个参数都是不变的;第一个便是委托类型AsyncCallBack(IAsyncResult result),第二个便是用户自定义的数据类型,IAsyncResult.AsyncState就是它的值。