gpt4 book ai didi

c# - 用于处理任何事件的通用委托(delegate)类型

转载 作者:太空狗 更新时间:2023-10-29 23:42:37 25 4
gpt4 key购买 nike

我有一个接收两个参数的函数 - 一个对象和一个定义该对象事件的 EventInfo 结构。我需要阻止该功能,直到指定的事件触发。我遇到的问题是,当处理程序的类型可以是任何类型时,如何将委托(delegate)添加到指定的事件?请注意,我不关心结果事件调用的参数,我只需要捕捉它被引发的事实。

我已经尝试使用 EventInfo.AddEventHandler 添加一个真正通用的委托(delegate)类型 (EventHandler),但没有成功。我也尝试过相同的方法,但使用 Activator 创建了 EventInfo.EventHandlerType 属性中指定类型的实例,但没有成功。

或者,如果有人有办法做类似的事情,给定一个对象,以及该对象上的一个事件的名称,那么这也行得通。

我正在使用 C# 和 .NET 2.0。

干杯

最佳答案

解决方案的提示可以使用 MethodBuilder类(class)。使用它,您可以在运行时生成适合 EventInfo 期望的委托(delegate)的方法。

基于它的示例(可以进行许多优化,但它适用于大多数情况):

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,它在事件被触发时被调用。

希望对你有帮助。

关于c# - 用于处理任何事件的通用委托(delegate)类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1565070/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com