委托
1.什么是委托?
委托是安全的函数指针,所谓的安全是指它的参数的类型是确定的,它的参数的个数是固定的。委托是一种数据类型,它和类是同级的,委托的是对方法的一种抽象,使用委托可以将方法作为参数进行传递。
2.委托的使用步骤
(1)定义委托类型,一般约定 “名称+delegate”来命名委托
public delegate void GreetDelegate(string msg);
(2)使用委托定义委托变量
GreetDelegate greetDelegate;
(3)为委托变量赋值
greetDelegate =new GreetDelegate(ChineseSayHello);
或者
greetDelegate=ChineseSayHello;(这一步也就是相当于事件中的订阅事件)
public void ChineseSayHello(string msg)
{
Console.WriteLine(msg);
}
(4).调用委托
greetDelegate("世界你好");//相当于事件中的发布事件
greetDelegate.Invoke(“世界你好2”);
3.委托的应用
(1)在前面也已经稍微的描述过了,就是构成了一种调用机制——发布订阅机制,一方可以通过委托监视另一方,当一方被调用的时候绑定的委托的方法也随之调用,这种应用已经完全的被事件所代替,事件更加的安全在实现的过程中,因为事件是不允许使用“=”,这样就可以避免将已经订阅的方法掩盖。
(2)另一种重要的应用,也是委托的核心,就是可以将函数作为参数进行传递,所以说委托是对方法的一种抽象啊
举例:
现在我有两种问候的方式1.helloworld 2.世界你好
如何简单的实现既可以英文的问候,又可以中式的问候呢?现在有一种简单的实现方案就是使用switch...case 或者使用if语句进行判断然后选择合适的问候方法进行调用。
现在使用更加简单的方法,可以更好将两种问候结合,那就是将抽象出委托作为上面两种方法的代表,同时作为方法的参数进行传递。
public void Greet(GreetDelegate greetDelegate ,string name )
{
greetDelegate(name);
}
public void EnglishSayHello(string name)
{
Console.Writeline(name+":"+"HelloWord");
}
public void ChineseSayHello(string name )
{
Console.Writeline(name+":" +"世界你好")
}
如同上面的代码所示,是不是更加的简洁呢。
4.多播委托
多播委托也就是发布订阅机制,使用+=和-=,实现订阅和退订
greetDelegate=ChineseSayHello;
greetDelegate+=EnglishSayHello;
注意点:多播委托的时候最好使用的是没有返回值的方法进行订阅,因为多播委托的返回值只有一个,也就是将最后一个订阅的方法的返回值返回回来。
注意点2:使用+=之前,必须先使用=,否则将出现编译错误(使用了未赋值的局部变量)
5.匿名方法
顾名思义就是没有函数名只有函数体的方法,这类方法用来只被调用一次,为了节省代码,使用匿名函数,但是在编译的时候,最终会为这个函数体生成默认的方法名,所以使用匿名函数的影响就是会使的程序变慢,当然这点效率的影响是微不足道的
举例:
greetDelegate=delegate(string msg){Console.Writeline(msg);};
greetDelegate("世界你好");
6.Lambda表达式
有了Lambda表达式后,可以更加方便的表示委托,首先对于匿名函数的函数体来说,首先存在一个关键字delegate,显得有些多余,同时还有变量的类型,都显得有些多余,所以在引入了Lambda表达式可以更加简洁的来书写,编译器遵循内部的约定,可以将变量的类型自动进行判断。
所以将上面的例子进行进一步的修改
greetDelegate=(ms)=>{Console.Writeline(msg);};
事件
事件可以说是一种特殊的委托,它使用关键字event对委托的变量进行封装,使得委托在其类的内部是private,也就是不允许使用=,而是只可以使用开放的接口+=和-=,事件的命名规范:On+名称
public Delegate void greetDelegate(string msg);
public event greetDelegate ongreetDelegate;
事件机制可以更加完善委托中对于发布订阅的机制,首先保证内部的私有化,禁止使用=,其次不允许订阅者(客户端)发布事件(调用事件),这样会直接报错的,只允许事件的发布者内部调用,将事件发布,订阅者至于允许订阅,符合发布订阅的机制。
注意:必须保证发布事件之后,一定有订阅事件的,否则将会出现空引用的错误
举例:
public Delegate void greetDelegate(string msg);
public class Publisher
{
public event greetDelegate OnGreetDelegate;
public void Do()
{
//doSomething
if(OnGreetDelegate!=null)//说明已经有客户端订阅了
{
OnGreetDelegate(“有人订阅了事件”);//发布事件,必须保证有订阅的,否则就出问题喽,并且只能发布者内部发布事件哦
}
}
当外部的类进行使用订阅这个事件的时候,只可以订阅,不可以发布,也就是说不可以使用OnGreetDelegate("xxx")
}