gpt4 book ai didi

c# - 在 C# 中为所有事件和委托(delegate)创建一个包罗万象的处理程序

转载 作者:太空狗 更新时间:2023-10-29 20:22:01 24 4
gpt4 key购买 nike

我想创建一个可用于处理任何事件或委托(delegate)的处理程序。具体来说,我希望能够编写如下代码:

class Invoker
{
public object Invoke(object[] arg)
{
// generic handling code
}
}

static void Main()
{
var p = new Person();
p.AddHandler("Event1", new Invoker().Invoke);
}

AddHandlerobject 的扩展方法它接收事件名称和类型为 Func<object[], object> 的委托(delegate).它应该能够施展魔法将事件(例如本例中的 Event1)绑定(bind)到提供的委托(delegate),以便在触发事件时调用委托(delegate)。

Event1的签名应该没关系因为AddHandler应该适用于所有类型的事件(和委托(delegate))。

我怀疑这可能涉及一些 CIL 生成以构建与指定事件类型匹配的动态委托(delegate)(例如 Event1 )并将调用转发给指定的委托(delegate)(例如 new Invoker().Invoke )。我能够构建这样一个动态委托(delegate),但是它只能转发到静态方法,而不是实例方法,因为我找不到将要调用方法的绑定(bind)实例推送到 CLR 堆栈(即Invoker 示例中的实例)。请参阅下面提供的代码以清楚地看到此问题(请参阅标有 ​​ISSUE 的行)。

如果有人能指出一种改进动态生成代码以捕获绑定(bind)对象或更好的方法,建议一个不需要 CIL 的更简单的解决方案,那么我们将不胜感激。

public static void AddHandler(this object target, string fieldName,
Func<object[], object> func)
{
var eventInfo = target.GetType().GetEvent(fieldName);
if (eventInfo != null)
{
Type delegateType = eventInfo.EventHandlerType;
var dynamicHandler = BuildDynamicHandler(target.GetType(), delegateType, func);
eventInfo.GetAddMethod().Invoke(target, new Object[] { dynamicHandler });
}
}

public static Delegate BuildDynamicHandler(this Type delegateOwnerType, Type delegateType,
Func<object[], object> func)
{
MethodInfo invokeMethod = delegateType.GetMethod("Invoke");
Type returnType = invokeMethod.ReturnType;
bool hasReturnType = returnType != Constants.VoidType;
var paramTypes = invokeMethod.GetParameters().Select(p => p.ParameterType).ToArray();
var dynamicMethod = new DynamicMethod("add_handler",
hasReturnType ? returnType : null, paramTypes, delegateOwnerType);

var il = new EmitHelper(dynamicMethod.GetILGenerator());
if (paramTypes.Length == 0)
{
il.ldnull.end();
}
else
{
il.DeclareLocal(typeof(object[]));
il.ldc_i4(paramTypes.Length);
il.newarr(typeof(object));
il.stloc_0.end();
for (int i = 0; i < paramTypes.Length; i++)
{
il.ldloc_0
.ldc_i4(i)
.ldarg(i)
.boxIfValueType(paramTypes[i])
.stelem_ref.end();
}
il.ldloc_0.end();
}

/////// ****************** ISSUE: work for static method only
il.call(func.Method);
if (hasReturnType)
{
il.unbox_any(returnType).ret();
}
else
{
il.pop.ret();
}
return dynamicMethod.CreateDelegate(delegateType);
}

最佳答案

这是一个使用表达式树的实现:

    public static Delegate BuildDynamicHandle(Type delegateType, Func<object[], object> func)
{
var invokeMethod = delegateType.GetMethod("Invoke");
var parms = invokeMethod.GetParameters().Select(parm => Expression.Parameter(parm.ParameterType, parm.Name)).ToArray();
var instance = func.Target == null ? null : Expression.Constant(func.Target);
var converted = parms.Select(parm => Expression.Convert(parm, typeof(object)));
var call = Expression.Call(instance, func.Method, Expression.NewArrayInit(typeof(object), converted));
var body =
invokeMethod.ReturnType == typeof(void) ? (Expression)call : Expression.Convert(call, invokeMethod.ReturnType);
var expr = Expression.Lambda(delegateType, body, parms);
return expr.Compile();
}

关于c# - 在 C# 中为所有事件和委托(delegate)创建一个包罗万象的处理程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5658765/

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