【问题标题】:Determine if MethodInfo represents a lambda expression确定 MethodInfo 是否表示 lambda 表达式
【发布时间】:2014-04-22 19:03:20
【问题描述】:

如何确定 MethodInfo 是否代表 lambda 表达式的元数据?

【问题讨论】:

  • 什么意思? MethodInfo 将引用一个方法,不是吗?
  • 更新的问题更加具体,即 lambda 表达式的元数据。
  • MethodInfo 永远不会表示 lambda 表达式。但是,DelegateExpression 可能代表一个 lambda,而该委托或表达式可能只代表一个方法调用。您是否尝试从代表那里获取MethodInfo
  • 我想我需要写出一个传递异步 lambda 的类,并显示在反映时,将为编译器生成的 lambda 表达式返回 MethodInfo。这对我来说并不明显,我应该预料到对其他人来说并不明显。我将添加代码,但创建一个自包含的 sn-p 需要一些时间。我正在获取一个类型的所有方法,并试图过滤掉编译器生成的 lambda 表达式方法。
  • @MichaelGunter:“委托或表达式代表方法调用”?我不喜欢这里的“代表”这个词。

标签: c# reflection lambda


【解决方案1】:

我认为您在谈论匿名方法。因此,您可以为此编写扩展方法并检查方法名称是否包含任何无效字符。因为编译器生成的方法包含无效字符,您可以使用该功能来判断方法是否匿名:

public static bool IsAnonymous(this MethodInfo method)
{
     var invalidChars = new[] {'<', '>'};
     return method.Name.Any(invalidChars.Contains);
}

测试:

Func<int> f = () => 23;

Console.Write(f.Method.IsAnonymous());  // true

更优雅的方法是使用IsValidLanguageIndependentIdentifier 方法验证方法名称,如下所示(来自this 答案的方法):

public static bool IsAnonymous(this MethodInfo method)
{
    return !CodeGenerator.IsValidLanguageIndependentIdentifier(method.Name);
}

记住要访问IsValidLanguageIndependentIdentifier 方法,您需要包含System.CodeDom.Compiler 命名空间。

【讨论】:

  • 太棒了,它是 CodeGenerator.IsValidLanguageIndependentIdentifier - 将其标记为答案
  • 这不会检测编译成委托的 Lambda 方法。
  • @CSharpie 是对的。使用 method.DeclaringType == null || !CodeGenerator.IsValidLanguageIndependentIdentifier(method.Name) 可以解决此问题,因为对于已编译的表达式,DeclaringType 为 null。
  • 这段代码没有正确区分 lambda 和内部方法(它以匿名方式捕获两者)。请参阅下面的答案...
【解决方案2】:

以下代码可以解决问题。与接受的答案相比,它有点长,但遗憾的是,接受的答案没有正确区分 lambda 和内部方法,它们的名称都被编译器弄乱了。因此下面提供了两种方法:IsAnonymousIsInner

顺便说一句,代码也应该在 Mono 下工作(名称似乎以相同的方式被破坏,但引擎盖下带有不同的魔术标签)。

public static class MethodInfoUtil
{
    static readonly Regex MagicTagPattern = new Regex(">([a-zA-Z]+)__");
    static readonly string AnonymousMagicTag;
    static readonly string InnerMagicTag;

    public static bool IsAnonymous(this MethodInfo mi)
    {
        return mi.Name.Contains(AnonymousMagicTag);
    }

    public static bool IsInner(this MethodInfo mi)
    {
        return mi.Name.Contains(InnerMagicTag);
    }

    public static string GetNameMagicTag(this MethodInfo mi, bool noThrow = false)
    {
        var match = MagicTagPattern.Match(mi.Name);
        if (match.Success && match.Value is string value && !match.NextMatch().Success)
            return value;
        else if (noThrow)
            return null;
        else
            throw new ArgumentException($"Cant find magic tag of {mi}");
    }

    // static constructor: initialize the magic tags
    static MethodInfoUtil()
    {
        void Inner() { };
        Action inner = Inner;
        Action anonymous = () => { };
        InnerMagicTag = GetNameMagicTag(inner.Method);
        AnonymousMagicTag = GetNameMagicTag(anonymous.Method);

        CheckThatItWorks();
    }

    [Conditional("DEBUG")]
    static void CheckThatItWorks()
    { 
        // Static mathods are neither anonymous nor inner
        Debug.Assert(!((Func<int, int>)Math.Abs).Method.IsAnonymous());
        Debug.Assert(!((Func<int, int>)Math.Abs).Method.IsInner());

        // Instance methods are neither anonymous nor inner
        Debug.Assert(!((Func<string, bool>)"".StartsWith).Method.IsAnonymous());
        Debug.Assert(!((Func<string, bool>)"".StartsWith).Method.IsInner());

        // Lambda 
        Action anonymous1 = () => { };
        Debug.Assert(anonymous1.Method.IsAnonymous());
        Debug.Assert(!anonymous1.Method.IsInner());

        // Anonymous delegates 
        Action anonymous2 = delegate(){ };
        Debug.Assert(anonymous2.Method.IsAnonymous());

        // Sublambdas 
        Action anonymous3 = new Func<Func<Action>>(() => () => () => { })()();
        Debug.Assert(anonymous3.Method.IsAnonymous());

        void Inner() { }
        Action inner1 = Inner;
        Debug.Assert(inner1.Method.IsInner());
        Debug.Assert(!inner1.Method.IsAnonymous());

        // Deep inner methods have same tag as inner
        Action Imbricated()
        {
            void Inside() { };
            return Inside;
        }
        Action inner2 = Imbricated();
        Debug.Assert(inner2.Method.IsInner());
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-19
    • 2014-09-12
    相关资源
    最近更新 更多