委托和事件

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# 编程指南)

事件具有以下特点:

  • 发行者确定何时引发事件,订户确定执行何种操作来响应该事件。

  • 一个事件可以有多个订户。 一个订户可处理来自多个发行者的多个事件。

  • 没有订户的事件永远也不会引发。

  • 事件通常用于通知用户操作,例如,图形用户界面中的按钮单击或菜单选择操作。

  • 如果一个事件有多个订户,当引发该事件时,会同步调用多个事件处理程序。 要异步调用事件,请参见使用异步方式调用同步方法

  • 可以利用事件同步线程。

  • 在 .NET Framework 类库中,事件是基于 EventHandler 委托和 EventArgs 基类的。

3引发事件

如果希望您的类引发一个事件,您需要提供以下三个元素:

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)
{
if (AlarmEvent!= null)
AlarmEvent(this, e); }
下面的示例定义名为 Set 的方法,该方法包含通过调用 OnAlarmEvent 方法来引发事件的逻辑。
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();
        }
    }
}
原文地址:https://www.cnblogs.com/yellowsail/p/1951339.html