【C#语言基础】--委托(Delegate)(一)
2011-03-29 17:58
507 查看
[b]一.动机[/b]
在Winform程序中我们经常有这样一种需求,就是在一个主窗口中,当用户点击添加按钮时弹出一个子窗口,用户输入数据,最后点击保存或者关闭窗口后需要主窗口中列表能够刷新,以显示出刚刚添加的数据,或者一些传递参数,改变某个控件的值等等。当然,完全可以使用暴露属性的方式来完成,但是扩展性比较好的做法是利用事件。在子窗体中发布一个事件,在父窗体中订阅这个事件,当子窗体保存数据后触发这个事件以修改父窗体中的某个控件的值,代码如下:
1:定义委托与委托参数
View Code
代码很简单,声明了一个比较2个数字大小的委托,他通过不同的回调函数来实现了不同的比较行为。结果运行如下
我们打开IL反汇编程序看看在CLR中,委托到底是什么摸样
从IL中看出程序中的CompareHandler被编译成了一个类,并且继承了System.MulticastDelegate这个类(MulticastDelegate派生自Delegate),里面包含了4个方法
第一个为构造器 CompareHandler(Object object, IntPtr method)
第二个 virtual Invoke(int value)
第三个 virtual BeginInvoke(int value,AsyncCallback callback,Object obj)
第四个virtual EndInvoke(IasyncResult result)
这里重点看一下构造函数和Invoke方法,后面2个主要是涉及到异步委托的问题,将会在后面讨论到。
在内部:
因为派生自MulticastDelegate,他其中包含了几个重要的非公有字段。
_target: 委托对象中为非静态方法时保存回调方法的对象,静态方法则为null
_methodPtr: 回调方法的标识
_invocationList:如果为委托链是存储委托数组
如下图
构造函数主要有一个类型为object的参数和一个IntPtr型的methoInfo,从名字可以看出,第一个参数object接收的是委托的回调函数所在那个对象中,例子中如果GraterThan 不是静态的,就是Program的对象,如果是静态的,则为null。第二个参数则是回调函数的引用。构造函数还会做一些其他的处理和初始化,根据委托的类型给invocationList赋值等等。
在外部:
我们知道的Target和Method属性,这2个属性的内部字段这里不用说大家也能猜到,需要说明的是,这个时候Method的类型是MethodInfo,这个也是在内部做了些许转换吧。有了这2个属性,我们又可以做一些检查,比如你可以限制这个委托调用的回调函数必须是某个类的对象的函数,还可以检查回调函数的名称(虽然可能意义不是很大)
Invoke函数:
在上面的代码中,在我们使用handler(items[j - 1], items[j]) 的时候,编译在内部调用了Invoke方法,这里是查看IL可以得出的结论,在Invoke方法内部,他取得_target和_methodPtr的值,然后调用被构造函数包装好了的某个对象上的回调函数。
最后,Invoke方法的签名跟我们的委托的签名是一致的。所以,上面的代码可以被替换为if(handler!=null)
handler.Invoke(items[j - 1], items[j]); 这里的是否为null的判断是必须的
在Winform程序中我们经常有这样一种需求,就是在一个主窗口中,当用户点击添加按钮时弹出一个子窗口,用户输入数据,最后点击保存或者关闭窗口后需要主窗口中列表能够刷新,以显示出刚刚添加的数据,或者一些传递参数,改变某个控件的值等等。当然,完全可以使用暴露属性的方式来完成,但是扩展性比较好的做法是利用事件。在子窗体中发布一个事件,在父窗体中订阅这个事件,当子窗体保存数据后触发这个事件以修改父窗体中的某个控件的值,代码如下:
1:定义委托与委托参数
View Code
/// <summary> /// 比较2个数的大小的委托 /// </summary> /// <param name="first"></param> /// <param name="second"></param> /// <returns></returns> public delegate bool CompareHandler(int first, int second); class Program { static void Main(string[] args) { int[] items = { 1, 2, 26, 32, 13, 5, 6, 9, 12 }; Console.WriteLine("按数字大小排序:"); BubbleSort(items, GraterThan); foreach (int item in items) { Console.WriteLine(item); } Console.WriteLine("按字符方式排序:"); BubbleSort(items, AlphabeticalGraterThan); foreach (int item in items) { Console.WriteLine(item); } Console.Read(); } public static void BubbleSort(int[] items, CompareHandler handler) { for (int i = items.Length - 1; i >= 0; i--) { for (int j = 1; j <= i; j++) { if (handler(items[j - 1], items[j])) { int tmp = items[j - 1]; items[j - 1] = items[j]; items[j] = tmp; } } } } /// <summary> /// 按数字大小排序 /// </summary> /// <param name="first"></param> /// <param name="second"></param> /// <returns></returns> public static bool GraterThan(int first, int second) { return first > second; } /// <summary> /// 按字符方式排序 /// </summary> /// <param name="first"></param> /// <param name="second"></param> /// <returns></returns> public static bool AlphabeticalGraterThan(int first, int second) { return first.ToString().CompareTo(second.ToString()) > 0; } }
代码很简单,声明了一个比较2个数字大小的委托,他通过不同的回调函数来实现了不同的比较行为。结果运行如下
我们打开IL反汇编程序看看在CLR中,委托到底是什么摸样
从IL中看出程序中的CompareHandler被编译成了一个类,并且继承了System.MulticastDelegate这个类(MulticastDelegate派生自Delegate),里面包含了4个方法
第一个为构造器 CompareHandler(Object object, IntPtr method)
第二个 virtual Invoke(int value)
第三个 virtual BeginInvoke(int value,AsyncCallback callback,Object obj)
第四个virtual EndInvoke(IasyncResult result)
这里重点看一下构造函数和Invoke方法,后面2个主要是涉及到异步委托的问题,将会在后面讨论到。
在内部:
因为派生自MulticastDelegate,他其中包含了几个重要的非公有字段。
_target: 委托对象中为非静态方法时保存回调方法的对象,静态方法则为null
_methodPtr: 回调方法的标识
_invocationList:如果为委托链是存储委托数组
如下图
构造函数主要有一个类型为object的参数和一个IntPtr型的methoInfo,从名字可以看出,第一个参数object接收的是委托的回调函数所在那个对象中,例子中如果GraterThan 不是静态的,就是Program的对象,如果是静态的,则为null。第二个参数则是回调函数的引用。构造函数还会做一些其他的处理和初始化,根据委托的类型给invocationList赋值等等。
在外部:
我们知道的Target和Method属性,这2个属性的内部字段这里不用说大家也能猜到,需要说明的是,这个时候Method的类型是MethodInfo,这个也是在内部做了些许转换吧。有了这2个属性,我们又可以做一些检查,比如你可以限制这个委托调用的回调函数必须是某个类的对象的函数,还可以检查回调函数的名称(虽然可能意义不是很大)
Invoke函数:
在上面的代码中,在我们使用handler(items[j - 1], items[j]) 的时候,编译在内部调用了Invoke方法,这里是查看IL可以得出的结论,在Invoke方法内部,他取得_target和_methodPtr的值,然后调用被构造函数包装好了的某个对象上的回调函数。
最后,Invoke方法的签名跟我们的委托的签名是一致的。所以,上面的代码可以被替换为if(handler!=null)
handler.Invoke(items[j - 1], items[j]); 这里的是否为null的判断是必须的
相关文章推荐
- 【C#语言基础】--委托(Delegate)(一)
- C#基础-3:委托(Delegate)
- C# 委托Delegate(一) 基础介绍&用法
- C#基础知识六之委托(delegate、Action、Func、predicate)
- C#基础笔记——委托(Delegate)和事件(Event)
- 【C#基础】枚举(Enum)、结构体(Struct)、委托(Delegate)
- 【C#基础知识】——初识委托(delegate)
- c#语言基础(5)----委托
- 017天(.net学习之路-C#基础知识)-委托(delegate)及多播委托
- C#语言基础(一)
- C#语言 第六部分 线程(一)线程基础(2)
- 『C/C++』[C# 基础知识系列]专题一:深入解析委托——C#中为什么要引入委托
- c#语言基础(4)使用var创建隐形局部变量
- C#委托的介绍(delegate、Action、Func、predicate)
- C#中的委托 Delegate(委托 也叫代表,代表一类方法)
- C#委托的介绍(delegate、Action、Func、predicate)
- C#_delegate - 用委托实现事件,Display和Log类都使用Clock对象
- 黑马程序员:C#基础篇(三)委托与事件
- 【C#】delegate(委托) 将方法作为参数在类class 之间传递
- c#的委托用法delegate