首页 > Python基础教程 >
-
C#教程之委托(delegate)
委托概述
将方法调用者和目标方法动态关联起来,委托是一个类,所以它和类是同级的,可以通过委托来掉用方法,不要误以为委托和方法同级的,方法只是类的成员。委托定义了方法的类型(定义委托和与之对应的方法必须具有相同的参数个数,并且类型相同,返回值类型相同),使得可以将方法当作另一个方法的参数来进行传递,这种将方法动态地赋给参数的做法,可以避免在程序中大量使用If-Else(Switch)语句,同时使得程序具有更好的可扩展性。
基础委托(Delegate)
在.Net中声明委托使用关键词delegate,委托具有多种使用方式(以下均为同步委托调用):
1 /// <summary> 2 /// 普通委托基础调用方式(同步委托) 3 /// </summary> 4 public class Delegates 5 { 6 /// <summary> 7 /// 定义有参无返回值委托 8 /// </summary> 9 /// <param name="i"></param> 10 public delegate void NoReturnWithParameters(string o); 11 /// <summary> 12 /// 构造函数实例化 13 /// </summary> 14 public void DemoOne() 15 { 16 NoReturnWithParameters methord = new NoReturnWithParameters(this.Test); 17 methord.Invoke("One-ok"); 18 } 19 /// <summary> 20 /// 赋值对象 21 /// </summary> 22 public void DemoTwo() 23 { 24 NoReturnWithParameters methord = this.Test; 25 methord.Invoke("Two-ok"); 26 } 27 /// <summary> 28 /// DotNet 2.0 29 /// </summary> 30 public void DemoThree() 31 { 32 NoReturnWithParameters methord = new NoReturnWithParameters( 33 delegate (string o) 34 { 35 Console.WriteLine("有参无返回值:{0}", o); 36 } 37 ); 38 methord.Invoke("Three-ok"); 39 } 40 /// <summary> 41 /// DotNet 3.0 42 /// </summary> 43 public void DemoFour() 44 { 45 NoReturnWithParameters methord = new NoReturnWithParameters( 46 (string o) => 47 { 48 Console.WriteLine("有参无返回值:{0}", o); 49 } 50 ); 51 methord.Invoke("Four-ok"); 52 } 53 /// <summary> 54 /// 委托约束 55 /// </summary> 56 public void DemoFive() 57 { 58 NoReturnWithParameters methord = new NoReturnWithParameters( 59 (o) => 60 { 61 Console.WriteLine("有参无返回值:{0}", o); 62 } 63 ); 64 methord.Invoke("Five-ok"); 65 } 66 /// <summary> 67 /// 方法只有一行去则掉大括号及分号 68 /// </summary> 69 public void DemoSix() 70 { 71 NoReturnWithParameters methord = new NoReturnWithParameters((o) => Console.WriteLine("有参无返回值:{0}", o)); 72 methord.Invoke("Six-ok"); 73 } 74 public void DemoSeven() 75 { 76 NoReturnWithParameters methord = (o) => Console.WriteLine("有参无返回值:{0}", o); 77 methord.Invoke("Seven-ok"); 78 } 79 /// <summary> 80 /// 定义有参无返回值测试方法 81 /// </summary> 82 /// <param name="o"></param> 83 private void Test(string o) 84 { 85 Console.WriteLine("有参无返回值:{0}", o); 86 } 87 /* 88 * 作者:Jonins 89 * 出处:http://www.cnblogs.com/jonins/ 90 */ 91 }
同步委托&异步委托
同步委托:委托的Invoke方法用来进行同步调用。同步调用也可以叫阻塞调用,它将阻塞当前线程,然后执行调用,调用完毕后再继续向下进行。
异步委托:异步调用不阻塞线程,而是把调用塞到线程池中,程序主线程或UI线程可以继续执行。委托的异步调用通过BeginInvoke和EndInvoke来实现。
以下为异步委托调用方式:
1 class Program 2 { 3 /// <summary> 4 /// 定义有参无返回值委托 5 /// </summary> 6 /// <param name="i"></param> 7 public delegate void NoReturnWithParameters(string o); 8 static void Main(string[] args) 9 { 10 NoReturnWithParameters methord = new NoReturnWithParameters(Test); 11 Console.WriteLine("主线程执行1"); 12 Console.WriteLine("主线程执行2"); 13 methord.BeginInvoke("demo-ok", null, null); 14 Console.WriteLine("主线程执行3"); 15 Console.WriteLine("主线程执行4"); 16 Console.ReadKey(); 17 } 18 /// <summary> 19 /// 异步调用委托方法 20 /// </summary> 21 /// <param name="o"></param> 22 static void Test(string o) 23 { 24 Console.WriteLine("有参无返回值:{0}", o); 25 } 26 /* 27 * 作者:Jonins 28 * 出处:http://www.cnblogs.com/jonins/ 29 */ 30 }
因为调用BeginInvoke为异步委托,不会阻塞主线程,运行结果如下:
异步回调(Callback)
异步回调通过设置回调函数,当调用结束时会自动调用回调函数,可以在回调函数里触发EndInvoke,这样就释放掉了线程,可以避免程序一直占用一个线程。
1 class Program 2 { 3 /// <summary> 4 /// 定义有参有返回值委托 5 /// </summary> 6 /// <param name="i"></param> 7 public delegate string ReturnWithParameters(string o); 8 static void Main(string[] args) 9 { 10 ReturnWithParameters methord = new ReturnWithParameters(Test); 11 Console.WriteLine("主线程执行1"); 12 Console.WriteLine("主线程执行2"); 13 /* 14 BeginInvoke方法参数个数不确定, 最后两个参数含义固定,如果不使用的话,需要赋值null 15 委托的方法无参数,这种情况下BeginInvoke中只有两个参数。 16 此外,委托的方法有几个参数,BeginInvoke中从左开始,对应响应的参数。 17 1.倒数第二个参数:是有一个参数值无返回值的委托,它代表的含义为,该线程执行完毕后的回调。 18 2.倒数第一个参数:向即回调中传值,用AsyncState来接受。 19 3.其它参数:对应委托方法的参数。 20 */ 21 IAsyncResult asyncResult = methord.BeginInvoke("demo-ok", new AsyncCallback(Callback), "AsycState:给回调函数的参数传递在此处出传值"); 22 Console.WriteLine("主线程执行3"); 23 Console.WriteLine("主线程执行4"); 24 Console.ReadKey(); 25 } 26 /// <summary> 27 /// 异步调用委托方法 28 /// </summary> 29 /// <param name="o"></param> 30 /// <returns></returns> 31 private static string Test(string o) 32 { 33 return "委托方法执行成功:" + o; 34 } 35 /// <summary> 36 /// 回调函数 37 /// </summary> 38 /// <param name="asyncResult"></param> 39 private static void Callback(IAsyncResult asyncResult) 40 { 41 /* 42 *asyncResult为回调前异步调用方法返回值 43 *AsyncResult 是IAsyncResult接口的一个实现类,引用空间:System.Runtime.Remoting.Messaging 44 *AsyncDelegate 属性可以强制转换为定义的委托类型 45 */ 46 ReturnWithParameters methord = (ReturnWithParameters)((System.Runtime.Remoting.Messaging.AsyncResult)asyncResult).AsyncDelegate; 47 Console.WriteLine(methord.EndInvoke(asyncResult)); 48 Console.WriteLine(asyncResult.AsyncState); 49 } 50 /* 51 * 作者:Jonins 52 * 出处:http://www.cnblogs.com/jonins/ 53 */ 54 }
执行结果如下:
注意:
1.异步调用只能调用一次EndInvoke,否则会报错。
2.如果不回调函数中执行EndInvoke,请在异步调用后手动执行EndInvoke方法释放资源。
异步委托线程等待
1.【Delegate】.EndInvoke(推荐)
1 public delegate void NoReturnWithParameters(string o); 2 NoReturnWithParameters noReturnWithParameters = new NoReturnWithParameters(...); 3 ...... 4 noReturnWithParameters.EndInvoke(asyncResult);
2.【IAsyncResult】.AsyncWaitHandle.WaitOne(可以定义等待时间,超过等待时间不继续等待向下执行)
1 IAsyncResult asyncResult = null; 2 asyncResult.AsyncWaitHandle.WaitOne