如何获取"Where"扩展方法的正确方法信息



我正在尝试使用反射返回正确的"Where"扩展方法,以便构建自定义表达式。我已经尝试了几种方法,但我得到的最接近的方法抛出了一个异常:"mscorlib 中发生了类型为'System.Reflection.AmbiguousMatchException'的未处理异常.dll"

我知道这是因为在 Enumrable 类中定义了两个 Where 方法 - 但是我如何返回仅使用

 Func<T, bool>. 

我目前拥有的是:

var collectionType = typeof(TSub);
Type tIEnumerable = typeof(IEnumerable<>).MakeGenericType(collectionType);
MethodInfo methodInfo =
        typeof(Enumerable)
        .GetMethod("Where")                
        .MakeGenericMethod(collectionType);

我也试过(这个返回空):

MethodInfo methodWhere = typeof(Enumerable).GetMethod("Where", new[] { typeof(TSub )});

和(也返回空值)

 MethodInfo methodWhere = typeof(Enumerable).GetMethod("Where", new[] { collectionType })

和(这个返回相同的模棱两可异常)

MethodInfo methodWhere = typeof(Enumerable).GetMethod("Where", BindingFlags.Public |      BindingFlags.Static)

有人可以帮忙吗?

谢谢

在我看来,目前的答案,包括公认的答案,远比必要的复杂得多。如果你有一个可以在编译时使用的类型T,你可以得到如下MethodInfo

Func<IEnumerable<T>, Func<T, bool>, IEnumerable<T>> whereDelegate = Enumerable.Where;
MethodInfo whereMethodInfo = whereDelegate.Method;

作为额外的奖励,这是强类型。只有当可以解析Enumerable.Where时,它才会编译,而不是任何查找字符串"Where":如果您不小心键入"Wehre",则可以编译,但在运行时会失败。

我相信有更简单的方法,但这里有一个:

typeof(Enumerable).GetMethods()
                  .Single(method => method.Name == "Where" 
                          && method.GetParameters()
                                   .ElementAt(1)
                                   .ParameterType
                                   .GetGenericTypeDefinition() == typeof(Func<,>)) 
                  .MakeGenericMethod(typeof(TSub))

不过这有点脆弱(想想Microsoft在 .NET 的未来版本中添加更多重载)。也许更强大(但更可怕;肯定有更好的方法)是:

var methods = from method in typeof(Enumerable).GetMember("Where")
                                               .OfType<MethodInfo>()                               
              let typeArgs = method.GetGenericArguments()
              where typeArgs.Length == 1
              let typeArg = typeArgs.Single()
              where !typeArg.GetGenericParameterConstraints().Any()
              let seqtype = typeof(IEnumerable<>).MakeGenericType(typeArg)                    
              where method.ReturnType == seqtype
              let expectedParams = new[]
              {
                 seqtype, 
                 typeof(Func<,>).MakeGenericType(typeArg, typeof(bool))
              }
              where method.GetParameters()
                          .Select(parameter => parameter.ParameterType)
                          .SequenceEqual(expectedParams)
              select method.MakeGenericMethod(typeof(TSub));

var result = methods.Single();

使用模板类型 T,这应该可以工作:

var methodWhere = typeof(Enumerable).GetMethod("Where", BindingFlags.Public |    BindingFlags.Static, new Type[]{ typeof(IEnumerable<T>), typeof(Func<T, bool>) });

Where 方法采用两个参数:IEnumerable 和比较函数。

我认为区分这两个重载的最简单方法是:

var whereMethod = typeof(Enumerable).GetMethods()
                .Single(m => m.Name == "Where" && m.GetParameters()[1].ParameterType.GetGenericTypeDefinition() == typeof(Func<,>))
.MakeGenericType(typeof(TSub));

最新更新