8

我有 IQueryable<T> 源,我想动态调用 IQueryable<T>.Count()。

所以,我需要在 IQueryable 中声明的 Count 方法的 MethodInfo。

这是来自 msdn 的签名(在 IQueryable<> 中):

public static int Count<TSource>(
    this IQueryable<TSource> source
)

这是我走了多远:

Expression expr; //this is expression which holds my IQueryable<T>
MethodInfo mi = expr.Type.GetMethod("Count", BindingFlags.Static | BindingFlags.Public, null, new[] { expr.Type }, null); 

但我的 mi 始终为空;

我也试过:

mi = typeof(IQueryable<>).GetMethod("Count", BindingFlags.Static | BindingFlags.Public, null, new[] { expr.Type }, null);

但又为空。

我的最终目标是:

Expression.Call(mi, expr);

更新:这就是我获得 Sum Extension 方法的方式:

MethodInfo sum = typeof(Queryable).GetMethod("Sum", BindingFlags.Static | BindingFlags.Public, null, new[] { typeof(IQueryable<decimal>) }, null);

这行得通,但是这个 Sum 方法不是通用的。它虽然是静态的。

4

2 回答 2

9

您需要破解IQueryable<T>类型的通用参数并使用它;拥有该方法的类型也不是IQueryable<T>,它是Queryable- 如果你考虑一下 - 接口不能有静态方法(嗯,正如评论者指出的那样,在 C# 中):)。

此外,因为它是一种泛型方法,所以您无法以您尝试过的方式匹配参数:因为您需要传递泛型类型定义 IQuerable<TSource>-而不是泛型类型 IQueryable<int>或任何实际表达式。

相反,您可以在类型上查找名为“Count”的静态方法的单参数版本Queryable

Type genericArgument = expr.GetGenericArguments()[0];

MethodInfo countMethod = typeof(Queryable)
              .GetMethods(BindingFlags.Static | BindingFlags.Public)
              //narrow the search before doing 'Single()'
              .Single(mi => mi.Name == "Count"
                         // this check technically not required, but more future proof
                         && mi.IsGenericMethodDefinition
                         && mi.GetParameters().Length == 1)
              .MakeGenericMethod(genericArgument);

//now you can bind to 'countMethod'

2017 年 3 月 7 日更新- 显然,框架中发生了一些变化,导致代码示例的原始版本无法工作 - 这是一个应该可以工作的更新版本

再深入一点 - 该方法的签名是:

public static int Count<TSource>(
  this IQueryable<TSource> source
)

因此,虽然参数类型是IQueryable<TSource>泛型的,但它是泛型的TSource——这就是为什么你需要深入你的IQueryable<TSource>表达式并抓住它的泛型参数的原因。你也应该能够看到我对这里参数的意思。

于 2012-04-23T08:29:21.563 回答
3

让编译器为您获取方法。

Type genericArgument = expr.GetGenericArguments()[0];
var fakeExp = (Expression<Func<IQueryable<int>, int>>)(q => q.Count());
var mi = ((MethodCallExpression)fakeExp.Body).Method.GetGenericMethodDefinition().MakeGenericMethod(genericArgument);
于 2014-06-04T20:05:45.723 回答