![](/img/trans.png)
[英]How to get method name from inside that method without using reflection in C#
[英]C# Reflection how to get local function inside a method
在sharplab中進行了一些實驗后,我發現所有的本地方法都編譯為內部static方法,名稱如下:
<Name1>g__Name2|x_y
Name1
是周圍方法的名稱。 Name2
是本地方法的名稱。 x
和y
是我還不特別知道它們的含義的數字。 他們還有一個CompilerGeneratedAttribute
。
無論如何,有了這些信息,你就可以在一個方法中找到所有的本地方法!
首先,您可以使用正則表達式來確定MethodInfo
是否是周圍方法的本地方法:
private static bool IsLocal(MethodInfo localMethod, string surroundingMethodName)
{
var match = Regex.Match(localMethod.Name, "^<(\\w+)>g__(\\w+)\\|\\d+_\\d+");
return match != null && match.Groups[1].Value == surroundingMethodName && localMethod.GetCustomAttribute<CompilerGeneratedAttribute>() != null;
}
然后你可以做一個簡單的Where
過濾器:
foreach (var method in typeof(SomeClass)
.GetMethods(BindingFlags.NonPublic | BindingFlags.Static)
.Where(x => IsLocal(x, nameof(SomeMethod))))
{
Console.WriteLine(method.Name);
}
請注意,這在很大程度上依賴於實現細節。 這很可能在未來發生變化,您的代碼將會中斷。
雖然在大多數情況下公認的答案是正確的,但規則也有例外。
基本上我發現至少在以下情況下:
In this particular case the local method will no longer be a static method in the class but an instance method in a compiler generated nested class with the class name being in the format of <>c__DisplayClassx_y
ie <>c__DisplayClass10_0
and the custom attribute will be in class 而該方法將沒有任何自定義屬性,並且本地方法名稱將采用以下格式之一:
<Name1>g__Name2|x
即<MyClass>g__MyMethod|1
<Name1>g__Name2|x_y
即<MyClass>g__MyMethod|1_2
查找所有本地方法
因此,我建議使用以下代碼來涵蓋所有情況:
private static bool IsLocal(MethodInfo localMethod, string surroundingMethodName)
{
var match = Regex.Match(localMethod.Name, @"^<(\w+)>g__(\w+)\|\d+(_\d+)?");
return match != null && match.Groups[1].Value == surroundingMethodName;
}
foreach (var method in typeof(SomeClass)
.GetMethods(BindingFlags.NonPublic | BindingFlags.Static)
.Where(x => IsLocal(x, nameof(SomeMethod)) && x.GetCustomAttribute<CompilerGeneratedAttribute>() != null))
.Union(typeof(SomeClass)
.GetNestedTypes(BindingFlags.NonPublic)
.Where(t => t.GetCustomAttribute<CompilerGeneratedAttribute>() != null)
.SelectMany(t => t.GetMethods(BindingFlags.NonPublic| BindingFlags.Instance)
.Where(x => IsLocal(x, nameof(SomeMethod))))
{
Console.WriteLine(method.Name);
}
尋找個人方法
雖然僅獲取單個方法,但以下代碼可能更清晰並具有更好的性能:
public static bool IsMatchLocal(this MethodInfo localMethod,
string surroundingMethodName, string localMethodName)
=> Regex.IsMatch(localMethod.Name,
$@"^<{surroundingMethodName}>g__{localMethodName}\|\d+(_\d+)?");
public static MethodInfo? GetLocalMethod(this Type type,
string surroundingMethodName, string localMethodName)
{
var method = type.GetMethods(BindingFlags.NonPublic | BindingFlags.Static)
.FirstOrDefault(m => m.GetCustomAttribute<CompilerGeneratedAttribute>() != null
&& m.IsMatchLocal(surroundingMethodName, localMethodName));
if(method is not null) return method;
var nestedTypes = type.GetNestedTypes(BindingFlags.NonPublic)
.Where(t => t.GetCustomAttribute<CompilerGeneratedAttribute>() != null);
foreach(var nested in nestedTypes)
{
method = nested.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance)
.FirstOrDefault(m => m.IsMatchLocal(surroundingMethodName, localMethodName));
if(method is not null) return method;
}
return null;
}
調用
在調用該方法時,您應該注意,雖然在以 static 版本結尾的一般非捕獲案例中,您只需將null
作為第一個參數傳遞給.Invoke()
,因為它是static
,對於具有捕獲的特殊案例 ZA81259C297DF1 的 4565D您需要傳遞實際 object (這是嵌套類的實例)的變量。
嵌套 class 的結構似乎是每個捕獲變量的一個公共字段(不是屬性),與捕獲的變量同名,除非它是這樣的受限名稱,在this
情況下,它使用格式為<>x__this
,例如<>4__this
。
因此,要調用該方法,您只需要實例化 class 的實例,很可能通過使用Activator.CreateInstance(nestedType)
然后設置所有需要的字段,很可能通過執行nestedType.GetField(nameof(myCapturedVariable), BindingFlags.Instance)
.
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.