Buu*_*yen 7 .net c# events delegates cil
我想创建一个可用于处理任何事件或委托的处理程序.具体来说,我希望能够编写如下代码:
class Invoker
{
public object Invoke(object[] arg)
{
// generic handling code
}
}
static void Main()
{
var p = new Person();
p.AddHandler("Event1", new Invoker().Invoke);
}
Run Code Online (Sandbox Code Playgroud)
AddHandler是一种扩展方法,object用于接收事件名称和类型委托Func<object[], object>.它应该能够做任何魔术来将事件(例如Event1在这种情况下)绑定到提供的委托,以便在触发事件时调用委托.
签名Event1无关紧要,因为它AddHandler应该适用于所有类型的事件(和代理).
我怀疑这可能涉及一些CIL生成来构建匹配指定事件类型的动态委托(例如Event1)并将调用转发给指定的委托(例如new Invoker().Invoke).我能够构建这样一个动态委托,但是它只能转发到静态方法,而不是实例方法,因为我找不到将待调用方法的绑定实例推送到CLR堆栈的方法(即Invoker示例中的实例).请参阅下面提供的代码以清楚地查看此问题(请参阅标有ISSUE的行).
如果有人能指出一种方法来改进动态生成代码以捕获绑定对象或更好,建议一个更简单的解决方案,不需要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);
}
Run Code Online (Sandbox Code Playgroud)
这是使用表达式树的实现:
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();
}
Run Code Online (Sandbox Code Playgroud)