【C#進階】動態註冊第三方庫事件,輕鬆搞定!附詳細步驟與範例

【C#進階】動態註冊第三方庫事件,輕鬆搞定!附詳細步驟與範例

在C#開發過程中,我們經常需要處理各種事件,有時候還需要動態地註冊第三方庫定義的事件。今天,我將為大家分享一個關於如何動態註冊第三方庫事件的Demo,並根據提供的程式碼和註解,詳細講解每一步驟。

最後更新 2024/2/3 下午10:57
沙漠尽头的狼
預計閱讀 6 分鐘
分類
.NET
標籤
.NET C# 事件註冊

大家好,我是沙漠盡頭的狼!

在 C# 開發過程中,我們經常需要處理各種事件,有時候還需要動態地註冊第三方庫定義的事件。今天,我將為大家分享一個關於如何動態註冊第三方庫事件的 Demo,並根據提供的程式碼和註解,詳細講解每一步驟。希望透過這篇文章,大家能夠更好地掌握動態註冊事件的方法,為開發工作帶來更多便利。

在 C# 中,事件是一種特殊的成員,用於提供類別或物件狀態變更的通知。有時候,我們需要在使用第三方庫時,動態地註冊這些庫定義的事件,以便在事件發生時執行對應的動作。

下面,我們將透過一個 Demo 來示範如何實現動態註冊第三方庫事件。

一、準備工作

首先,我們需要一個第三方庫的範例程式碼。在這個範例中,我們有一個名為 ThirdLibrary 的庫,其中包含一個名為 TestClass 的類別。這個類別定義了幾個事件和委派,我們將動態地為它們加入處理程式。

namespace ThirdLibrary;

public class TestClass
{
    /// <summary>
    /// 無參委派
    /// </summary>
    public Action? NoParamEvent;

    /// <summary>
    /// 帶1個string參數
    /// </summary>
    public Action<string>? OneParamEvent;

    /// <summary>
    /// 帶1個基本類型和自訂類型的委派
    /// </summary>
    public Action<string, EventParam>? TwoParamEvent;

    /// <summary>
    /// EventHandler事件
    /// </summary>
    public static event EventHandler<EventParam> EventHandlerEvent;

    public void CallEvent()
    {
        NoParamEvent?.Invoke();
        OneParamEvent?.Invoke("單參數委派");
        TwoParamEvent?.Invoke("2個參數委派呼叫成功", new EventParam() { Message = "帥哥,你成功呼叫啦!" });
        EventHandlerEvent?.Invoke(this, new EventParam { Message = "EventHandler事件呼叫成功"});
    }
}

/// <summary>
/// 自訂類型,註冊時需要使用dynamic接收
/// </summary>
public class EventParam
{
    public string Message { get; set; }
}

二、載入第三方庫並建立實例

首先,我們使用 Assembly.LoadFrom 方法載入第三方庫。然後,透過 Assembly.GetType 方法取得 TestClass 的類型,並使用 Activator.CreateInstance 方法建立其實例。

using System.Reflection;

// 載入第三方庫  
var assembly = Assembly.LoadFrom("ThirdLibrary.dll");

// 建立 TestClass 的實例  
var testClassType = assembly.GetType("ThirdLibrary.TestClass");
var testClassInstance = Activator.CreateInstance(testClassType!);

三、動態註冊事件

接下來,我們將透過反射動態地註冊事件。首先,透過 Type.GetFields 方法取得 TestClass 類型的所有欄位,並找到對應的事件欄位。

var fields = testClassType!.GetFields();
  1. 註冊無參委派事件

透過欄位名稱找到 NoParamEvent 欄位,並使用 FieldInfo.SetValue 方法將事件處理程式方法 EventHandlerMethod 賦值給該欄位。這樣,當 NoParamEvent 事件被觸發時,EventHandlerMethod 方法將被呼叫。

// 1、取得 NoParamEvent 委派  
var noParamEventField = fields.First(field => "NoParamEvent" == field.Name);
noParamEventField.SetValue(testClassInstance, EventHandlerMethod);

// NoParamEvent 事件處理程式方法  
void EventHandlerMethod()
{
    Console.WriteLine("NoParamEvent: event raised.");
}
  1. 註冊帶一個字串參數的委派事件

類似地,找到 OneParamEvent 欄位,並將其設定為 OneParamEventHandler 方法。這個方法接受一個字串參數,並輸出一則訊息。

