如何确定MethodInfo是否表示lambda表达式的元数据?
答案 0 :(得分:4)
我认为你在谈论匿名方法。所以,你可以为它编写一个扩展方法,并检查方法的名称是否包含任何无效的chars。因为编译器生成的方法包含无效的chars,你可以使用该功能确定该方法是否是匿名的:
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
命名空间。
答案 1 :(得分:0)
以下代码可以解决问题。与接受的答案相比,它有点长,但是可惜,接受的答案并未在lambda和内部方法之间进行适当的区分,它们都被编译器弄乱了名字。因此,以下提供了两种方法:IsAnonymous
和IsInner
。
顺便说一句,代码也应该在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());
}
}