[英]get methodinfo from a method reference C#
We can use a C# typeof
keyword when we want to get Type instance for specified type.当我们想要获取指定类型的 Type 实例时,我们可以使用 C#
typeof
关键字。 But what can I use if I want to get MethodInfo
of a method by it's reference?但是如果我想通过它的引用获取方法的
MethodInfo
,我可以使用什么?
For example I have a simple console app.例如,我有一个简单的控制台应用程序。 It contains
Program.Main
method.它包含
Program.Main
方法。 I want to get MethodInfo
by using something like methodinfoof(Program.Main)
.我想通过使用诸如
methodinfoof(Program.Main)
类的东西来获取MethodInfo
。 I have this problem because the method names might change, so I cannot just use Type.GetMethodInfo(string MethodName)
for that.我有这个问题,因为方法名称可能会改变,所以我不能只使用
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
,因此向我的方法添加任何自定义属性或其他任何内容都不是解决方案。
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
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 MemberExpression
and MemberInfo
instead if you want to support property getters and setters.如果您想支持属性 getter 和 setter,请改用
MemberExpression
和MemberInfo
。
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));
你也可以做
typeof(Program).GetMethod(nameof(Program.Main));
this way if the method's name change Visual Studio's refactoring will rename it here too.这样,如果方法的名称更改,Visual Studio 的重构也会在此处重命名。
NOTE: The "nameof" keyword was not available 5 years ago when question was posted.注意:“nameof”关键字在 5 年前发布问题时不可用。
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
.根据@Greg 评论,如果您有一些方法参数,您可以使用
Action<T>
、 Action<T1, T2>
、 Action<T1, T2, T3>
或Func<T1>
,不便之处在于您仍然会需要为GetMethodInfo
编写重载。
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.我们正在寻找一个方法
GetMethodInfo(SomeMethodSymbol)
,它返回有关给定方法的信息。 This is not straitforward because methods may be overloaded in C#.这并不直截了当,因为方法可能会在 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.
所以基本上你需要在调用中提供额外的提示,以使编译器(和其他代码分析器,如 Intellisense)理解你在谈论哪种方法。
Say for example I am looking for informations about the Math.Abs
method.举例来说,我正在寻找有关
Math.Abs
方法的信息。 I must then specify which overloaded version of the method I am looking for exactly:然后我必须指定我正在寻找的方法的哪个重载版本:
// 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.Exp
method, 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
方法,我仍然必须提供类型提示,因为该方法将来可能会被重载,然后代码将不再编译。
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
.请注意,除了没有像
Console.Clear
这样的参数的 void 静态方法之外,仍然应该提供类型信息。 Also, for instance methods, an actual instance should be used to get the appropriate method, which uses more resources.此外,对于实例方法,应该使用实际实例来获取适当的方法,这会使用更多资源。
Now for some corner cases the above helpers won't work.现在对于某些极端情况,上述助手将不起作用。 Say the method uses
out
parameters for example.例如,假设该方法使用
out
参数。 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 ):在那些特殊情况下,从 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
out
parameter.还要注意,添加了一个虚拟参数只是为了可以使用
out
参数。
Complete demo program: https://dotnetfiddle.net/CkS075 .完整的演示程序: https : //dotnetfiddle.net/CkS075 。
Maybe not the ideal way, but it could help
:
也许不是理想的方式,但它可以帮助
:
Solution without using lambdas/expressions:不使用 lambdas/表达式的解决方案:
var callback = typeof(BlogController).GetMethod(nameof(BlogController.GetBlogs));
I created a T4 template that creates the needed helper functions to help you with this.我创建了一个 T4 模板,它创建了所需的辅助函数来帮助您解决这个问题。 It creates a list of functions to get MethodInfo objects from Func<> or Action<> methods.
它创建了一个函数列表,用于从 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 :注意事项:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.