1.委托
委托类型的声明与方法签名相似, 有一个返回值和任意数目任意类型的参数:
public delegate void TestDelegate(string message); public delegate int TestDelegate(MyType m, long num);
delegate 是一种可用于封装命名或匿名方法的引用类型。 委托类似于 C++ 中的函数指针;但是,委托是类型安全和可靠的。
委托是事件的基础。
通过将委托与命名方法或匿名方法关联,可以实例化委托。 有关更多信息,请参见命名方法和匿名方法。
必须使用具有兼容返回类型和输入参数的方法或 lambda 表达式实例化委托。 有关方法签名中允许的差异程度的更多信息,请参见委托中的变体(C# 和 Visual Basic)。 为了与匿名方法一起使用,委托和与之关联的代码必须一起声明
示例:
// Declare delegate -- defines required signature: delegate double MathAction(double num); class DelegateTest { // Regular method that matches signature: static double Double(double input) { return input * 2; } static void Main() { // Instantiate delegate with named method: MathAction ma = Double; // Invoke delegate ma: double multByTwo = ma(4.5); Console.WriteLine(multByTwo); // Instantiate delegate with anonymous method: MathAction ma2 = delegate(double input) { return input * input; }; double square = ma2(5); Console.WriteLine(square); // Instantiate delegate with lambda expression MathAction ma3 = s => s * s * s; double cube = ma3(4.375); Console.WriteLine(cube); } }
2事件
类或对象可以通过事件向其他类或对象通知发生的相关事情。 发送(或引发)事件的类称为“发行者”,接收(或处理)事件的类称为“订户”。
在典型的 C# Windows 窗体或 Web 应用程序中,可订阅由控件(如按钮和列表框)引发的事件。 可使用 Visual C# 集成开发环境 (IDE) 来浏览控件发布的事件,选择要处理的事件。 IDE 会自动添加空事件处理程序方法和订阅事件的代码。 有关更多信息,请参见如何:订阅和取消订阅事件(C# 编程指南)。
事件具有以下特点:
3引发事件
发行者确定何时引发事件,订户确定执行何种操作来响应该事件。
一个事件可以有多个订户。 一个订户可处理来自多个发行者的多个事件。
没有订户的事件永远也不会引发。
事件通常用于通知用户操作,例如,图形用户界面中的按钮单击或菜单选择操作。
如果一个事件有多个订户,当引发该事件时,会同步调用多个事件处理程序。 要异步调用事件,请参见使用异步方式调用同步方法。
可以利用事件同步线程。
在 .NET Framework 类库中,事件是基于 EventHandler 委托和 EventArgs 基类的。
如果希望您的类引发一个事件,您需要提供以下三个元素:
提供事件数据的类。
事件委托。
引发事件的类。
定义提供事件数据的类public class AlarmEventArgs : EventArgs { private DateTime alarmTime; private bool snoozeOn = true; public AlarmEventArgs(DateTime time) { this.alarmTime = time; } public DateTime Time { get { return this.alarmTime; } } public bool Snooze { get { return this.snoozeOn; } set { this.snoozeOn = value; } } }定义事件的委托public delegate void AlarmEventHandler(object sender, AlarmEventArgs e);定义引发事件的类public event AlarmEventHandler AlarmEvent;定义事件实现后,您必须确定引发事件的时间。 通过在定义事件的类或派生类中调用受保护的 OnEventName 方法来引发事件。 随后,OnEventName方法引发事件。
受保护的 OnEventName方法也允许派生类重写事件,而不必向其附加委托。 派生类必须始终调用基类的 OnEventName方法以确保注册的委托接收到事件。
下面的示例定义负责引发 AlarmEvent 事件的 OnAlarmEvent 方法。
protected void OnAlarmEvent(AlarmEventArgs e) {下面的示例定义名为 Set 的方法,该方法包含通过调用 OnAlarmEvent 方法来引发事件的逻辑。if (AlarmEvent!= null)AlarmEvent(this, e); }public void Set() { while (true) { System.Threading.Thread.Sleep(2000); DateTime currentTime = DateTime.Now; // Test whether it is time for the alarm to go off. if (currentTime.Hour == alarmTime.Hour && currentTime.Minute == alarmTime.Minute) { AlarmEventArgs args = new AlarmEventArgs(currentTime); OnAlarmEvent(args); if (! args.Snooze) return; else this.alarmTime = this.alarmTime.AddMinutes(this.interval); } } }4完整示例其他资源
using System; namespace EventSample { // Class that contains the data for // the alarm event. Derives from System.EventArgs. // public class AlarmEventArgs : EventArgs { private bool snoozePressed; private int nrings; //Constructor. // public AlarmEventArgs(bool snoozePressed, int nrings) { this.snoozePressed = snoozePressed; this.nrings = nrings; } // The NumRings property returns the number of rings // that the alarm clock has sounded when the alarm event // is generated. // public int NumRings { get { return nrings;} } // The SnoozePressed property indicates whether the snooze // button is pressed on the alarm when the alarm event is generated. // public bool SnoozePressed { get {return snoozePressed;} } // The AlarmText property that contains the wake-up message. // public string AlarmText { get { if (snoozePressed) { return ("Wake Up!!! Snooze time is over."); } else { return ("Wake Up!"); } } } } // Delegate declaration. // public delegate void AlarmEventHandler(object sender, AlarmEventArgs e); // The Alarm class that raises the alarm event. // public class AlarmClock { private bool snoozePressed = false; private int nrings = 0; private bool stop = false; // The Stop property indicates whether the // alarm should be turned off. // public bool Stop { get {return stop;} set {stop = value;} } // The SnoozePressed property indicates whether the snooze // button is pressed on the alarm when the alarm event is generated. // public bool SnoozePressed { get {return snoozePressed;} set {snoozePressed = value;} } // The event member that is of type AlarmEventHandler. // public event AlarmEventHandler Alarm; // The protected OnAlarm method raises the event by invoking // the delegates. The sender is always this, the current instance // of the class. // protected virtual void OnAlarm(AlarmEventArgs e) { AlarmEventHandler handler = Alarm; if (handler != null) { // Invokes the delegates. handler(this, e); } } // This alarm clock does not have // a user interface. // To simulate the alarm mechanism it has a loop // that raises the alarm event at every iteration // with a time delay of 300 milliseconds, // if snooze is not pressed. If snooze is pressed, // the time delay is 1000 milliseconds. // public void Start() { for (;;) { nrings++; if (stop) { break; } else { if (snoozePressed) { System.Threading.Thread.Sleep(1000); } else { System.Threading.Thread.Sleep(300); } AlarmEventArgs e = new AlarmEventArgs(snoozePressed, nrings); OnAlarm(e); } } } } // The WakeMeUp class has a method AlarmRang that handles the // alarm event. // public class WakeMeUp { public void AlarmRang(object sender, AlarmEventArgs e) { Console.WriteLine(e.AlarmText +"\n"); if (!(e.SnoozePressed)) { if (e.NumRings % 10 == 0) { Console.WriteLine(" Let alarm ring? Enter Y"); Console.WriteLine(" Press Snooze? Enter N"); Console.WriteLine(" Stop Alarm? Enter Q"); String input = Console.ReadLine(); if (input.Equals("Y") ||input.Equals("y")) { return; } else if (input.Equals("N") || input.Equals("n")) { ((AlarmClock)sender).SnoozePressed = true; return; } else { ((AlarmClock)sender).Stop = true; return; } } } else { Console.WriteLine(" Let alarm ring? Enter Y"); Console.WriteLine(" Stop Alarm? Enter Q"); String input = Console.ReadLine(); if (input.Equals("Y") || input.Equals("y")) { return; } else { ((AlarmClock)sender).Stop = true; return; } } } } // The driver class that hooks up the event handling method of // WakeMeUp to the alarm event of an Alarm object using a delegate. // In a forms-based application, the driver class is the // form. // public class AlarmDriver { public static void Main(string[] args) { // Instantiates the event receiver. WakeMeUp w = new WakeMeUp(); // Instantiates the event source. AlarmClock clock = new AlarmClock(); // Wires the AlarmRang method to the Alarm event. clock.Alarm += new AlarmEventHandler(w.AlarmRang); clock.Start(); } } }