大家好,我是沙漠盡頭的狼!
在 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();
- 註冊無參委派事件
透過欄位名稱找到 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.");
}
- 註冊帶一個字串參數的委派事件
類似地,找到 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}");
}
- 註冊帶兩個參數的委派事件
對於 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}");
}
- 註冊 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}");
}
四、觸發事件並驗證註冊
為了驗證事件是否成功註冊,我們呼叫 TestClass 的 CallEvent 方法,該方法將觸發所有已註冊的事件。如果一切正常,我們將在控制台上看到對應的輸出訊息,證明事件處理程式被正確呼叫。
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事件呼叫成功
五、總結
透過以上步驟,我們成功地動態註冊了第三方庫定義的事件。這種方法在處理不可預知或無法修改的第三方庫時非常有用,因為它允許我們在執行時動態地加入或移除事件處理程式。
希望本文能夠幫助大家更好地理解如何動態註冊第三方庫事件,並在實際開發中靈活應用。如有任何疑問或建議,請隨時留言交流!