DynamicMethod.CreateDelegate 的异常,几乎相同的 MSDN 示例
当我调用 CreateDelegate(delegateType) 时,我得到一个 System.ArgumentException ,根据 MSDN,这是因为 delegateType 的参数数量错误或参数类型错误。
奇怪的是我使用的代码几乎都是从 MSDN 复制的。我的整体功能:
public static void AssertRaisesEvent(Action action, object obj, string eventName, NumberOfTimes numberOfTimesRaised)
{
eventCounter = 0;
EventInfo eventInfo = obj.GetType().GetEvent(eventName);
Type tDelegate = eventInfo.EventHandlerType;
Type returnType = GetDelegateReturnType(tDelegate);
if (returnType != typeof(void))
throw new ApplicationException("Delegate has a return type.");
var handler =
new DynamicMethod("CompletedHandler",
typeof(int),
GetDelegateParameterTypes(tDelegate),
obj.GetType());
// Generate a method body. This method loads a string, calls
// the Show method overload that takes a string, pops the
// return value off the stack (because the handler has no
// return type), and returns.
//
ILGenerator ilgen = handler.GetILGenerator();
FieldInfo counterFieldInfo = typeof (AssertionHelpers).GetField("eventCounter",
BindingFlags.NonPublic | BindingFlags.Static);
ilgen.Emit(OpCodes.Ldfld, counterFieldInfo);
ilgen.Emit(OpCodes.Ldc_I4, 1);
ilgen.Emit(OpCodes.Add);
ilgen.Emit(OpCodes.Pop);
ilgen.Emit(OpCodes.Ret);
// Complete the dynamic method by calling its CreateDelegate
// method. Use the "add" accessor to add the delegate to
// the invocation list for the event.
//
var delParams = GetDelegateParameterTypes(tDelegate);
var handlerParams = handler.GetParameters();
Delegate dEmitted = handler.CreateDelegate(tDelegate);
eventInfo.GetAddMethod().Invoke(obj, new Object[] { dEmitted });
...
正如你所看到的,评论甚至在那里。正如您还可以看到的,我有 delParams 和 handlerParams 变量,它们具有相同数量、相同类型的参数。
这是怎么回事?
MSDN:http://msdn.microsoft.com/en-us/library/ms228976 .aspx
编辑: 我试图绑定的事件:
private NullTransaction transaction;
public delegate void CompletedEventHandler(object testParam);
internal class NullTransaction : ITransaction
{
public event CompletedEventHandler Completed;
public void Dispose()
{
// no implementation
}
public void Complete()
{
// no implementation
if(Completed != null)
Completed.Invoke(this);
}
}
When i call CreateDelegate(delegateType) i get a System.ArgumentException
, which according to MSDN is because the delegateType has the wrong number of parameters or the wrong parameter types.
The strange part is the code I'm using is almost all copied from MSDN. My function as whole:
public static void AssertRaisesEvent(Action action, object obj, string eventName, NumberOfTimes numberOfTimesRaised)
{
eventCounter = 0;
EventInfo eventInfo = obj.GetType().GetEvent(eventName);
Type tDelegate = eventInfo.EventHandlerType;
Type returnType = GetDelegateReturnType(tDelegate);
if (returnType != typeof(void))
throw new ApplicationException("Delegate has a return type.");
var handler =
new DynamicMethod("CompletedHandler",
typeof(int),
GetDelegateParameterTypes(tDelegate),
obj.GetType());
// Generate a method body. This method loads a string, calls
// the Show method overload that takes a string, pops the
// return value off the stack (because the handler has no
// return type), and returns.
//
ILGenerator ilgen = handler.GetILGenerator();
FieldInfo counterFieldInfo = typeof (AssertionHelpers).GetField("eventCounter",
BindingFlags.NonPublic | BindingFlags.Static);
ilgen.Emit(OpCodes.Ldfld, counterFieldInfo);
ilgen.Emit(OpCodes.Ldc_I4, 1);
ilgen.Emit(OpCodes.Add);
ilgen.Emit(OpCodes.Pop);
ilgen.Emit(OpCodes.Ret);
// Complete the dynamic method by calling its CreateDelegate
// method. Use the "add" accessor to add the delegate to
// the invocation list for the event.
//
var delParams = GetDelegateParameterTypes(tDelegate);
var handlerParams = handler.GetParameters();
Delegate dEmitted = handler.CreateDelegate(tDelegate);
eventInfo.GetAddMethod().Invoke(obj, new Object[] { dEmitted });
...
As you can see the comments are even there. As you also can see i have delParams and handlerParams variables which have the same number of parameters of the same type.
What is going on here?
MSDN: http://msdn.microsoft.com/en-us/library/ms228976.aspx
EDIT:
The event im trying to bind to:
private NullTransaction transaction;
public delegate void CompletedEventHandler(object testParam);
internal class NullTransaction : ITransaction
{
public event CompletedEventHandler Completed;
public void Dispose()
{
// no implementation
}
public void Complete()
{
// no implementation
if(Completed != null)
Completed.Invoke(this);
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
大多数事件不返回任何内容 - 事实上,您断言它没有返回类型。然后,您将自定义方法 (
handler
) 声明为返回int
,并尝试将其绑定到不返回 int 的委托。这行不通。还;您的堆栈对于返回 int 无效,因为您“弹出”结果。
即我创建了一个测试
并与其绑定;那么在这里:
您会发现
tDelegate
是EventHandler
。这与返回int
的handler
不匹配。重新堆栈(注释);考虑一下:
您已经加载了两个值,将它们相加,丢弃结果,然后返回。但您尚未返回您声明的
int
- 这将导致 IL 检查失败。如果您更改:
和:
那么它可能会按您的预期工作。
还;这更简单:
Most events don't return anything - in fact you assert that it has no return-type. You then declare your custom method (
handler
) as returningint
, and try to bind it to a delegate that doesn't return an int. This won't work.Also; your stack isn't valid for returning an int, since you "pop" the result.
i.e. I created a test with
and bound to it; so then here:
you'll find that
tDelegate
isEventHandler
. That doesn't matchhandler
, which returnsint
.Re the stack (comments); consider:
You've loaded two values, added them up, thrown the result away, and then returned. But you haven't returned the
int
that you claim to - this will fail IL inspection.If you change:
and:
then it might work as you intend.
Also; this is simpler: