如何获取Enumerable.SequenceEqual的MethodInfo

时间:2015-09-25 07:00:11

标签: c# reflection

我正在尝试使用MethodInfo获取Enumerable.SequenceEqual的{​​{1}}。到目前为止,我尝试了以下内容:

Type.GetMethod(...)

var mi = typeof(Enumerable).GetMethod(nameof(Enumerable.SequenceEqual),
    BindingFlags.Static | BindingFlags.Public, null, CallingConventions.Any,
    new Type[] { typeof(IEnumerable<>), typeof(IEnumerable<>) }, null);

但是,两个解决方案都返回var enumTyped = typeof(IEnumerable<>).MakeGenericType(ValueType); var mi = typeof(Enumerable).GetMethod(nameof(Enumerable.SequenceEqual), BindingFlags.Static | BindingFlags.Public, null, CallingConventions.Any, new Type[] { enumTyped, enumTyped }, null); 而不是我想要的方法。我知道可以通过调用null和过滤来检索该方法,但我非常想知道如何使用GetMethods()检索它。

3 个答案:

答案 0 :(得分:3)

不幸的是,为了使用Type.GetMethod(string name, Type[] types)获取通用泛型方法,您必须在Type[]中为方法提供正确的泛型类型,这意味着当您尝试执行此操作时:

Type requiredType = typeof(IEnumerable<>);
typeof(Enumerable).GetMethod("SequenceEqual", new Type[] { requiredType, requiredType });

你实际上需要做类似的事情:

Type requiredType = typeof(IEnumerable<TSource>);
typeof(Enumerable).GetMethod("SequenceEqual", new Type[] { requiredType, requiredType });

因为如果您查看SequenceEqual的签名,则通用类型为IEnumerable<TSource>而不是IEnumerable<>

public static IEnumerable<TSource> SequenceEqual<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second);

BUT:您无法访问类型TSource以便使用它。 因此,获取IEnumerable<TSource>的唯一方法是使用如下反射:

MethodInfo info = typeof(Enumerable)
    .GetMethods(BindingFlags.Static | BindingFlags.Public)
    .Where(x => x.Name.Contains("SequenceEqual"))
    .Single(x => x.GetParameters().Length == 2);
Type genericType = typeof(IEnumerable<>).MakeGenericType(infos.GetGenericArguments());

而不是使用

获取方法
typeof(Enumerable).GetMethod("SequenceEqual", new Type[] { genericType, genericType });

但这需要我们无论如何都要获得SequenceEqual方法,所以可悲的事实是当使用GetMethod而不是{的重载很少时,该方法是一种通用方法{1}}几乎不可能* (您 CAN 实施GetMethods并在{{1}中使用它方法,但它需要很长的编码,这可能是错误的,不可维护的,应该避免)

答案 1 :(得分:2)

想要添加到之前的答案。首先,确实不可能使用单个GetMethod来做你想做的事情。但是,如果你不想调用GetMethods并获得所有180多种Enumerable方法,你可以这样做:

var mi = typeof(Enumerable).GetMember(nameof(Enumerable.SequenceEqual), MemberTypes.Method,
            BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod).OfType<MethodInfo>().ToArray();

GetMember调用将返回2个SequenceEqual方法的重载,您可以选择其中一个并按照其他答案中的方式执行MakeGenericMethod。 此外,根据您的目标,您可以考虑使用表达式:

var source = Expression.Parameter(
            typeof(IEnumerable<string>), "source");
var target = Expression.Parameter(
            typeof(IEnumerable<string>), "target");
var callExp = Expression.Call(typeof(Enumerable), "SequenceEqual", new Type[] { typeof(string)},
            source, target);            
var lambda = Expression.Lambda<Func<IEnumerable<string>, IEnumerable<string>, bool>>(callExp, source, target).Compile();
var result = lambda(new[] { "1", "2", "3" }, new[] { "1", "2", "3" });
Debug.Assert(result);

答案 2 :(得分:0)

另一个答案与之前的两个答案略有不同,但使用的是MakeGenericMethod调用和VisualBasic版本。

Dim lSequanceEqual As MethodInfo = GetType(System.Linq.Enumerable).GetMethods()
    .First(Function(mi) mi.Name.Contains(NameOf(System.Linq.Enumerable.SequenceEqual)) AndAlso mi.GetParameters.Length = 2)
Dim lMethod As MethodInfo = lSequanceEqual.MakeGenericMethod(New Type() { GetType(String)}) 
if CBool(lMethod.Invoke(Nothing, New Object() { firstList, secondList})) Then 'Do something