如何發佈符合 .NET 指導方針的事件 (C# 程式設計手冊)

下列程序示範如何將遵循標準 .NET 模式的事件,新增至您的類別和結構。 .NET 類別庫中的所有事件均以如下定義的 EventHandler 委派為基礎:

public delegate void EventHandler(object sender, EventArgs e);

注意

.NET Framework 2.0 引進此委派的泛型版本 EventHandler<TEventArgs>。 下列範例示範如何使用這兩種版本。

雖然您所定義之類別中的事件能以任何有效的委派型別 (甚至是傳回值的委派) 為基礎,但通常建議您使用 EventHandler,讓事件以 .NET 模式為基礎,如下列範例所示。

名稱 EventHandler 可能會導致混淆,因為它實際上不會處理事件。 EventHandler, 和泛型 EventHandler<TEventArgs> 均為委派型別。 簽章符合委派定義的方法或 Lambda 運算式是事件處理常式,並在引發事件時叫用。

發佈以 EventHandler 模式為基礎的事件

  1. (如果您不需要傳送事件的自訂資料,請跳過此步驟,並前往步驟 3a。)以發行者和訂閱者類別可見的範圍,宣告自訂資料的類別。 然後新增必要的成員來保存自訂事件資料。 在此範例中,會傳回一個簡單的字串。

    public class CustomEventArgs : EventArgs
    {
        public CustomEventArgs(string message)
        {
            Message = message;
        }
    
        public string Message { get; set; }
    }
    
  2. (如果您要使用 EventHandler<TEventArgs> 的泛型版本,請跳過此步驟。)在發行類別中宣告委派。 指定名稱並以 EventHandler 作為結尾。 第二個參數指定自訂 EventArgs 型別。

    public delegate void CustomEventHandler(object sender, CustomEventArgs args);
    
  3. 使用下列其中一個步驟,在發行類別中宣告事件。

    1. 如果沒有自訂 EventArgs 類別,Event 類型將會是非泛型的 EventHandler 委派。 因為當您建立 C# 專案時所包含的 System 命名空間中已宣告委派,所以您不需要宣告委派。 將下列程式碼新增至發行者類別。

      public event EventHandler RaiseCustomEvent;
      
    2. 如果您使用的是 EventHandler 的非泛型版本,而且有衍生自 EventArgs 的自訂類別,請在發行類別內宣告事件,並使用步驟 2 中的委派作為類型。

      public event CustomEventHandler RaiseCustomEvent;
      
    3. 如果您使用的是泛型版本,則不需要自訂委派。 相反地,您會在發行類別中將事件類型指定為 EventHandler<CustomEventArgs>,來替代角括號之間的類別名稱。

      public event EventHandler<CustomEventArgs> RaiseCustomEvent;
      

範例

下列範例使用自訂 EventArgs 類別和 EventHandler<TEventArgs> 作為事件類型,來示範上述步驟。

using System;

namespace DotNetEvents
{
    // Define a class to hold custom event info
    public class CustomEventArgs : EventArgs
    {
        public CustomEventArgs(string message)
        {
            Message = message;
        }

        public string Message { get; set; }
    }

    // Class that publishes an event
    class Publisher
    {
        // Declare the event using EventHandler<T>
        public event EventHandler<CustomEventArgs> RaiseCustomEvent;

        public void DoSomething()
        {
            // Write some code that does something useful here
            // then raise the event. You can also raise an event
            // before you execute a block of code.
            OnRaiseCustomEvent(new CustomEventArgs("Event triggered"));
        }

        // Wrap event invocations inside a protected virtual method
        // to allow derived classes to override the event invocation behavior
        protected virtual void OnRaiseCustomEvent(CustomEventArgs e)
        {
            // Make a temporary copy of the event to avoid possibility of
            // a race condition if the last subscriber unsubscribes
            // immediately after the null check and before the event is raised.
            EventHandler<CustomEventArgs> raiseEvent = RaiseCustomEvent;

            // Event will be null if there are no subscribers
            if (raiseEvent != null)
            {
                // Format the string to send inside the CustomEventArgs parameter
                e.Message += $" at {DateTime.Now}";

                // Call to raise the event.
                raiseEvent(this, e);
            }
        }
    }

    //Class that subscribes to an event
    class Subscriber
    {
        private readonly string _id;

        public Subscriber(string id, Publisher pub)
        {
            _id = id;

            // Subscribe to the event
            pub.RaiseCustomEvent += HandleCustomEvent;
        }

        // Define what actions to take when the event is raised.
        void HandleCustomEvent(object sender, CustomEventArgs e)
        {
            Console.WriteLine($"{_id} received this message: {e.Message}");
        }
    }

    class Program
    {
        static void Main()
        {
            var pub = new Publisher();
            var sub1 = new Subscriber("sub1", pub);
            var sub2 = new Subscriber("sub2", pub);

            // Call the method that raises the event.
            pub.DoSomething();

            // Keep the console window open
            Console.WriteLine("Press any key to continue...");
            Console.ReadLine();
        }
    }
}

另請參閱