我需要一个方法,它接受一个具有任意签名的非泛型静态方法的MethodInfo
实例,并返回一个绑定到该方法的委托,该方法可以稍后使用Delegate.DynamicInvoke
方法调用。我的第一个naïve尝试看起来像这样:
using System;
using System.Reflection;
class Program
{
static void Main()
{
var method = CreateDelegate(typeof (Console).GetMethod("WriteLine", new[] {typeof (string)}));
method.DynamicInvoke("Hello world");
}
static Delegate CreateDelegate(MethodInfo method)
{
if (method == null)
{
throw new ArgumentNullException("method");
}
if (!method.IsStatic)
{
throw new ArgumentNullException("method", "The provided method is not static.");
}
if (method.ContainsGenericParameters)
{
throw new ArgumentException("The provided method contains unassigned generic type parameters.");
}
return method.CreateDelegate(typeof(Delegate)); // This does not work: System.ArgumentException: Type must derive from Delegate.
}
}
我希望MethodInfo.CreateDelegate
方法能够自己找出正确的委托类型。显然不能。那么,如何创建一个System.Type
的实例来表示具有与所提供的MethodInfo
实例匹配的签名的委托呢?
可以使用System.Linq.Expressions.Expression.GetDelegateType方法:
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
class Program
{
static void Main()
{
var writeLine = CreateDelegate(typeof(Console).GetMethod("WriteLine", new[] { typeof(string) }));
writeLine.DynamicInvoke("Hello world");
var readLine = CreateDelegate(typeof(Console).GetMethod("ReadLine", Type.EmptyTypes));
writeLine.DynamicInvoke(readLine.DynamicInvoke());
}
static Delegate CreateDelegate(MethodInfo method)
{
if (method == null)
{
throw new ArgumentNullException("method");
}
if (!method.IsStatic)
{
throw new ArgumentException("The provided method must be static.", "method");
}
if (method.IsGenericMethod)
{
throw new ArgumentException("The provided method must not be generic.", "method");
}
return method.CreateDelegate(Expression.GetDelegateType(
(from parameter in method.GetParameters() select parameter.ParameterType)
.Concat(new[] { method.ReturnType })
.ToArray()));
}
}
在!method.IsStatic
的第二次检查中可能存在复制粘贴错误-您不应该在那里使用ArgumentNullException
。提供参数名作为ArgumentException
的参数是一种很好的样式。
如果您想拒绝所有泛型方法,请使用method.IsGenericMethod
;如果您只想拒绝具有未替换类型参数的泛型方法,请使用method.ContainsGenericParameters
。
你可以试试System.LinQ.Expressions
...
using System.Linq.Expressions;
...
static Delegate CreateMethod(MethodInfo method)
{
if (method == null)
{
throw new ArgumentNullException("method");
}
if (!method.IsStatic)
{
throw new ArgumentException("The provided method must be static.", "method");
}
if (method.IsGenericMethod)
{
throw new ArgumentException("The provided method must not be generic.", "method");
}
var parameters = method.GetParameters()
.Select(p => Expression.Parameter(p.ParameterType, p.Name))
.ToArray();
var call = Expression.Call(null, method, parameters);
return Expression.Lambda(call, parameters).Compile();
}
并在后面使用
var method = CreateMethod(typeof (Console).GetMethod("WriteLine", new[] {typeof (string)}));
method.DynamicInvoke("Test Test");
如果你想创建一个非静态方法,你必须实现一个目标/实例对象。
/// <summary>
/// Create delegate by methodinfo in target
/// </summary>
/// <param name="method">method info</param>
/// <param name="target">A instance of the object which contains the method where will be execute</param>
/// <returns>delegate or null</returns>
public static Delegate? CreateDelegateWithTarget(MethodInfo? method, object? target)
{
if (method is null ||
target is null)
return null;
if (method.IsStatic)
return null;
if (method.IsGenericMethod)
return null;
return method.CreateDelegate(Expression.GetDelegateType(
(from parameter in method.GetParameters() select parameter.ParameterType)
.Concat(new[] { method.ReturnType })
.ToArray()), target);
}