从方法引用 C# 中获取方法信息

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9382216/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 07:07:37  来源:igfitidea点击:

get methodinfo from a method reference C#

c#.netreflectiontypeofmethodinfo

提问by Bogdan Verbenets

We can use a C# typeofkeyword when we want to get Type instance for specified type. But what can I use if I want to get MethodInfoof a method by it's reference?

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

For example I have a simple console app. It contains Program.Mainmethod. I want to get MethodInfoby using something like methodinfoof(Program.Main). I have this problem because the method names might change, so I cannot just use Type.GetMethodInfo(string MethodName)for that.

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

I have about 10 000 methods for which I would like to get MethodInfo, so adding any custom attributes or anything else to my methods is not a solution.

我有大约 10 000 种方法想要获取MethodInfo,因此向我的方法添加任何自定义属性或其他任何内容都不是解决方案。

采纳答案by Christopher McAtackney

Slight adaptation of a previously posted answer, but this blog post seems to achieve what you're asking for; http://blog.functionalfun.net/2009/10/getting-methodinfo-of-generic-method.html

对先前发布的答案稍作改编,但这篇博文似乎实现了您的要求;http://blog.functionalfun.net/2009/10/getting-methodinfo-of-generic-method.html

Sample usage would be as follows;

示例用法如下;

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

Original answer was to this question; https://stackoverflow.com/a/9132588/5827

最初的答案是这个问题;https://stackoverflow.com/a/9132588/5827

回答by oleksii

Test class

测试班

public class  Foo
{
    public void DoFoo()
    {
        Trace.WriteLine("DoFoo");
    }

    public static void DoStaticFoo()
    {
        Trace.WriteLine("DoStaticFoo");
    }
}

And you can do something like this

你可以做这样的事情

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

Update
Per @Greg comment if you have some parameters to the methods, you can use Action<T>, Action<T1, T2>, Action<T1, T2, T3>, or Func<T1>, the inconvenience is that you will still need to write the overloads for GetMethodInfo.

更新
Per @Greg 注释,如果您有方法的一些参数,则可以使用Action<T>, Action<T1, T2>, Action<T1, T2, T3>, 或Func<T1>,不便之处在于您仍然需要为 编写重载GetMethodInfo

回答by Dmitry S.

You can use expression trees for non-static methods. Here is an example.

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

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");
    }
}

You would use it like this:

你会像这样使用它:

        MethodInfo mi = MethodInfoHelper.GetMethodInfo<Program>(x => x.Test());
        Console.WriteLine(mi.Name);

Test() is a member function declared in the Program class.

Test() 是在 Program 类中声明的成员函数。

Use MemberExpressionand MemberInfoinstead if you want to support property getters and setters.

使用MemberExpressionMemberInfo替代,如果你想支持财产getter和setter。

回答by MovGP0

I created a T4 template that creates the needed helper functions to help you with this. It creates a list of functions to get MethodInfo objects from Func<> or Action<> methods.

我创建了一个 T4 模板,它创建了所需的辅助函数来帮助您解决这个问题。它创建了一个函数列表,用于从 Func<> 或 Action<> 方法中获取 MethodInfo 对象。

Copy the following code into a file named GetMethodInfo.tt:

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

<# } #>
    }
}

Notes:

注意事项

  • please make sure, that the Build Actionof the .tt template is set to None
  • you can create more or less functions by setting the max variable to the appropriate setting.
  • 请确保.tt 模板的Build Action设置为None
  • 您可以通过将 max 变量设置为适当的设置来创建更多或更少的函数。

回答by Matheus Rocha

I know this is a very old post, but I'll just throw this out there for someone who might still be looking for a simple solution to this.. It just seems like no one thought of the simplest solution:

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

typeof(Program).GetMethods();

Returns an array with the MethodInfo of all methods in the Program class, regardless of attributes or of having parameters or not.

返回一个包含 Program 类中所有方法的 MethodInfo 的数组,而不管属性或是否有参数。

You can iterate ove it if you want, for instance, to list the names of all your 10.000+ methods.

例如,如果您想列出所有 10.000 多个方法的名称,您可以对其进行迭代。

You can also do typeof(Program).GetMethod(nameof(Program.Main));this way if the method's name change Visual Studio's refactoring will rename it here too.

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

NOTE: The "nameof" keyword was not available 5 years ago when question was posted.

注意:“nameof”关键字在 5 年前发布问题时不可用。

回答by Mladen B.

Maybe not the ideal way, but it could help:

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

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

回答by Frederic

Let me add some explanations to the problem at hands here. We are looking for a method GetMethodInfo(SomeMethodSymbol)which returns information about the given method. This is not straitforward because methods may be overloaded in C#. So basically you need to provide additionnal cues into the call to make the compiler (and other code analysers like Intellisense) understand which method you are talking about.

让我在这里对手头的问题添加一些解释。我们正在寻找一种GetMethodInfo(SomeMethodSymbol)返回有关给定方法的信息的方法。这并不直截了当,因为方法可能会在 C# 中重载。所以基本上你需要在调用中提供额外的提示,以使编译器(和其他代码分析器,如 Intellisense)理解你在谈论哪种方法。

Say for example I am looking for informations about the Math.Absmethod. I must then specify which overloaded version of the method I am looking for exactly:

比如说,我正在寻找有关该Math.Abs方法的信息。然后我必须指定我正在寻找的方法的哪个重载版本:

// int
MethodInfo info1 = ((Func<int, int>)Math.Abs).Method;

// or double ?
MethodInfo info2 = ((Func<double, double>)Math.Abs).Method;

Even if there is just one existing overload, like for the Math.Expmethod, I must still provide typing cues, because the method might be overloaded in the future and the code would then not compile anymore.

即使只有一个现有的重载,比如Math.Exp方法,我仍然必须提供类型提示,因为该方法将来可能会被重载,然后代码将不再编译。

Direct helpers

直接帮手

Given the above remarks, we can provide the following set of helper methods to alleviate somewhat the tedious task of casting every method to reach its informations:

鉴于上述说明,我们可以提供以下一组辅助方法,以在一定程度上减轻转换每个方法以获取其信息的繁琐任务:

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;
}

You would then use those helpers like this:

然后你会像这样使用这些助手:

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),
};

Note that type information should still be provided except for void static method taking no arguments like Console.Clear. Also, for instance methods, an actual instance should be used to get the appropriate method, which uses more resources.

请注意,除了不带参数的 void 静态方法外,仍应提供类型信息Console.Clear。此外,对于实例方法,应该使用实际实例来获取适当的方法,这会使用更多资源。

Indirect helpers

间接帮手

Now for some corner cases the above helpers won't work. Say the method uses outparameters for example. In those special cases, extracting method informations from lambda expressions becomes handy, and we get back to the solution provided by other posters (code inspiration from here):

现在对于某些极端情况,上述助手将不起作用。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;
    }
}

You would use those like this:

你会使用这样的:

int dummyInt;
var moreMethodInfos = new[]
{
    // Extracted from lambdas
    GetIndirectMethodInfo(() => "".StartsWith("")),
    GetIndirectMethodInfo((string s) => s.StartsWith(s)),
    GetIndirectMethodInfo(() => int.TryParse("", out dummyInt)),
};

Note that type information is still provided indirectly from argument type. Note as well that a dummy argument has been added just to make it possible to use an outparameter.

请注意,类型信息仍然是从参数类型间接提供的。还要注意,添加了一个虚拟参数只是为了可以使用out参数。

Complete demo program: https://dotnetfiddle.net/CkS075.

完整的演示程序:https: //dotnetfiddle.net/CkS075