簡體   English   中英

C# 反射如何在一個方法內獲取本地 function

[英]C# Reflection how to get local function inside a method

您好,我正在嘗試列出方法中的所有本地函數,但我找不到任何方法來獲取這些方法。

例子:

在此處輸入圖像描述

我想獲取 MyFunction MethodInfo,使用類似 Assembly.EntryPoint.GetLocalMethods()

感謝您的寶貴時間,如果我不夠清楚,請告訴我。

在sharplab中進行了一些實驗后,我發現所有的本地方法都編譯為內部static方法,名稱如下:

<Name1>g__Name2|x_y

Name1是周圍方法的名稱。 Name2是本地方法的名稱。 xy是我還不特別知道它們的含義的數字。 他們還有一個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);
}

請注意,這在很大程度上依賴於實現細節。 這很可能在未來發生變化,您的代碼將會中斷。

雖然在大多數情況下公認的答案是正確的,但規則也有例外。

基本上我發現至少在以下情況下:

  1. 在捕獲/引用任何局部變量或參數的方法中有一個 lambda,並且
  2. 本地方法是捕獲/引用任何局部變量或參數(不一定與 lambda 中捕獲的相同)

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM