我有一个接收两个参数的函数 - 一个对象,以及一个定义该对象上事件的EventInfo结构。我需要阻止该函数,直到指定的事件触发。我遇到的问题是,当处理程序的类型可能是什么时,如何向指定的事件添加委托?请注意,我不关心那个结果事件调用的参数,我只需要抓住它被引发的事实。
我已经尝试使用EventInfo.AddEventHandler添加一个非常通用的委托类型(EventHandler
),但无济于事。我也尝试了同样的方法,但是使用Activator
来创建EventInfo.EventHandlerType
属性中指定类型的实例,但没有快乐。
或者,如果有人有办法做类似的事情,给定一个对象,以及该对象上的事件名称,那么这也可以。
我正在使用C#和.NET 2.0。
干杯
答案 0 :(得分:2)
解决方案的提示可以使用MethodBuilder类。使用它,您可以在运行时生成一个适合EventInfo期望的委托的方法。
基于它的示例(可以完成许多优化,但它适用于大多数情况):
namespace AutoEventListener
{
using System;
using System.Linq;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
public class EventExample
{
public static event EventHandler MyEvent;
public void Test()
{
bool called;
var eventInfo = GetType().GetEvent("MyEvent");
EventFireNotifier.GenerateHandlerNorifier(eventInfo,
callbackEventInfo =>
{
called = true;
});
MyEvent(null, null);;
}
}
public class EventFireNotifier
{
static private readonly Dictionary<int, EventInfo> eventsMap = new Dictionary<int, EventInfo>();
static private readonly Dictionary<int, Action<EventInfo>> actionsMap = new Dictionary<int, Action<EventInfo>>();
static private int lastIndexUsed;
public static MethodInfo GenerateHandlerNorifier(EventInfo eventInfo, Action<EventInfo> action)
{
MethodInfo method = eventInfo.EventHandlerType.GetMethod("Invoke");
AppDomain myDomain = AppDomain.CurrentDomain;
var asmName = new AssemblyName(){Name = "HandlersDynamicAssembly"};
AssemblyBuilder myAsmBuilder = myDomain.DefineDynamicAssembly(
asmName,
AssemblyBuilderAccess.RunAndSave);
ModuleBuilder myModule = myAsmBuilder.DefineDynamicModule("DynamicHandlersModule");
TypeBuilder typeBuilder = myModule.DefineType("EventHandlersContainer", TypeAttributes.Public);
var eventIndex = ++lastIndexUsed;
eventsMap.Add(eventIndex, eventInfo);
actionsMap.Add(eventIndex, action);
var handlerName = "HandlerNotifierMethod" + eventIndex;
var parameterTypes = method.GetParameters().Select(info => info.ParameterType).ToArray();
AddMethodDynamically(typeBuilder, handlerName, parameterTypes, method.ReturnType, eventIndex);
Type type = typeBuilder.CreateType();
MethodInfo notifier = type.GetMethod(handlerName);
var handlerDelegate = Delegate.CreateDelegate(eventInfo.EventHandlerType, notifier);
eventInfo.AddEventHandler(null, handlerDelegate);
return notifier;
}
public static void AddMethodDynamically(TypeBuilder myTypeBld, string mthdName, Type[] mthdParams, Type returnType, int eventIndex)
{
MethodBuilder myMthdBld = myTypeBld.DefineMethod(
mthdName,
MethodAttributes.Public |
MethodAttributes.Static,
returnType,
mthdParams);
ILGenerator generator = myMthdBld.GetILGenerator();
generator.Emit(OpCodes.Ldc_I4, eventIndex);
generator.EmitCall(OpCodes.Call, typeof(EventFireNotifier).GetMethod("Notifier"), null);
generator.Emit(OpCodes.Ret);
}
public static void Notifier(int eventIndex)
{
var eventInfo = eventsMap[eventIndex];
actionsMap[eventIndex].DynamicInvoke(eventInfo);
}
}
}
类 EventFireNotifier 注册 EventInfo Action ,在事件被触发时调用。
我希望它有所帮助。
答案 1 :(得分:0)
我不完全理解这个问题,也许代码示例可能更好。但有人认为你可以做的是添加一个无参数的委托作为事件处理程序。无论定义的事件的委托类型如何,这都将起作用。
someobject.someevent += delegate{ // do whatever;}