[英]get methodinfo from a method reference C#
當我們想要獲取指定類型的 Type 實例時,我們可以使用 C# typeof
關鍵字。 但是如果我想通過它的引用獲取方法的MethodInfo
,我可以使用什么?
例如,我有一個簡單的控制台應用程序。 它包含Program.Main
方法。 我想通過使用諸如methodinfoof(Program.Main)
類的東西來獲取MethodInfo
。 我有這個問題,因為方法名稱可能會改變,所以我不能只使用Type.GetMethodInfo(string MethodName)
。
我有大約 10 000 個方法想要獲取MethodInfo
,因此向我的方法添加任何自定義屬性或其他任何內容都不是解決方案。
對先前發布的答案稍作改編,但這篇博文似乎實現了您的要求; http://blog.functionalfun.net/2009/10/getting-methodinfo-of-generic-method.html
示例用法如下;
var methodInfo = SymbolExtensions.GetMethodInfo(() => Program.Main());
最初的答案是這個問題; https://stackoverflow.com/a/9132588/5827
您可以將表達式樹用於非靜態方法。 這是一個例子。
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 的重構也會在此處重命名。
注意:“nameof”關鍵字在 5 年前發布問題時不可用。
測試班
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
編寫重載。
讓我在這里對手頭的問題添加一些解釋。 我們正在尋找一個方法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 靜態方法之外,仍然應該提供類型信息。 此外,對於實例方法,應該使用實際實例來獲取適當的方法,這會使用更多資源。
現在對於某些極端情況,上述助手將不起作用。 例如,假設該方法使用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 。
也許不是理想的方式,但它可以幫助
:
不使用 lambdas/表達式的解決方案:
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");
}
<# } #>
}
}
注意事項:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.