[英]Add and remove event handler via reflection c#
美好的一天! 我的目的是實現類,該類將允許我們向(從)事件訂閱和取消訂閱對象。 這是我班上的代碼。
public static class EventSubscriber
{
public static void AddEventHandler(EventInfo eventInfo, object item, Action action)
{
var parameters = GetParameters(eventInfo);
var handler = GetHandler(eventInfo, action, parameters);
eventInfo.AddEventHandler(item, handler);
}
public static void RemoveEventHandler(EventInfo eventInfo,
object item, Action action)
{
var parameters = GetParameters(eventInfo);
var handler = GetHandler(eventInfo, action, parameters);
eventInfo.RemoveEventHandler(item, handler);
}
private static ParameterExpression[] GetParameters(EventInfo eventInfo)
{
return eventInfo.EventHandlerType
.GetMethod("Invoke")
.GetParameters()
.Select(parameter => Expression.Parameter(parameter.ParameterType))
.ToArray();
}
private static Delegate GetHandler(EventInfo eventInfo,
Action action, ParameterExpression[] parameters)
{
return Expression.Lambda(
eventInfo.EventHandlerType,
Expression.Call(Expression.Constant(action),
"Invoke", Type.EmptyTypes), parameters)
.Compile();
}
}
如您所見,這里有2個公共方法,它們實際上向(從)事件訂閱和取消訂閱對象。 這是我如何測試的示例
class Program
{
static void Main()
{
Test test = new Test();
test.SubscribeTimer();
while (true)
{
if(test.a == 10)
{
break;
}
}
test.UnsubscribeTimer();
while (true)
{
}
}
}
class Test
{
System.Timers.Timer timer;
public int a = 0;
public Test()
{
timer = new System.Timers.Timer(1000);
timer.Start();
}
public void SubscribeTimer()
{
var eventInfo = typeof(System.Timers.Timer).GetEvent("Elapsed");
EventSubscriber.AddEventHandler(eventInfo, timer, TimerElapsed);
EventSubscriber.RemoveEventHandler(eventInfo, timer, TimerNotElapsed);
}
public void UnsubscribeTimer()
{
var eventInfo = typeof(System.Timers.Timer).GetEvent("Elapsed");
EventSubscriber.AddEventHandler(eventInfo, timer, TimerNotElapsed);
EventSubscriber.RemoveEventHandler(eventInfo, timer, TimerElapsed);
}
public void TimerElapsed()
{
Console.WriteLine("timer elapsed");
a++;
}
public void TimerNotElapsed()
{
Console.WriteLine("timer not elapsed");
a++;
}
}
樣本的預期行為是,在一開始,我們將每秒看到消息“計時器已過去”,在10秒之后,我們應該僅看到“計時器未過去”,但是,我們仍然看到“計時器已過去”。 這意味着AddEventHandler方法有效,但RemoveEventHandler方法無效。
如果您能幫助我,我將非常高興。 提前致謝。
我認為這是因為您每次都在創建一個新的處理程序:( 與先前的處理程序不匹配,因此無法從調用列表中刪除)
public static void RemoveEventHandler(EventInfo eventInfo,
object item, Action action)
{
var parameters = GetParameters(eventInfo);
var handler = GetHandler(eventInfo, action, parameters); // <--
eventInfo.RemoveEventHandler(item, handler);
}
你為什么要包裝Action
? 要丟失參數? 無法添加/刪除eventInfo.RemoveEventHandler(item, action);
由於參數。 如果要刪除新生成的處理程序,則在刪除它時應返回該處理程序。
public static Delegate AddEventHandler(EventInfo eventInfo, object item, Action action)
{
var parameters = GetParameters(eventInfo);
var handler = GetHandler(eventInfo, action, parameters);
eventInfo.AddEventHandler(item, handler);
return handler;
}
public static void RemoveEventHandler(EventInfo eventInfo,
object item, Delegate handler)
{
eventInfo.RemoveEventHandler(item, handler);
}
var handler = EventSubscriber.AddEventHandler(eventInfo, timer, TimerElapsed);
EventSubscriber.RemoveEventHandler(eventInfo, timer, handler);
為了將我需要的東西縫合在一起,需要一站式擴展方法(如果我們更換組件供應商,可以輕松修改),以清除我們無法控制的事件上的所有現有事件處理程序。
用法很簡單:
thirdPartyControlInstance.ClearEventHandlers(nameof(ThirdPartyControlType.ToolClick));
這是代碼,歡迎提出任何使其更健壯/高效/清潔的建議:
public static class EventExtensions
{
public static void ClearEventHandlers(this object obj, string eventName)
{
if (obj == null)
{
return;
}
var objType = obj.GetType();
var eventInfo = objType.GetEvent(eventName);
if (eventInfo == null)
{
return;
}
var isEventProperty = false;
var type = objType;
FieldInfo eventFieldInfo = null;
while (type != null)
{
/* Find events defined as field */
eventFieldInfo = type.GetField(eventName, BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (eventFieldInfo != null && (eventFieldInfo.FieldType == typeof(MulticastDelegate) || eventFieldInfo.FieldType.IsSubclassOf(typeof(MulticastDelegate))))
{
break;
}
/* Find events defined as property { add; remove; } */
eventFieldInfo = type.GetField("EVENT_" + eventName.ToUpper(), BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic);
if (eventFieldInfo != null)
{
isEventProperty = true;
break;
}
type = type.BaseType;
}
if (eventFieldInfo == null)
{
return;
}
if (isEventProperty)
{
// Default Events Collection Type
RemoveHandler<EventHandlerList>(obj, eventFieldInfo);
// Infragistics Events Collection Type
RemoveHandler<EventHandlerDictionary>(obj, eventFieldInfo);
return;
}
if (!(eventFieldInfo.GetValue(obj) is Delegate eventDelegate))
{
return;
}
// Remove Field based event handlers
foreach (var d in eventDelegate.GetInvocationList())
{
eventInfo.RemoveEventHandler(obj, d);
}
}
private static void RemoveHandler<T>(object obj, FieldInfo eventFieldInfo)
{
var objType = obj.GetType();
var eventPropertyValue = eventFieldInfo.GetValue(obj);
if (eventPropertyValue == null)
{
return;
}
var propertyInfo = objType.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance)
.FirstOrDefault(p => p.Name == "Events" && p.PropertyType == typeof(T));
if (propertyInfo == null)
{
return;
}
var eventList = propertyInfo?.GetValue(obj, null);
switch (eventList) {
case null:
return;
case EventHandlerDictionary typedEventList:
typedEventList.RemoveHandler(eventPropertyValue, typedEventList[eventPropertyValue]);
break;
}
}
}
希望這對某人有幫助!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.