5174

Why am I getting an Argument exception when creating event handler dynamically?

Question:

Good day all

I wrote the following method:

private void RegisterEvent(object targetObject, string eventName, string methodName) { EventInfo eventInfo = targetObject.GetType().GetEvent(eventName); MethodInfo method = eventInfo.EventHandlerType.GetMethod("Invoke"); IEnumerable<Type> types = method.GetParameters().Select(param => param.ParameterType); DynamicMethod dynamicMethod = new DynamicMethod(eventInfo.EventHandlerType.Name, typeof (void), types.ToArray(), typeof (QueryWindow)); MethodInfo methodInfo = typeof (QueryWindow).GetMethod(methodName, new[] { typeof (object) }); ILGenerator ilGenerator = dynamicMethod.GetILGenerator(256); ilGenerator.Emit(OpCodes.Ldarg_1); ilGenerator.EmitCall(OpCodes.Call, methodInfo, null); dynamicMethod.DefineParameter(1, ParameterAttributes.In, "sender"); dynamicMethod.DefineParameter(2, ParameterAttributes.In, "e"); // Get an argument exception here Delegate methodDelegate = dynamicMethod.CreateDelegate(eventInfo.EventHandlerType, this); eventInfo.AddEventHandler(targetObject, methodDelegate); }

I get ArgumentException with the message

<blockquote>

Error binding to target method.

</blockquote>

in the line

Delegate methodDelegate = dynamicMethod.CreateDelegate(eventInfo.EventHandlerType, this);

Could anyone point out on my mistake?

Thanks in advance.

Answer1:

Assuming that methodName is a static method of QueryWindow, this should work:

private static void RegisterEvent(object targetObject, string eventName, string methodName) { var eventInfo = targetObject.GetType().GetEvent(eventName); var method = eventInfo.EventHandlerType.GetMethod("Invoke"); var types = method.GetParameters().Select(param => param.ParameterType); var methodInfo = typeof(QueryWindow).GetMethod(methodName, new[] { typeof(object) }); // replaced typeof(void) by null var dynamicMethod = new DynamicMethod(eventInfo.EventHandlerType.Name, null, types.ToArray(), typeof(QueryWindow)); ILGenerator ilGenerator = dynamicMethod.GetILGenerator(256); // Using Ldarg_0 to pass the sender to methodName ; Ldarg_1 to pass the event args ilGenerator.Emit(OpCodes.Ldarg_0); ilGenerator.EmitCall(OpCodes.Call, methodInfo, null); // Added return ilGenerator.Emit(OpCodes.Ret); // Removed parameter definition (implicit from DynamicMethod constructor) // Removed the target argument var methodDelegate = dynamicMethod.CreateDelegate(eventInfo.EventHandlerType); eventInfo.AddEventHandler(targetObject, methodDelegate); }

Edit :

Since you can use .NET 3.5, you should create an expression tree. Here is another solution:

public class QueryWindow { public void RegisterEvent(object targetObject, string eventName, string methodName) { var eventInfo = targetObject.GetType().GetEvent(eventName); var sender = Expression.Parameter(typeof (object), "sender"); var e = Expression.Parameter(typeof (EventArgs), "e"); var body = Expression.Call(Expression.Constant(this), methodName, null, e); var lambda = Expression.Lambda(eventInfo.EventHandlerType, body, sender, e); eventInfo.AddEventHandler(targetObject, lambda.Compile() ); } public void OnEvent(object o) { Console.WriteLine(o); } }

Notice that the OnEvent method is no longer static. I also assume that events you are trying to subscribe to are events that follow .NET conventions (sender + event args). This way, we can leverage contravariance and always pass a lambda of type :

(object sender, EventArgs e) => { /* */ }

Answer2:

<blockquote>

dynamicMethod.CreateDelegate(eventInfo.EventHandlerType, this);

</blockquote>

The <em>this</em> argument cannot be correct. That references your class, the one that generates the dynamic type. Surely you need <em>targetObject</em> instead.

Answer3:

When calling DynamicMethod.CreateDelegate, you should not pass a target parameter.

Edit:

I think you would also have to make the first parameter = 0, and change the codegen accordingly.

Recommend

  • Shared ownership of an str between a HashMap and a Vec
  • When should __method__ be called directly?
  • How can we merge two databases with identical schemas?
  • Android kivy where to put application files (ini, images db etc)
  • How to aggregate objects properties?
  • Unable to establish a neo4j - bolt driver connection in javascript
  • Curl_exec return null in php
  • SQL: How to merge case-insensitive duplicates
  • Parse all the xml files in a directory one by one using ElementTree
  • How to find all files in current directory with filenames that match a certain pattern in python?
  • Comparison operators and 'is' - operator precedence in python?
  • No log messages in production.log
  • Angular 2 final - change route parameter on the URL programmatically
  • cobertura-maven-plugin with Java 8
  • Disable all but one checkbox
  • Angular2 linq style property accessor
  • Warning: Memcache::get() [memcache.get]: Node no longer exists
  • Increment counter with Cloud Functions for Firebase
  • PHP dependency class
  • Sub-Matrix computations
  • Normalize a table with tightly coupled data
  • Git Merge Branches Conflict Marker Resolution
  • Test fails, how to find out why?
  • VBA code can't access to DLL in System32
  • How to extract details from the xml files using java?
  • ORA-02253: constraint specification not allowed here
  • submit a comment on Instagram posts using jQuery or pure javascript
  • In Bootstrap 3's table-responsive when below breakpoint dropdown menus can't be used, any
  • BouncyCastle on the server side with Android phones as clients
  • AWS RDS Parameter Group not changing MySQL encoding
  • Debug `Unexpected end of JSON input Error` on content script
  • Bad automatic Triangulation with Mayavi for coloring a surface known only by its corner
  • Using Service Component Runtime
  • How to handle a codeigniter PDF generator