Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Builds a Delegate from MethodInfo?

After googling and landing on SO and having read this other question

Is it possible to build a correct Delegate from a MethodInfo if you didn't know the number or types of parameters at compile time?

More on this: can this be done elegantly without the use of Reflection.Emit or type builders?

This is sorta a bummer for me because Delegate.CreateDelegate requires me to specify the correct Delegate type as the first parameter or else it would throw exceptions or invoke an incorrect method.

I'm building some ninja gears and this would helps a lot... Thanks!


Here's a generic solution:

/// <summary> /// Builds a Delegate instance from the supplied MethodInfo object and a target to invoke against. /// </summary> public static Delegate ToDelegate(MethodInfo mi, object target) {     if (mi == null) throw new ArgumentNullException("mi");      Type delegateType;      var typeArgs = mi.GetParameters()         .Select(p => p.ParameterType)         .ToList();      // builds a delegate type     if (mi.ReturnType == typeof(void)) {         delegateType = Expression.GetActionType(typeArgs.ToArray());      } else {         typeArgs.Add(mi.ReturnType);         delegateType = Expression.GetFuncType(typeArgs.ToArray());     }      // creates a binded delegate if target is supplied     var result = (target == null)         ? Delegate.CreateDelegate(delegateType, mi)         : Delegate.CreateDelegate(delegateType, target, mi);      return result; } 

Note: I am building a Silverlight application that would replace a built-years-ago javascript application in which I have multiple Javascript interfaces that calls into the same Silverlight [ScriptableMember] method.

All those legacy JS interfaces need to be supported as well as new interface for accessing new features, so something that automatically setups the JS interface and "delegates" the call to the right Silverlight method would helps speed up work a lot.

I can't post code here, so that's the summary.

like image 954
chakrit Avatar asked Jul 14 '09 10:07

chakrit


People also ask

How do you call a delegate in C#?

Delegates can be invoke like a normal function or Invoke() method. Multiple methods can be assigned to the delegate using "+" or "+=" operator and removed using "-" or "-=" operator. It is called multicast delegate. If a multicast delegate returns a value then it returns the value from the last assigned target method.

What is MethodInfo C#?

The MethodInfo class represents a method of a type. You can use a MethodInfo object to obtain information about the method that the object represents and to invoke the method.

What is generic delegates?

A delegate can define its own type parameters. Code that references the generic delegate can specify the type argument to create a closed constructed type, just like when instantiating a generic class or calling a generic method, as shown in the following example: C# Copy.


2 Answers

To be honest, if you don't know the type at compile time, there isn't a huge amount of benefit in creating a Delegate. You don't want to use DynamicInvoke; it will be about as slow as reflection. The main exception to this is when there is a delegate-type lurking in the shadows, for example when subscribing to an event - in which case EventInfo makes this available.

For info, in .NET 3.5 on Expression, there is:

Expression.GetActionType(params Type[] typeArgs); Expression.GetFuncType(params Type[] typeArgs) 

That might help to an extent:

using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Reflection; static class Program {     static void Main() {         DoStuff("Test1");         DoStuff("Test2");     }     static void DoStuff(string methodName) {         MethodInfo method = typeof(Program).GetMethod(methodName);         List<Type> args = new List<Type>(             method.GetParameters().Select(p => p.ParameterType));         Type delegateType;         if (method.ReturnType == typeof(void)) {             delegateType = Expression.GetActionType(args.ToArray());         } else {             args.Add(method.ReturnType);             delegateType = Expression.GetFuncType(args.ToArray());         }         Delegate d = Delegate.CreateDelegate(delegateType, null, method);         Console.WriteLine(d);     }     public static void Test1(int i, DateTime when) { }     public static float Test2(string x) { return 0; } } 
like image 81
Marc Gravell Avatar answered Sep 20 '22 08:09

Marc Gravell


Why that complicated?

public static Delegate CreateDelegate(this MethodInfo method) {     return Delegate.CreateDelegate     (         Expression.GetDelegateType         (             method.GetParameters()                 .Select(p => p.ParameterType)                 .Concat(new Type[] { method.ReturnType })                 .ToArray()         ),         null,         method     );    } 

[Side note: I prefixed this method "Create...". "To..." is confusingly as it misleds you to think it's a conversion.]

like image 39
0xbadf00d Avatar answered Sep 21 '22 08:09

0xbadf00d