关于C#中委托的一点理解
C#中委托是一种类型。可以这么笼统的理解:int型变量代表一个整型,而委托类型的变量代表一个方法的地址(将方法名称传入constructor并实例化该委托变量)。
--By Brisk Yu
1 为何要使用委托
我觉得网上关于什么现实生活的举例并不好,还是要从程序的本质去理解:
1)程序是由事件驱动的。
2)事件发生时,操作系统需要知道事件对应的处理函数。例如,用户按下鼠标时操作系统需要知道此时该做什么,是关闭窗口呢,还是打开某个文件呢?当网卡接收到数据包时操作系统也需要知道此时该做什么,是往上层传输呢,还是丢弃呢?
3)因此,我们需要将事件对应的处理函数提前告知操作系统(向操作系统注册),操作系统在发生该事件时,调用对应的处理函数,这便是回调,对应的处理函数也被称为回调函数。
4)那么我们如何向操作系统注册回调函数呢(如何让操作系统知道发生对于事件它该干嘛呢)?对于C++,我们使用pointer,而对于C#,我们使用delegate。
2 如何使用委托
先从最基本的创建委托的方法开始,逐步变换为使用匿名方法和lambda expression。
1)最原始用法,用方法名初始化一个委托类型变量,调用该委托类型变量,执行承载的方法:
public delegate int SomeDelegate(int i); int SomeFunction1(int i) { Console.WriteLine("func1"+i); return 3; } 。。。Main Function { SomeDelegate sd = new SomeDelegate(SomeFunction1); sd(2); }
2)如1)中,如果我们使用委托都需要定义一个委托类型比较麻烦,因此我们使用匿名委托:
删去1)中的
public delegate int SomeDelegate(int i);
并将main function中的代码改为:
Func<int, int> sd= new Func<int, int>(SomeFunction1); sd(2);
Func和Action是C#为我们定义好了委托类型。Func指有返回参数的委托类型,其<>中最后一个参数既是返回参数的类型;Action指无返回参数的委托类型。
3)既然定义委托类型的代码可以拿掉,那么相应的方法声明与定义的语句也可以拿掉:
删去1)中的方法声明与定义的语句:
int SomeFunction1(int i) {
Console.WriteLine("func1"+i);
return 3;
}
将main function 中的代码改为:
Func<int, int> sd = new Func<int, int>(delegate (int s) { Console.WriteLine("匿名方法" + s); return 88; }); int i = sd(2);
此时,Func()中的代码称为匿名方法,即没有方法名。
4)我们对3)中的代码进一步修改,将匿名方法改为lambda表达式。(lambda表达式是匿名方法的一种表示方法)
将mian function中的代码改为:
Func<int, int> sd = new Func<int, int>(s=> { Console.WriteLine("匿名方法"+s); return 88; }); int i = sd(2);
此时,对于lambda表达式,编译器会自动判断其类型,因此无需特指其类型。
3 实际应用
我们参考一下winform中鼠标点击事件响应是如何实现的
1)在System命名空间中定义一个委托类型
namespace System { // // 摘要: // 表示将用于处理不具有事件数据的事件的方法。 // // 参数: // sender: // 事件源。 // // e: // 不包含事件数据的对象。 [ComVisible(true)] public delegate void EventHandler(object sender, EventArgs e); }
2)在Control.cs(所有控件的父类)中定义一个EventHandler型的委托Click
public event EventHandler Click;
注:这里用到了event关键字,表明这个委托是一个事件。其实是指一簇委托。如果理解不了姑且将event拿掉来看。
3)编写鼠标点击事件响应代码
private void buttonStart_Click(object sender, EventArgs e) { //TODO }
4)用3)中方法实例化一个委托赋给Click
this.buttonStart.Click += new System.EventHandler(this.buttonStart_Click);
至此,程序便可以响应buttonStart这个按钮的响应事件了。更加具体的操作会深入到操作系统中,这里不再叙述。
--By Brisk Yu