Delegate.CreateDelegate cannot bind to static universal methods

I am trying to use Delegate.CreateDelegate [MSDN Link] to bind to a static universal method, but the binding fails. Here is the PoC code:

 public static class CreateDelegateTest { public static void Main() { Action actionMethod = CreateDelegateTest.GetActionDelegate(); Action<int> intActionMethod = CreateDelegateTest.GetActionDelegate<int>(); Func<int> intFunctionMethod = CreateDelegateTest.GetFunctionDelegate<int>(); } public static Action GetActionDelegate() { return (Action)Delegate.CreateDelegate(typeof(Action), typeof(CreateDelegateTest), "ActionMethod"); } public static Action<T> GetActionDelegate<T>() { return (Action<T>)Delegate.CreateDelegate(typeof(Action<T>), typeof(CreateDelegateTest), "GenericActionMethod"); } public static Func<TResult> GetFunctionDelegate<TResult>() { return (Func<TResult>)Delegate.CreateDelegate(typeof(Func<TResult>), typeof(CreateDelegateTest), "GenericFunctionMethod"); } public static void ActionMethod() { } public static void GenericActionMethod<T>(T arg) { } public static TResult GenericFunctionMethod<TResult>() { return default(TResult); } } 

The actionMethod line is created correctly, but the creation of intActionMethod and intFunctionMethod .

Why can't CreateDelegate be bound to common methods? How to become attached to them?

I sent an error to Microsoft Connect [link] . If you think this is a mistake, vote for it, please.

Update 2: I was mistaken in thinking that binding to non-functional universal methods is successful. It turned out that any general method could not bind.

+4
source share
1 answer

Try it (I could not get your version of GetActionDelegate() to work either):

 public class CreateDelegateTest { public static Func<TResult> GetFunctionDelegate<TResult>() { var methodInfo = typeof(CreateDelegateTest).GetMethod("FunctionMethod") .MakeGenericMethod(typeof(TResult)); return (Func<TResult>)Delegate.CreateDelegate(typeof(Func<TResult>), methodInfo); } public static Action<T> GetActionDelegate<T>() { var methodInfo = typeof(CreateDelegateTest).GetMethod("ActionMethod") .MakeGenericMethod(typeof(T)); return (Action<T>)Delegate.CreateDelegate(typeof(Action<T>), methodInfo); } } 

I'm not sure why overloading CreateDelegate(Type, Type, string) does not allow this, it is simply implemented in this way.

Update:

So far, you can use the same approach with any type of delegate. The basic idea is to find the right arguments to call MakeGenericMethod() . A quick example of how this can be done:

 public static Delegate CreateDelegate(Type delegateType, Type objectType, string methodName) { var delegateMethod = delegateType.GetMethod("Invoke"); var delegateReturn = delegateMethod.ReturnType; var delegateParameters = delegateMethod.GetParameters(); var methods = objectType.GetMethods(); MethodInfo method = null; ParameterInfo[] methodParameters = null; Type methodReturn = null; // find correct method by argument count foreach(var methodInfo in methods) { if(methodInfo.Name != methodName) { continue; } methodParameters = methodInfo.GetParameters(); methodReturn = methodInfo.ReturnType; if(methodParameters.Length != delegateParameters.Length) { continue; } method = methodInfo; } if(method == null) { throw new Exception("Method not found"); } if(method.IsGenericMethodDefinition) { var genericArguments = method.GetGenericArguments(); var genericParameters = new Type[genericArguments.Length]; int genericArgumentIndex = Array.IndexOf(genericArguments, methodReturn); if(genericArgumentIndex != -1) { genericParameters[genericArgumentIndex] = delegateReturn; } for(int i = 0; i < methodParameters.Length; ++i) { var methodParameter = methodParameters[i]; genericArgumentIndex = Array.IndexOf(genericArguments, methodParameter.ParameterType); if(genericArgumentIndex == -1) continue; genericParameters[genericArgumentIndex] = delegateParameters[i].ParameterType; } if(Array.IndexOf(genericParameters, null) != -1) { throw new Exception("Failed to resolve some generic parameters."); } var concreteMethod = method.MakeGenericMethod(genericParameters); return Delegate.CreateDelegate(delegateType, concreteMethod); } else { return Delegate.CreateDelegate(delegateType, method); } } 

Note 1: I have a very simplified overloaded method resolution in this example - it depends only on the arguments.

Note 2:. You can still write a method that cannot be wrapped by a delegate in this way, for example, int Method<T>(string arg) (anything that does not refer to a common argument in the argument list or as a return value, which is bad practice).

+3
source

All Articles