让我在这里为手头的问题添加一些解释。我们正在寻找一种GetMethodInfo(SomeMethodSymbol)
返回有关给定方法的信息的方法。这并不严格,因为方法可能在 C# 中被重载。因此,基本上您需要在调用中提供额外的提示,以使编译器(以及其他代码分析器,如 Intellisense)了解您正在谈论的方法。
例如说我正在寻找有关该Math.Abs
方法的信息。然后我必须指定我正在寻找的方法的哪个重载版本:
// int
MethodInfo info1 = ((Func<int, int>)Math.Abs).Method;
// or double ?
MethodInfo info2 = ((Func<double, double>)Math.Abs).Method;
即使只有一个现有的重载,例如该Math.Exp
方法,我仍然必须提供输入提示,因为该方法将来可能会重载,然后代码将不再编译。
直接帮手
鉴于上述说明,我们可以提供以下一组辅助方法,以在一定程度上减轻强制转换每个方法以获取其信息的繁琐任务:
public static class GetMethodInfoUtil
{
// No cast necessary
public static MethodInfo GetMethodInfo(Action action) => action.Method;
public static MethodInfo GetMethodInfo<T>(Action<T> action) => action.Method;
public static MethodInfo GetMethodInfo<T,U>(Action<T,U> action) => action.Method;
public static MethodInfo GetMethodInfo<TResult>(Func<TResult> fun) => fun.Method;
public static MethodInfo GetMethodInfo<T, TResult>(Func<T, TResult> fun) => fun.Method;
public static MethodInfo GetMethodInfo<T, U, TResult>(Func<T, U, TResult> fun) => fun.Method;
// Cast necessary
public static MethodInfo GetMethodInfo(Delegate del) => del.Method;
}
然后,您将像这样使用这些助手:
var methodInfos = new[] {
// Static methods
GetMethodInfo<int, int>(Math.Abs),
GetMethodInfo<double, double>(Math.Abs),
GetMethodInfo<long, long, long>(Math.Max),
// Static void methods
GetMethodInfo(Console.Clear),
GetMethodInfo<string[]>(Main),
// With explicit cast if too many arguments
GetMethodInfo((Action<string, object, object>)Console.WriteLine),
// Instance methods
GetMethodInfo<string, bool>("".StartsWith),
GetMethodInfo(new List<int>().Clear),
};
请注意,除了不带参数的 void 静态方法(如Console.Clear
. 此外,对于实例方法,应使用实际实例来获取使用更多资源的适当方法。
间接助手
现在对于某些极端情况,上述助手将不起作用。例如,假设该方法使用out
参数。在那些特殊情况下,从 lambda 表达式中提取方法信息变得很方便,我们回到其他海报提供的解决方案(代码灵感来自这里):
public static class GetIndirectMethodInfoUtil
{
// Get MethodInfo from Lambda expressions
public static MethodInfo GetIndirectMethodInfo(Expression<Action> expression)
=> GetIndirectMethodInfo((LambdaExpression)expression);
public static MethodInfo GetIndirectMethodInfo<T>(Expression<Action<T>> expression)
=> GetIndirectMethodInfo((LambdaExpression)expression);
public static MethodInfo GetIndirectMethodInfo<T, TResult>(Expression<Func<TResult>> expression)
=> GetIndirectMethodInfo((LambdaExpression)expression);
public static MethodInfo GetIndirectMethodInfo<T, TResult>(Expression<Func<T, TResult>> expression)
=> GetIndirectMethodInfo((LambdaExpression)expression);
// Used by the above
private static MethodInfo GetIndirectMethodInfo(LambdaExpression expression)
{
if (!(expression.Body is MethodCallExpression methodCall))
{
throw new ArgumentException(
$"Invalid Expression ({expression.Body}). Expression should consist of a method call only.");
}
return methodCall.Method;
}
}
你会使用这样的:
int dummyInt;
var moreMethodInfos = new[]
{
// Extracted from lambdas
GetIndirectMethodInfo(() => "".StartsWith("")),
GetIndirectMethodInfo((string s) => s.StartsWith(s)),
GetIndirectMethodInfo(() => int.TryParse("", out dummyInt)),
};
请注意,类型信息仍然是从参数类型间接提供的。另请注意,添加了一个虚拟参数只是为了可以使用out
参数。
完整的演示程序:https ://dotnetfiddle.net/CkS075 。