【问题标题】:How to get the correct MethodInfo for "Where" extension method如何为“Where”扩展方法获取正确的 MethodInfo
【发布时间】:2014-04-02 18:01:24
【问题描述】:

我正在尝试使用反射返回正确的“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 )});

and(也返回 null)

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

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

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

有人可以帮忙吗?

谢谢

【问题讨论】:

    标签: c# expression where methodinfo


    【解决方案1】:

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

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

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

    【讨论】:

    • 非常感谢,我认为你是对的。这种方式有效且代码更少 - 再次感谢
    【解决方案2】:

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

    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();
    

    【讨论】:

    • 这行得通,非常感谢....现在让它在我的自定义表达式中工作! :-)
    【解决方案3】:

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

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

    【讨论】:

      【解决方案4】:

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

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

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

      【讨论】:

      • 感谢您的想法。上面没有编译(无效参数),所以我尝试了: var methodWhere = typeof(Enumerable).GetMethod("Where", new Type[] { typeof(IEnumerable), typeof(Func ) });但不幸的是,这返回 null 。我会看看我是否可以暂时尝试一下你的想法并让它发挥作用....
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-19
      • 1970-01-01
      相关资源
      最近更新 更多