从方法引用C#获取methodinfo

时间:2012-02-21 17:30:48

标签: c# .net reflection typeof methodinfo

当我们想要获取指定类型的Type实例时,我们可以使用C#typeof关键字。但是如果我想通过它的引用得到MethodInfo方法,我可以使用什么?

例如,我有一个简单的控制台应用程序。它包含Program.Main方法。我希望通过MethodInfo之类的内容获得methodinfoof(Program.Main)。我有这个问题,因为方法名称可能会改变,所以我不能只使用Type.GetMethodInfo(string MethodName)

我有大约10 000种方法,我希望得到MethodInfo,因此在我的方法中添加任何自定义属性或其他任何方法都不是解决方案。

7 个答案:

答案 0 :(得分:14)

稍微修改了之前发布的答案,但这篇博文似乎达到了你的要求; http://blog.functionalfun.net/2009/10/getting-methodinfo-of-generic-method.html

样本用法如下;

var methodInfo = SymbolExtensions.GetMethodInfo(() => Program.Main());

原来的回答是这个问题; https://stackoverflow.com/a/9132588/5827

答案 1 :(得分:12)

您可以将表达式树用于非静态方法。这是一个例子。

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类中声明的成员函数。

如果您想支持属性获取者和设置者,请使用MemberExpressionMemberInfo

答案 2 :(得分:6)

测试课

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的重载。

答案 3 :(得分:5)

我知道这是一个非常古老的帖子,但我会把它扔给那些可能仍在寻找一个简单解决方案的人。这似乎没有人想到最简单的解决方案:

typeof(Program).GetMethods();

返回一个包含Program类中所有方法的MethodInfo的数组,无论属性如何或是否有参数。

如果您愿意,可以迭代它,例如,列出所有10.000+方法的名称。

如果方法名称更改,您也可以typeof(Program).GetMethod(nameof(Program.Main));这样做Visual Studio的重构也会在这里重命名。

注意:5年前发布问题时,“nameof”关键字无效。

答案 4 :(得分:2)

也许不是理想的方式,但它可能有所帮助:

var callback = typeof(BlogController).GetMethod(nameof(BlogController.GetBlogs));

答案 5 :(得分:1)

我创建了一个T4模板,可以创建所需的帮助函数来帮助您完成此任务。它创建了一个函数列表,用于从Func&lt;&gt;获取MethodInfo对象。或行动&lt;&gt;方法。

将以下代码复制到名为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");
        }

<# } #>
    }
}

备注

  • 请确保.tt模板的构建操作设置为
  • 您可以通过将max变量设置为适当的设置来创建更多或更少的功能。

答案 6 :(得分:1)

在这里,让我为当前的问题添加一些解释。我们正在寻找一种方法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 static方法外,不使用任何类似Console.Clear的参数,都应提供类型信息。另外,对于实例方法,应使用实际实例来获取适当的方法,该方法使用更多的资源。

间接助手

现在在某些特殊情况下,上述助手将无法工作。假设该方法使用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