c# - 如何用反射识别 lambda 闭包

标签 c# reflection lambda delegates

我正在编写一个涉及 Actions 的组件,并且需要找到一种方法来识别当 Action.Target 对象是编译器生成的闭包时使用反射情况。我正在做一个实验来尝试找到一种方法,这个小实验的目的是开发一个谓词,该谓词接受一个 Action 并返回一个 bool 值,该 bool 值指示操作目标是否是此类闭包类的实例。

在我的测试用例中,我有以下创建 4 种不同类型操作的方法:

    private void _createClosure(int i)
    {
        ClosureAction = new Action(() =>
        {
            var j = i;
            var k = somenum;
        });
    }

    private void _createLambda()
    {
        LambdaAction = new Action(() =>
        {
            this._instanceAction();

        });
    }

    private void _createInstance()
    {
        InstanceAction = new Action(_instanceAction);
    }

    private void _createStatic()
    {
        StaticAction = new Action(_staticAction);
    }

    private int somenum;

    private void _instanceAction()
    {
        somenum++;
    }

    private static void _staticAction()
    {

    }

下表显示了每个操作的属性: Action properties

如你所见,LambaAction 和 ClosureAction 在定义上非常相似,它们都使用 lambda,但是闭包有一个在 lambda 内部使用的局部函数变量,因此编译器被迫生成一个闭包类(class)。很明显,第二行,即表示 ClosureAction 的行,是唯一具有闭包类型目标的行。静态的根本没有目标,另外两个使用调用类(Called ActionReferences)作为目标。下表显示了目标反射类型属性的比较: Target Types

因此我们可以看到闭包案例的独特之处在于目标类型不是类型信息而是嵌套类型。它也是唯一一个私有(private)嵌套、密封且名称包含字符串 +<>c__DisplayClass 的。现在,虽然我认为这些特征对于任何正常用例都是决定性的,但我更愿意定义一个我可以依赖的谓词。我不喜欢将这种机制建立在编译器命名约定或非唯一属性的基础上,因为从技术上讲,用户可能会创建一个具有相同命名约定的私有(private)嵌套密封类……这不太可能,但它不是 100% 干净的解决方案.

最后 - 问题是:是否有一种简洁的方法来编写谓词来标识实际上是编译器生成的闭包的操作?

谢谢

最佳答案

这不是 100% 准确,但通常有效:

bool isClosure = action.Target != null && Attribute.IsDefined(
    action.Target.GetType(), typeof(CompilerGeneratedAttribute));
Console.WriteLine(isClosure);

您当然可以通过手动将 [CompilerGenerated] 添加到您选择的任何类型来强制误报。

您也可以使用 action.Method.DeclaringType,但由于所有捕获都涉及目标实例,因此保留 Target 检查很有用:

bool isClosure = action.Target != null && Attribute.IsDefined(
    action.Method.DeclaringType, typeof(CompilerGeneratedAttribute));

关于c# - 如何用反射识别 lambda 闭包,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25721711/

相关文章:

c# - 如何实现XUnit描述性Assert消息?

c# - 在 CSS 中使用人造全高列时修复 anchor

java - 如何使用 BeanUtils 自省(introspection)获取 Java 对象的所有属性列表?

c# - System.Refelection.Assembly.CreateInstance 在 .NET 4.0 中损坏

c - Printf 语句不适用于 lambda

c++ - 对象存储 lambda 函数是否有自己的地址?

c# - 在C#中将MAC地址转换为字节数组

c# - 在使用 XAMLC 时,在 FontSize 中使用静态标记扩展会导致无效转换

reflection - clojure.lang.Reflector 在互操作方法的实现中是如何使用的

python - 在 lambda 中访问函数的 __doc__