我正在尝试使用 Delegate.CreateDelegate
[MSDN link]绑定(bind)到静态泛型方法,但绑定(bind)失败。
这是 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
无法绑定(bind)到泛型方法?如何绑定(bind)到它们?
我已在 Microsoft Connect 上提交错误 [link] .如果您认为这是一个错误,请为它投票。
更新 2: 我错误地认为绑定(bind)到非函数泛型方法会成功。事实证明,任何泛型方法都无法绑定(bind)。
最佳答案
试试这个(我也无法让你的 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)
重载无法做到这一点,它只是以这种方式实现。
更新:
仍然可以对任何委托(delegate)类型使用相同的方法。主要思想是为 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: 仍然可以用这种方式写一个不能被包裹在委托(delegate)中的方法,例如int Method<T>(string arg)
(任何不在参数列表中引用通用参数或作为返回值的东西,无论如何这都是一种不好的做法)。
关于c# - Delegate.CreateDelegate 无法绑定(bind)到静态泛型方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14035204/