Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a delegate from a MethodInfo when method signature cannot be known beforehand?

I need a method that takes a MethodInfo instance representing a non-generic static method with arbitrary signature and returns a delegate bound to that method that could later be invoked using Delegate.DynamicInvoke method. My first naïve try looked like this:

using System; using System.Reflection;  class Program {     static void Main()     {         var method = CreateDelegate(typeof (Console).GetMethod("WriteLine", new[] {typeof (string)}));         method.DynamicInvoke("Hello world");     }      static Delegate CreateDelegate(MethodInfo method)     {         if (method == null)         {             throw new ArgumentNullException("method");         }          if (!method.IsStatic)         {             throw new ArgumentNullException("method", "The provided method is not static.");         }          if (method.ContainsGenericParameters)         {             throw new ArgumentException("The provided method contains unassigned generic type parameters.");         }          return method.CreateDelegate(typeof(Delegate)); // This does not work: System.ArgumentException: Type must derive from Delegate.     } } 

I hoped that the MethodInfo.CreateDelegate method could figure out the correct delegate type itself. Well, obviously it cannot. So, how do I create an instance of System.Type representing a delegate with a signature matching the provided MethodInfo instance?

like image 813
Zakharia Stanley Avatar asked May 03 '13 17:05

Zakharia Stanley


People also ask

What is signature in delegate C#?

A delegate is a type that represents references to methods with a particular parameter list and return type. When you instantiate a delegate, you can associate its instance with any method with a compatible signature and return type. You can invoke (or call) the method through the delegate instance.

How do you pass parameters to delegates?

You can pass methods as parameters to a delegate to allow the delegate to point to the method. Delegates are used to define callback methods and implement event handling, and they are declared using the “delegate” keyword. You can declare a delegate that can appear on its own or even nested inside a class.


2 Answers

You can use System.Linq.Expressions.Expression.GetDelegateType method:

using System; using System.Linq; using System.Linq.Expressions; using System.Reflection;  class Program {     static void Main()     {         var writeLine = CreateDelegate(typeof(Console).GetMethod("WriteLine", new[] { typeof(string) }));         writeLine.DynamicInvoke("Hello world");          var readLine = CreateDelegate(typeof(Console).GetMethod("ReadLine", Type.EmptyTypes));         writeLine.DynamicInvoke(readLine.DynamicInvoke());     }      static Delegate CreateDelegate(MethodInfo method)     {         if (method == null)         {             throw new ArgumentNullException("method");         }          if (!method.IsStatic)         {             throw new ArgumentException("The provided method must be static.", "method");         }          if (method.IsGenericMethod)         {             throw new ArgumentException("The provided method must not be generic.", "method");         }          return method.CreateDelegate(Expression.GetDelegateType(             (from parameter in method.GetParameters() select parameter.ParameterType)             .Concat(new[] { method.ReturnType })             .ToArray()));     } } 

There is probably a copy-paste error in the 2nd check for !method.IsStatic - you shouldn't use ArgumentNullException there. And it is a good style to provide a parameter name as an argument to ArgumentException.

Use method.IsGenericMethod if you want to reject all generic methods and method.ContainsGenericParameters if you want to reject only generic methods having unsubstituted type parameters.

like image 180
Oksana Gimmel Avatar answered Sep 18 '22 19:09

Oksana Gimmel


You may want to try System.LinQ.Expressions

... using System.Linq.Expressions; ...  static Delegate CreateMethod(MethodInfo method) {     if (method == null)     {         throw new ArgumentNullException("method");     }      if (!method.IsStatic)     {         throw new ArgumentException("The provided method must be static.", "method");     }      if (method.IsGenericMethod)     {         throw new ArgumentException("The provided method must not be generic.", "method");     }      var parameters = method.GetParameters()                            .Select(p => Expression.Parameter(p.ParameterType, p.Name))                            .ToArray();     var call = Expression.Call(null, method, parameters);     return Expression.Lambda(call, parameters).Compile(); } 

and use it later as following

var method = CreateMethod(typeof (Console).GetMethod("WriteLine", new[] {typeof (string)})); method.DynamicInvoke("Test Test"); 
like image 23
Khoa Nguyen Avatar answered Sep 20 '22 19:09

Khoa Nguyen