一、委托:是一个能够引用方法的对象。创建委托时实际是创建一个方法引用的对象,创建的引用对象能够调用方法。
委托调用可以调用不同的方法,只需改变方法的引用即可。即委托调用方法是运行时确定,而非编译时确定。
就像声名一个object实例一样,声名的只是一个占位符,具体指向哪个对象在运行时可以动态指定。在委托中指定方法有限制:返回值,参数类型要相同。
委托声名:delegate ret-type delegatename(parameter-list)
delegate 关键字声名委托
ret-type是委托返回值类型
delegatename 委托名称
parameter-list 参数列表
委托声名的是一个方法引用对象,被委托引用的方法返回值类型、形参类型必须与委托定义的相同,不限制是静态方法、还是实例方法。
委托示例:
//委托使用静态方法声名 StrMethodDelegate strdelegate = new StrMethodDelegate(StaticMethodClass.StaticStrMethod); //调用方法 string result = strdelegate("HI"); Console.WriteLine(result); //委托使用实例方法声名 InstanceClass instanceClass = new InstanceClass(); StrMethodDelegate instanceDelegate = new StrMethodDelegate(instanceClass.InstanceStrMethod); result = instanceDelegate("Hi");
运行结果:
委托方法组转换:允许简单的为委托指定方法名称,不再使用new或者显示的调用构造函数。实际操作就像是变量赋值一样把方法赋值给方法引用。
委托方法转换示例:
VoidMethodDeleteage voidDelegateone = StaticMethodClass.FirstStaticEmpMethod; voidDelegateone(); VoidMethodDeleteage voidDelegatetwo = new InstanceClass().FirstInstanceEmpMethod; voidDelegatetwo();
运行结果:
委托多播:多播是指委托有创建方法调用列表,方法调用链表的能力。通过+、+=、-、-=运算符为链表添加方法。
示例代码:
VoidMethodDeleteage multi = StaticMethodClass.FirstStaticEmpMethod; multi += StaticMethodClass.SecondStaticEmpMethod; InstanceClass incclass = new InstanceClass(); multi += incclass.FirstInstanceEmpMethod; multi(); multi -= incclass.FirstInstanceEmpMethod; multi();
运行结果:
匿名方法赋值给委托
使用delegate关键字创建匿名方法,可以赋值给委托。
VoidMethodDeleteage delte = delegate { for (int i = 0; i <= 5; i++) { Console.Write(i); Console.Write(" "); } }; delte();
运行结果:
Lambda赋值给委托
StrMethodDelegate delegateInc = n => { return "Lambda ReturnValue:" + n; }; string returnstr = delegateInc("Hello"); Console.WriteLine(returnstr);
运行结果:
使用匿名函数和lambad表达式和实例方法、静态方法一样能够进行方法的调用。
协变、逆变
协变是指:只要方法的返回值类型派于委托声明的返回类型,该方法就可赋值给委托。
逆变是指:只要方法参数的类型是委托声明类的父类,该方法即可赋值给委托。
二、事件:事件是基于委托类型,事件是一种信号机制,通知应用程序操作发生。
工作原理是:如果对象对某事件感兴趣,则对象为事件注册事件的处理程序,事件发生时就会调用注册在事件上的处理程序。
事件声明:使用Event关键字声明事件。
Event event-delegate event-name
Event声明事件关键字
event-delegate 支持事件的委托声明,意思事件的注册程序通过委托来承载。
event-name 具体的事件对象的名称。
事件示例:
delegate void MyEventHandle(); static void Main(string[] args) { EventDemo demo = new EventDemo(); //注册事件 demo.SomeEvent += Handler; //事件发生 demo.OnSomeEvent(); Console.ReadKey(); } public static void Handler() { Console.WriteLine("Event ocurred"); } class EventDemo { public event MyEventHandle SomeEvent; //触发事件 public void OnSomeEvent() { if (SomeEvent != null) { SomeEvent(); } } }
运行结果:
事件多播
事件是基于委托创建,所以事件是支持事件多播。
事件多播示例
EventDemo demo = new EventDemo(); //注册事件 demo.SomeEvent += Handler; //事件多播, demo.SomeEvent += MoreMethod.MoreMethodForEvent; //事件发生 demo.OnSomeEvent(); Console.ReadKey();
运行结果:
事件存取器
事件存取器类似属性存取器操作,通过存取器对事件控制更加灵活。
事件可以使用匿名函数、和Lambda表达式,由于事件基本委托,所以事件的匿名函数、Lambda表达式同委托一样。
.NET事件的指导原则
为了使编写的组件与window兼容,开发人员需要遵循Microsoft建立的指导原则。事件处理程序必须有两个参数,
第一个参数是产生事件的对象的引用,第二个参数为EventArgs类型。
为了使事件遵循指导原则,再声明委托时使用delegate void MyEvent(object sender,EventArgs e),当然如果
委托这么声明,那么委托调用的方法也要这样定义。