詳解C#委託與事件

Y00發表於2024-07-11

image

在C#中,委託是一種引用型別的資料型別,允許我們封裝方法的引用。透過使用委託,我們可以將方法作為引數傳遞給其他方法,或者將多個方法組合在一起,從而實現更靈活的程式設計模式。委託類似於函式指標,但提供了型別安全和垃圾回收等現代語言特性。

基本概念

定義委託

定義委託需要指定它所代表的方法的原型,包括返回型別和引數列表。例如:

public delegate int MyDelegate(int a, int b);

這定義了一個名為MyDelegate的委託,它代表一個接受兩個整數引數並返回一個整數的方法。

建立委託例項

建立委託例項時,可以使用new關鍵字加上委託型別和要封裝的方法名:

MyDelegate myDelegate = new MyDelegate(AddNumbers);

其中AddNumbers是一個符合MyDelegate定義的方法。

呼叫委託

一旦有了委託例項,就可以像呼叫方法一樣呼叫它:

int result = myDelegate(5, 3);

多播委託

委託可以被設計為“多播”的,這意味著它們可以呼叫多個方法。當呼叫多播委託時,所有註冊的方法都會按順序執行:

MyDelegate del1 = new MyDelegate(AddNumbers);
MyDelegate del2 = new MyDelegate(MultiplyNumbers);
MyDelegate combinedDel = del1 + del2;
combinedDel(5, 3); // 先呼叫 AddNumbers, 然後呼叫 MultiplyNumbers

匿名方法和Lambda表示式

從C# 2.0開始,可以使用匿名方法來定義委託:

MyDelegate anonMethod = delegate(int x, int y) { return x + y; };

而在C# 3.0之後,Lambda表示式成為更簡潔的選擇:

MyDelegate lambdaExpr = (int x, int y) => x + y;

事件

在C#中,事件是一種特殊的委託型別,用於封裝訊息的傳送機制,通常用於元件之間或物件之間的通訊。事件是.NET框架中處理非同步操作、UI互動和訊號通知的核心機制。下面詳細介紹事件的概念、定義和使用。

事件的基本概念

事件允許一個類(事件釋出者)向另一個或多個類(事件訂閱者)廣播資訊,而無需直接呼叫接收方的任何方法。這實現了釋出者和訂閱者之間的解耦,使得程式碼更加模組化和可維護。

定義事件

事件基於委託型別定義,通常使用System.EventHandler或自定義的委託型別。定義事件時,通常在類中宣告一個委託型別的私有欄位,並在此基礎上宣告一個公共的事件屬性。例如:

public class Publisher
{
    // 自定義委託型別
    public delegate void MyEventHandler(object source, MyEventArgs args);

    // 定義事件
    private event MyEventHandler myEvent;

    // 使用事件屬性暴露事件
    public event MyEventHandler MyEvent
    {
        add { myEvent += value; }
        remove { myEvent -= value; }
    }

    // 觸發事件
    public void RaiseEvent()
    {
        if (myEvent != null)
        {
            myEvent(this, new MyEventArgs());
        }
    }
}

在這個例子中,Publisher類有一個名為MyEvent的事件,它基於MyEventHandler委託型別。事件觸發時,RaiseEvent方法會被呼叫,它會檢查是否有訂閱者,並呼叫所有訂閱者的相應方法。

訂閱和取消訂閱事件

事件可以透過事件處理程式來訂閱。事件處理程式是一個與事件委託型別匹配的方法。訂閱事件時,將事件處理程式新增到事件中;取消訂閱則移除該處理程式。

class Subscriber
{
    public void OnMyEvent(object sender, MyEventArgs e)
    {
        Console.WriteLine("Event triggered.");
    }
}

// 在某個地方訂閱事件
Publisher publisher = new Publisher();
Subscriber subscriber = new Subscriber();
publisher.MyEvent += subscriber.OnMyEvent;

// 取消訂閱事件
publisher.MyEvent -= subscriber.OnMyEvent;

使用事件引數

事件經常與事件引數一起使用,這些引數通常封裝了事件發生時的附加資訊。事件引數是透過繼承EventArgs類來建立的。例如:

public class MyEventArgs : EventArgs
{
    public string Message { get; set; }
}

在觸發事件時,可以建立事件引數的例項並傳遞給事件:

public void RaiseEvent()
{
    if (myEvent != null)
    {
        myEvent(this, new MyEventArgs { Message = "Hello, world!" });
    }
}

相關文章