1

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

我知道这是因为在 Enumrable 类中定义了两个 Where 方法 - 但是我怎样才能返回只使用谓词的 Where 方法

 Func<T, bool>. 

我目前拥有的是:

var collectionType = typeof(TSub);
Type tIEnumerable = typeof(IEnumerable<>).MakeGenericType(collectionType);

MethodInfo methodInfo =
        typeof(Enumerable)
        .GetMethod("Where")                
        .MakeGenericMethod(collectionType);

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

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

和(也返回 null)

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

和(这个返回相同的歧义异常)

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

任何人都可以帮忙吗?

谢谢

4

4 回答 4

2

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

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

作为额外的奖励,这是强类型的。它只有Enumerable.Where可以解析的情况下才会编译,而不是任何寻找字符串的东西"Where":如果你不小心键入,它会编译得很好"Wehre",但在运行时会失败。

于 2014-03-01T17:56:20.470 回答
1

我敢肯定有更简单的方法,但这里有一个:

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

不过这有点脆弱(想想微软在未来版本的 .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();
于 2014-03-01T16:49:03.147 回答
0

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

var whereMethod = typeof(Enumerable).GetMethods()
                .Single(m => m.Name == "Where" && m.GetParameters()[1].ParameterType.GetGenericTypeDefinition() == typeof(Func<,>))
.MakeGenericType(typeof(TSub));
于 2014-03-01T16:44:42.220 回答
0

有一个模板类型 T,这应该工作:

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

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

于 2014-03-01T16:48:23.467 回答