菜鸟之旅——认识委托与事件
这个是我刚入行第一个感兴趣的知识点,翻了翻不知道什么时候记的笔记,觉得有必要把自己学的知识在梳理一遍,有一些点比当时更清晰;在这里,先将一位大牛的博客贴出来,有兴趣的可以去看看,很详细的介绍了委托与事件,读了几遍受益匪浅:
本文实例是在VS2013下实现的
初识委托
刚刚学习委托可能会有些困惑,不知道委托是什么,怎么用,有什么好处,下面我会通过一个简单的场景来进行说明。
场景:假设下某人班回到家,依次打开灯,打开热水器,打开电视。
我们先定义一个房子:
public class House { public void OpenLight() { Console.WriteLine("打开灯!"); } public void OpenHeater() { Console.WriteLine("打开热水器!"); } public void OpenTV() { Console.WriteLine("打开电视!"); } }
将方法当作参数传递
下面我们先利用委托来进行执行开灯、开热水器、开电视的操作,我们先定义一个无参数无返回值的委托(事实上.NET已经有一个内置的Action委托),在创建一个打开电器的方法:
delegate void OpenMachineHandle(); static void OpenMachine(OpenMachineHandle openHandle) { openHandle(); }
然后我们就可以这样来实现打开电器:
static void Main(string[] args) { House house = new House(); Console.WriteLine("开门回家......"); OpenMachine(house.OpenLight); OpenMachine(house.OpenHeater); OpenMachine(house.OpenTV); Console.ReadLine(); }
我们可以看到我们是将House的三个实例方法当作参数来进行传递,不过有人会说,这个我们可以直接调用方法来进行实现啊?你看这还多了一个OpenMachine的方法不是?现在假设不是用委托,并且只能用OpenMachine的方法打开电器(这种的需求会有的,比方说OpenMachine是我作为第三方发布的接口),里面使用了if-else或switch来进行分辨;但是,改需求了XD,增加打开洗衣机了,这样子我的接口也需要变化以适应新的需求,再发布,需求再变动那岂不是改的没完没了?
这里我们直接打开电器方法当作参数来使用,以后增加新的打开电器犯法就可以不用修改OpenMachine这个统一入口,只是在主程序里面增加一行调用即可;这样子可以在某些场景下还可以减少使用if-else或switch语句,在一定程度上解耦程序,使得程序具有更好的可扩展性。
委托绑定多个方法
当然,委托也可以绑定多个方法(静态方法、实例方法都可以,只要参数与返回值与委托的一样即可),以上程序我们还可以这么改,我们可以无视掉OpenMachine这个统一入口,然后实例化一个委托,直接将打开电器方法直接绑定到委托上面,然后让这个实例代我们执行所有绑定好的方法,实例化还有另外的方法,不过+=是增加绑定,-=是移除绑定,这些是一定的。
static void Main(string[] args) { House house = new House(); Console.WriteLine("开门回家......"); OpenMachineHandle openHandle = house.OpenLight; openHandle += house.OpenHeater; openHandle += house.OpenTV; openHandle(); Console.ReadLine(); }
从委托到事件
在面向对象中,讲究对对象的封装,我们可以将delegate的实例封装到一个类中,这样可以更方便的在客户端中使用,这里建立一个Person类:
public class Person { public string Name { get; set; } public OpenMachineHandle openMachineHandle; public void OpenMachine() { if (openMachineHandle != null) openMachineHandle(); } }
我们就可以这样使用委托:
static void Main(string[] args) { House house = new House(); Person caster = new Person(); caster.Name = "Caster"; caster.openMachineHandle = house.OpenLight; caster.openMachineHandle += house.OpenHeater; caster.openMachineHandle += house.OpenTV; Console.WriteLine("{0}开门回家......", caster.Name); caster.OpenMachine(); Console.ReadLine(); }
看到这里大家可能会觉得稍微有些问题,openMachineHandle第一次绑定方法是=赋值语法,后面的才会变为+=注册的方式,还有这里直接使用了openMachineHandle这一个委托变量,但是在面向对象中,不是所有的成员变量都可以公布出来的,对于普通的成员变量来说,可以使用属性来进行封装,但是委托变量使用属性还是解决不了第一个问题,于是就可以使用事件event来对委托进行封装了,这样,我们改写Person类:
public class Person { public string Name { get; set; } public event OpenMachineHandle OpenMachine; public void OpenDoor() { OpenMachine(); } }
声明事件的同时会默认构造一个私有的OpenMachineHandle委托(就行上面声明一个Name属性时会默认构造一个私有变量一样),详细可以翻阅上面大牛的博客,我也正在研究中;改写完毕之后,我们再重新在主程序里面使用:
static void Main(string[] args) { House house = new House(); Person caster = new Person(); caster.Name = "Caster"; caster.OpenMachine += house.OpenLight; caster.OpenMachine += house.OpenHeater; caster.OpenMachine += house.OpenTV; Console.WriteLine("{0}开门回家......", caster.Name); caster.OpenDoor(); Console.ReadLine(); }
这里我们就可以直接使用+=注册方法来绑定想要执行的事件,前面我说过OpenMachineHandle这个委托是无参数无返回值的,那么OpenMachineHandle这个可以完全的换成Action这一个内置委托。
.NET内置委托介绍
delegate关键字
delegate我们常用到的一种声明
delegate至少0个参数,至多32个参数,可以无返回值,也可以指定返回值类型。
例:public delegate int MethodtDelegate(int x, int y);表示有两个参数,并返回int型。
Action
Action是无返回值的泛型委托。
Action 表示无参,无返回值的委托
Action<int,string> 表示有传入参数int,string无返回值的委托
Action<int,string,bool> 表示有传入参数int,string,bool无返回值的委托
Action<int,int,int,int> 表示有传入4个int型参数,无返回值的委托
Action至少0个参数,至多16个参数,无返回值。
例:
public void Test<T>(Action<T> action,T p)
{
action(p);
}
Func
Func是有返回值的泛型委托
Func<int> 表示无参,返回值为int的委托
Func<object,string,int> 表示传入参数为object, string 返回值为int的委托
Func<object,string,int> 表示传入参数为object, string 返回值为int的委托
Func<T1,T2,,T3,int> 表示传入参数为T1,T2,,T3(泛型)返回值为int的委托
Func至少0个参数,至多16个参数,根据返回值泛型返回。必须有返回值,不可void
例:
public int Test<T1,T2>(Func<T1,T2,int>func,T1 a,T2 b)
{
return func(a, b);
}
predicate
predicate 是返回bool型的泛型委托
predicate<int> 表示传入参数为int 返回bool的委托
predicate有且只有一个参数,返回值固定为bool
例:public delegate bool Predicate<T> (T obj)
总结
我对于委托的学习总结就暂时到此结束,东西不是很多,更深层的代码实现和设计思想还有待学习,希望能给对于委托还不了解的人有一定的帮助!