C# 在使用反射的方法中列出(检测)闭包

C# 在使用反射的方法中列出(检测)闭包,c#,reflection,closures,C#,Reflection,Closures,我知道我可以使用MethodInfo.GetMethodBody().LocalVariables在方法中迭代所有本地定义的变量 但如果我将方法定义为: public static void somemethod( int someint ) { int test = 1; HM.M(() => { test = 2; }); } 匿名方法可以访问someint并作为闭包进行测试,但GetMethodBody().LocalVariabl

我知道我可以使用MethodInfo.GetMethodBody().LocalVariables在方法中迭代所有本地定义的变量

但如果我将方法定义为:

public static void somemethod( int someint )
{
    int test = 1;

    HM.M(() =>
    {
        test = 2;
    });
}
匿名方法可以访问someint并作为闭包进行测试,但GetMethodBody().LocalVariables将为空


有没有一种方法可以使用反射来检测闭包?

我找到了答案。c#中的闭包由编译器使用编译器生成的类实现。编译器生成一个类,在该类中复制方法中可访问的所有变量,并且方法本身封装在该类中。外部变量值将复制到类中

因此,在我上面的示例中,M方法具有签名:

public void M( Action method )
获取闭包列表的步骤如下:

MethodInfo mi = method.Method; 

FieldInfo[] fields = mi.DeclaringType.GetFields
                                    (
                                        BindingFlags.NonPublic |
                                        BindingFlags.Instance |
                                        BindingFlags.Public |
                                        BindingFlags.Static
                                    );
DeclaringType将是编译器生成的类,用于实现闭包

在字段数组中,将列出所有闭包

获取闭包的值是另一回事,但它不是这个问题的一部分

编辑: 正如@leppie所指出的,获取值很容易:

object res = fields[ 0 ].GetValue( method.Target );

如果你检查IL,你会发现编译器创建了一个编译器生成的类的实例,比如
Program/'c_udisplayclas1'
,但是反射并没有给你做这类事情的工具。你可能可以用Mono.Cecil或者。我对第一个做了一些研究,到目前为止我认为Mono.Cecil做不到。我将进一步研究,我还将研究System.Reflection.Metadata和tks。实际上更容易。只需检查委托的
Target
属性。您也可以从该实例中获取值。在这种情况下,您可能需要改进您的答案:)@leppie:因为我没有在问题中包括获取值,所以从技术上讲,我认为答案是可以的。我需要一个闭包列表,所以在这种情况下使用DeclaringType或Target是等效的,但是您是对的,改进答案不会有什么坏处。