我正在尝试使用Delegate.CreateDelegate
[MSDN link]绑定到静态泛型方法,但绑定失败。
这是PoC代码:
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);
}
}
actionMethod
已正确创建,但intActionMethod
和intFunctionMethod
创建会抛出。
为什么CreateDelegate
无法绑定到泛型方法?如何绑定它们?
我已在Microsoft Connect [link]上提交了该错误。如果您认为这是一个错误,请投票支持。
更新2:我认为绑定到非功能泛型方法成功是错误的。事实证明,任何通用方法都无法绑定。
答案 0 :(得分:3)
尝试此操作(我无法让您的GetActionDelegate()
版本也能正常工作):
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);
}
}
我不确定为什么CreateDelegate(Type, Type, string)
重载无法执行此操作,它只是以这种方式实现。
<强>更新强>
仍然可以对任何委托类型使用相同的方法。主要想法是为MakeGenericMethod()
调用找到正确的参数。如何完成的简单示例:
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);
}
}
注1:在此示例中,我极度简化了重载方法解析 - 它仅依赖于参数计数。
注2:仍然可以编写一个以这种方式包装在委托中的方法,例如int Method<T>(string arg)
(任何不引用参数列表中的泛型参数的方法或作为一个返回值,无论如何都是一种不好的做法。)