C#中的事件其实就是一个特殊的多播委托。
委托
- C#中的委托类似于C/C++中的函数指针,
- 委托(Delegate)特别用于实现事件和回调方法。
- 所有的委托(Delegate)都派生自 System.Delegate 类
- 声明委托
public delegate int MyDelegate(string a); //上面的委托可被用于引用任何一个带有一个单一的 string 参数的方法,并返回一个 int 类型变量。
- 实例化&使用
using System; delegate int NumberChanger(int n); namespace DelegateAppl { class TestDelegate { static int num = 10; public static int AddNum(int p) { num += p; return num; } public static int MultNum(int q) { num *= q; return num; } public static int getNum() { return num; } static void Main(string[] args) { // 创建委托实例 NumberChanger nc1 = new NumberChanger(AddNum); NumberChanger nc2 = new NumberChanger(MultNum); // 使用委托对象调用方法 nc1(25); Console.WriteLine("Value of Num: {0}", getNum()); nc2(5); Console.WriteLine("Value of Num: {0}", getNum()); Console.ReadKey(); } } }
- 委托的多播
委托对象可使用 “+” 运算符进行合并。一个合并委托调用它所合并的两个委托。
只有相同类型的委托可被合并。
“-” 运算符可用于从合并的委托中移除组件委托。
// 创建委托实例 NumberChanger nc; NumberChanger nc1 = new NumberChanger(AddNum); NumberChanger nc2 = new NumberChanger(MultNum); nc = nc1; nc += nc2; // 调用多播 nc(5); Console.WriteLine("Value of Num: {0}", getNum());//两个函数都被调用,并且都传入相同参数 Console.ReadKey();
- 委托的多播
事件
- 事件(Event) 基本上说是一个用户操作,如按键、点击、鼠标移动等等,或者是一些提示信息,如系统生成的通知。
- 应用程序需要在事件发生时响应事件。例如,中断。
- C# 中使用事件机制实现线程间的通信。
- 通过事件使用委托
事件在类中声明且生成,且通过使用同一个类或其他类中的委托与事件处理程序关联。包含事件的类用于发布事件。这被称为 发布器(publisher) 类。其他接受该事件的类被称为 订阅器(subscriber) 类。事件使用 发布-订阅(publisher-subscriber) 模型。 - 发布器(publisher) 是一个包含事件和委托定义的对象。事件和委托之间的联系也定义在这个对象中。发布器(publisher)类的对象调用这个事件,并通知其他的对象。
- 订阅器(subscriber) 是一个接受事件并提供事件处理程序的对象。在发布器(publisher)类中的委托调用订阅器(subscriber)类中的方法(事件处理程序)。
- 事件的声明
声明事件需要先声明该事件的委托类型public Delegate void MyDelegate(string a); //基于上面的委托定义事件 public event MyDelegate MyEvent;
- 事件的使用
using System; namespace SimpleEvent { using System; /***********发布器类***********/ public class EventTest { private int value; public delegate void NumManipulationHandler(); public event NumManipulationHandler ChangeNum; protected virtual void OnNumChanged() { if (ChangeNum != null) { ChangeNum(); /* 事件被触发 */ } else { Console.WriteLine("event not fire"); Console.ReadKey(); /* 回车继续 */ } } public EventTest() { int n = 5; SetValue(n); } public void SetValue(int n) { if (value != n) { value = n; OnNumChanged(); } } } /***********订阅器类***********/ public class subscribEvent { public void printf() { Console.WriteLine("event fire"); Console.ReadKey(); /* 回车继续 */ } } /***********触发***********/ public class MainClass { public static void Main() { EventTest e = new EventTest(); /* 实例化对象,第一次没有触发事件 */ subscribEvent v = new subscribEvent(); /* 实例化对象 */ e.ChangeNum += new EventTest.NumManipulationHandler(v.printf); /* 注册 */ e.SetValue(7); e.SetValue(11); } } }