VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > Python基础教程 >
  • C#教程之委托(delegate)(3)

<summary> 5 /// 模拟观察者 6 /// </summary> 7 public void Demo() 8 { 9 Manager manager = new Manager(); 10 manager.Attach(new MulticastInstance(Add)); 11 manager.Attach(new MulticastInstance(Reduce)); 12 manager.Attach(new MulticastInstance(Multiply)); 13 manager.Execute(10, 5); 14 } 15 /// <summary> 16 /// Observer模式、又称呼发布订阅或监听模式 17 /// </summary> 18 public class Manager 19 { 20 private MulticastInstance Handler; 21 22 /// <summary> 23 /// 附加观察者 24 /// </summary> 25 /// <param name="handler1"></param> 26 public void Attach(MulticastInstance handler1) 27 { 28 Handler += handler1; 29 } 30 /// <summary> 31 /// 分离观察者 32 /// </summary> 33 /// <param name="handler1"></param> 34 public void Detach(MulticastInstance handler1) 35 { 36 Handler -= handler1; 37 } 38 /// <summary> 39 /// 如果观察者数量大于0即执行播委托列表中的方法 40 /// </summary> 41 /// <param name="inputA"></param> 42 /// <param name="inputB"></param> 43 public void Execute(int inputA, int inputB) 44 { 45 if (Handler != null) 46 if (Handler.GetInvocationList().Count() != 0) 47 Handler(inputA, inputB); 48 } 49 } 50 private int Add(int inputA, int inputB) 51 { 52 int result = inputA + inputB; 53 Console.WriteLine("Add方法执行结果:{0}", result); 54 return result; 55 } 56 private int Reduce(int inputA, int inputB) 57 { 58 int result = inputA - inputB; 59 Console.WriteLine("Reduce方法执行结果:{0}", result); 60 return result; 61 } 62 private int Multiply(int inputA, int inputB) 63 { 64 int result = inputA * inputB; 65 Console.WriteLine("Multiply方法执行结果:{0}", result); 66 return result; 67 } 68 }

 

委托揭秘

委托看似很容易使用,通过delegate关键词定义,用熟悉的new构造委托实例,熟悉的方式调用回调函数,但实际上编译器和CLR在幕后做了大量工作来隐藏其复杂性。
重新审视上面计算器的一段代码:
1     public delegate int MulticastInstance(int inputA, int inputB);

事实上通过反编译可看到:

编译器相当于定义了一个完整的类(继承自System.MulticastDelegate,定义四个方法:构造函数、Invoke、BeginInvoke和EndInvoke):

 
 1      internal class MulticastInstance : System.MulticastDelegate//继承System.MulticastDelegate
 2         {
 3             //构造器
 4             public MulticastInstance(object @object, IntPtr method);
 5             //这个方法的原型和源代码指定的一样
 6             public virtual int Invoke(int inputA, int inputB);
 7             //实现回调方法和异步回调
 8             public virtual IAsyncResult BeginInvoke(int inputA, int inputB, AsyncCallback callback, object @object);
 9             public virtual int EndInvoke(IAsyncResult result);
10         }
11         /*
12          * 作者:Jonins
13          * 出处:http://www.cnblogs.com/jonins/
14          */

所有委托类型都派生自System.MulticastDelegate类,System.MulticastDelegate派生自System.Delegate,后者又派生自System.Object。历史原因造成有两个委托类。
创建的所有委托类型豆浆MulticastDelegate作为基类,个别情况下仍会用到Delegate。Delegate类的两个静态方法CombineRemove的签名都指出要获取Delegate参数。由于创建的委托类型派生自MulticastDelegate,后者又派生自Delegate,所以委托类型的实例是可以传递给这两个方法的。

MulticastDelegate的三个重要非公共字段

字段 类型 说明
_target System.Object

当委托对象包装一个静态方法时,这个字段为null。当委托对象包装一个实例方法时,这个字段引用的是回调方法要操作的对象。

当委托对象包装一个实例方法时,这个字段引用的是回调方法要操作的对象。换言之

换言之,这个字段指出要传给实例方法的隐士参数的值。

_methodPtr System.IntPtr

一个内部的整数值,CLR用它标记要回调的方法。

_invocationList System.Object 该字段通常为null,构造委托链时它引用一个委托数组。

Delegate反编译后可看到静态方法CombineRemove(委托的+、-、+=、-=编译后的本质):

 1     [Serializable, ClassInterface(ClassInterfaceType.AutoDual), ComVisible(true), __DynamicallyInvokable]
 2     public abstract class Delegate : ICloneable, ISerializable
 3     {
 4         [ComVisible(true), __DynamicallyInvokable]
 5         public static Delegate Combine(params Delegate[] delegates);
 6         [__DynamicallyInvokable]
 7         public static Delegate Combine(Delegate a, Delegate b);
 8         [SecuritySafeCritical, __DynamicallyInvokable]
 9         public static Delegate Remove(Delegate source, Delegate value);
10     }

 

 结语

同步委托将阻塞当前线程,等待方法执行完毕继续执行程序,相当于直接调用方法。异步委托是将方法放入线程池中执行并不阻塞主线程。异步委托从根本上说并不是多线程技术(任务Task也一样),就算异步委托内部将方法塞给线程池去执行也并不能说是开辟新线程执行方法,(线程池一定开辟新线程)这种说法并不严谨。委托本质是将调用者和目标方法动态关联起来,这是或许是我所理解的委托存在的最根本目的吧。

 



相关教程
关于我们--广告服务--免责声明--本站帮助-友情链接--版权声明--联系我们       黑ICP备07002182号