当我们想要获取指定类型的 Type 实例时,我们可以使用 C#
typeof
关键字。但是如果我想通过方法的引用获取方法的MethodInfo
,我可以使用什么?
例如我有一个简单的控制台应用程序。它包含
Program.Main
方法。我想通过使用类似 MethodInfo
的东西来获得 methodinfoof(Program.Main)
。我遇到这个问题是因为方法名称可能会改变,所以我不能只使用 Type.GetMethodInfo(string MethodName)
来解决这个问题。
我想要获得大约 10 000 个方法
MethodInfo
,因此向我的方法添加任何自定义属性或其他任何内容都不是解决方案。
对之前发布的答案进行了轻微改编,但这篇博文似乎达到了您的要求; http://blog.functionfun.net/2009/10/getting-methodinfo-of-generic-method.html
示例用法如下;
var methodInfo = SymbolExtensions.GetMethodInfo(() => Program.Main());
原来的答案是这个问题; https://stackoverflow.com/a/9132588/5827
让我对这里的问题添加一些解释。我们正在寻找一个方法
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),
};
请注意,除了像
Console.Clear
这样不带参数的 void static 方法外,仍应提供类型信息。另外,对于实例方法,应该使用实际实例来获取适当的方法,这会占用更多资源。
现在,对于某些极端情况,上述帮助程序将不起作用。例如,假设该方法使用
out
参数。在这些特殊情况下,从 lambda 表达式中提取方法信息变得很方便,我们回到其他海报提供的解决方案(代码灵感来自here):
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.
您可以将表达式树用于非静态方法。这是一个例子。
using System.Linq.Expressions;
using System.Reflection;
public static class MethodInfoHelper
{
public static MethodInfo GetMethodInfo<T>(Expression<Action<T>> expression)
{
var member = expression.Body as MethodCallExpression;
if (member != null)
return member.Method;
throw new ArgumentException("Expression is not a method", "expression");
}
}
你可以像这样使用它:
MethodInfo mi = MethodInfoHelper.GetMethodInfo<Program>(x => x.Test());
Console.WriteLine(mi.Name);
Test()是在Program类中声明的成员函数。
如果您想支持属性 getter 和 setter,请使用
MemberExpression
和 MemberInfo
。
我知道这是一篇非常旧的帖子,但我只是将其扔给那些可能仍在寻找简单解决方案的人。似乎没有人想到最简单的解决方案:
typeof(Program).GetMethods();
返回一个数组,其中包含 Program 类中所有方法的 MethodInfo,无论属性如何或是否有参数。
如果您想要,例如,列出所有 10.000 多个方法的名称,您可以迭代它。
如果方法的名称更改,您也可以这样做
typeof(Program).GetMethod(nameof(Program.Main));
,Visual Studio 的重构也会在这里重命名它。
注意:5 年前发布问题时,“nameof”关键字不可用。
测试课
public class Foo
{
public void DoFoo()
{
Trace.WriteLine("DoFoo");
}
public static void DoStaticFoo()
{
Trace.WriteLine("DoStaticFoo");
}
}
你可以做这样的事情
MethodInfo GetMethodInfo(Action a)
{
return a.Method;
}
var foo = new Foo();
MethodInfo mi = GetMethodInfo(foo.DoFoo);
MethodInfo miStatic = GetMethodInfo(Foo.DoStaticFoo);
//do whatever you need with method info
更新
根据 @Greg 注释,如果方法有一些参数,则可以使用
Action<T>
、Action<T1, T2>
、Action<T1, T2, T3>
或 Func<T1>
,不便之处在于您仍然需要为 GetMethodInfo
编写重载。
也许不是理想的方式,但它可以帮助:
不使用 lambda/表达式的解决方案:
var callback = typeof(BlogController).GetMethod(nameof(BlogController.GetBlogs));
我创建了一个 T4 模板,它创建了所需的辅助函数来帮助您完成此任务。它创建一个函数列表以从 Func<> 或 Action<> 方法获取 MethodInfo 对象。
将以下代码复制到名为
GetMethodInfo.tt
的文件中:
<#@ template language="C#" #>
<#@ output extension=".cs" encoding="utf-8" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Text" #>
using System;
using System.Linq.Expressions;
using System.Reflection;
namespace Tools
{
public static class GetMethodInfo
{
<# int max = 12;
for(int i = 0; i <= max; i++)
{
var builder = new StringBuilder();
for(int j = 0; j <= i; j++)
{
builder.Append("T");
builder.Append(j);
if(j != i)
{
builder.Append(", ");
}
}
var T = builder.ToString();
#>
public static MethodInfo ForFunc<T, <#= T #>>(Expression<Func<T, <#= T #>>> expression)
{
var member = expression.Body as MethodCallExpression;
if (member != null)
return member.Method;
throw new ArgumentException("Expression is not a method", "expression");
}
public static MethodInfo ForAction<<#= T #>>(Expression<Action<<#= T #>>> expression)
{
var member = expression.Body as MethodCallExpression;
if (member != null)
return member.Method;
throw new ArgumentException("Expression is not a method", "expression");
}
<# } #>
}
}
注释:
这是一个基于 Linq 表达式的解决方案,适用于任意数量的方法参数:
public static MethodInfo GetMethodInfo<T>(Expression<Func<T, Delegate>> function)
{
var body = function?.Body as UnaryExpression; // Convert(delegate)
var operand = body?.Operand as MethodCallExpression; // CreateDelegate(method)
var @object = operand?.Object as ConstantExpression; // MethodInfo
var method = @object?.Value as MethodInfo;
return method;
}
然后你可以像这样使用它:
var info = GetMethodInfo<MyClass>(c => c.MyMethod);