在我的单元测试中,我试图动态包装一个事件,以便在转发到实际处理程序之前注入一些测试代码。这就是我现在所拥有的:
Delegate handler = // the original method handler
object myObject = // the original object
EventInfo ei = myObject.GetType().GetEvent("MyEvent");
Delegate d = GenerateWrappedDelegate(ei);
ei.AddEventHandler(myObject, d);
...
private GenerateWrappedDelegate(EventInfo eventInfo)
{
var eventHandlerType = eventInfo.EventHandlerType;
int arity = eventHandlerType.GetMethod("Invoke").GetParameters().Count();
var methodName = string.Format("Arity{0}", arity);
var eventRegisterMethod = typeof(EventMonitor).GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance);
return Delegate.CreateDelegate(eventHandlerType, this, eventRegisterMethod);
}
private void Arity1(object arg1)
{
Handle(() => handler.DynamicInvoke(arg1));
}
private void Arity2(object arg1, object arg2)
{
Handle(() => handler.DynamicInvoke(arg1, arg2));
}
private void Handle(Action action)
{
// Do something interesting here, before the original event handler is called
action();
}
我有很多这些Arity
方法,因为我事先不知道我的事件会有多少参数,我想将它们全部传递给原始委托。
如果我的事件处理程序委托看起来像这样,所有这些都可以正常工作:
public delegate void MyDelegate(object sender, EventArgs e);
public event MyDelegate MyEvent;
然而,我们代码库中的一些委托看起来并不像“传统”事件处理程序,而是更像这样:
public delegate void MyOtherDelegate(object sender, int updatedValue);
public event MyOtherDelegate MyOtherEvent;
然后,我的代码突然不再工作了;它在int
.
我通过在其中添加一个复杂的if
语句GenerateWrappedDelegate
并添加Arity
方法来解决这个问题,如下所示:
private void Arity2oo(object arg1, object arg2)
{
Handle(() => handler.DynamicInvoke(arg1, arg2));
}
private void Arity2oi(object arg1, int arg2)
{
Handle(() => handler.DynamicInvoke(arg1, arg2));
}
但这显然不能很好地扩展,而且非常多余。
我一直在研究生成此处描述的动态方法,但这让我更加困惑。我不熟悉 MSIL,而且我不知道如何生成一个方法体,该方法体根据它们的运行时类型加载所有参数,并调用DynamicInvoke
它们中的每一个。我想它看起来不会很漂亮。
我们正在使用 .NET 4.0,所以我也一直在研究dynamic
,但我也无法找到一种方法来实现它。
我没主意了。你有什么?