// 2、取得 OneParamEvent 委派,並設定事件參數處理程式  
var oneParamEventField = fields.First(field => "OneParamEvent" == field.Name);
oneParamEventField.SetValue(testClassInstance, OneParamEventHandler);

// OneParamEvent 事件處理程式方法,需要一個字串參數  
void OneParamEventHandler(string param)
{
    Console.WriteLine($"OneParamEvent: event raised with parameter: {param}");
}
  1. 註冊帶兩個參數的委派事件

對於 TwoParamEvent 欄位,我們將其設定為 TwoParamEventHandler 方法。由於第二個參數是自訂類型 EventParam,我們無法在編譯時知道其確切類型。因此,我們使用 dynamic 關鍵字作為參數類型,以便在執行時解析類型。

// 3、取得 TwoParamEvent 委派,並設定事件參數處理程式  
var twoParamEventField = fields.First(field => "TwoParamEvent" == field.Name);
twoParamEventField.SetValue(testClassInstance, TwoParamEventHandler);

// TwoParamEvent 事件處理程式方法,需要兩個參數:string 和 EventParam 類型(透過反射傳遞,EventParam 類型使用動態類型 dynamic 取代)  
void TwoParamEventHandler(string param1, dynamic param2) // 使用 dynamic 作為第二個參數的類型,並透過反射傳遞實際參數值  
{
    Console.WriteLine($"TwoParamEvent: event raised, param1={param1}, param2.Param1={param2.Message}");
}
  1. 註冊 EventHandler 事件

對於 EventHandlerEvent 事件,我們使用 Type.GetEvents 方法取得事件資訊,並透過 EventInfo.EventHandlerType 取得事件處理程式的類型。然後,我們建立一個 EventHandler<dynamic> 類型的委派,並使用 Delegate.CreateDelegate 方法建立一個與事件處理程式類型匹配的委派實例。最後,透過 EventInfo.AddEventHandler 方法將委派實例加入到事件中。

var events = testClassType.GetEvents();

// 4、取得 EventHandler 事件
var eventHandlerEventField = events.First(item => "EventHandlerEvent" == item.Name);
var eventHandlerType = eventHandlerEventField.EventHandlerType;
var eventHandlerMethod = new EventHandler<dynamic>(EventHandlerEventHandler);
var handle = Delegate.CreateDelegate(eventHandlerType, eventHandlerMethod.Method);
eventHandlerEventField.AddEventHandler(null, handle);

// EventHandler 事件處理方法
void EventHandlerEventHandler(object sender, dynamic param)
{
    Console.WriteLine($"EventHandler: param.Param1={param.Message}");
}

四、觸發事件並驗證註冊

為了驗證事件是否成功註冊,我們呼叫 TestClassCallEvent 方法,該方法將觸發所有已註冊的事件。如果一切正常,我們將在控制台上看到對應的輸出訊息,證明事件處理程式被正確呼叫。

ThirdLibrary 庫方法:

/// <summary>
/// 該方法用於觸發事件,方便測試
/// </summary>
public void CallEvent()
{
    NoParamEvent?.Invoke();
    OneParamEvent?.Invoke("單參數委派");
    TwoParamEvent?.Invoke("2個參數委派呼叫成功", new EventParam() { Message = "帥哥,你成功呼叫啦!" });
    EventHandlerEvent?.Invoke(this, new EventParam { Message = "EventHandler事件呼叫成功" });
}

觸發上面的事件:

// 5、模擬觸發事件通知,測試事件是否註冊成功
var callEventMethod = testClassType.GetMethods().First(method => "CallEvent" == method.Name);
callEventMethod.Invoke(testClassInstance, null);

程式輸出如下:

NoParamEvent: event raised.
OneParamEvent: event raised with parameter: 單參數委派
TwoParamEvent: event raised, param1=2個參數委派呼叫成功, param2.Param1=帥哥,你成功呼叫啦!
EventHandler: param.Param1=EventHandler事件呼叫成功

五、總結

透過以上步驟,我們成功地動態註冊了第三方庫定義的事件。這種方法在處理不可預知或無法修改的第三方庫時非常有用,因為它允許我們在執行時動態地加入或移除事件處理程式。

希望本文能夠幫助大家更好地理解如何動態註冊第三方庫事件,並在實際開發中靈活應用。如有任何疑問或建議,請隨時留言交流!

繼續探索

延伸閱讀

更多文章
同分類 / 同標籤 2026/2/7

AOT使用經驗總結

從專案建立伊始,就應養成良好的習慣,即只要添加了新功能或使用了較新的語法,就及時進行 AOT 發布測試。

繼續閱讀