我正在尝试使用 Delegate.CreateDelegate
[msdn链接]绑定到静态通用方法,但绑定失败。这是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:我是错误的,以为可以绑定到非功能通用方法成功。事实证明,任何通用方法都无法约束。
尝试一下(我也无法让您的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)
(任何不参考参数列表中不引用通用参数的内容或作为返回值,无论如何,这是一个不好的做法)。