2012-04-23 32 views
7

我有IQueryable < T>源,我想動態調用IQueryable < T> .Count()。獲取MethodInfo的Count()任意IQueryable上的LINQ擴展方法<T>

所以,我需要在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); 

UPDATE: 我這是怎麼弄總和擴展方法:

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

和這個工作,但這筆款項的方法是不通用的。它雖然是靜態的。

回答

8

您需要弄清IQueryable<T>類型的泛型參數並使用它;也是擁有該方法的類型不是IQueryable<T>,它是Queryable - 如果你考慮它 - 接口不能有靜態方法(就像一個評論者指出的那樣,在C#中):)。

而且,因爲它是一個通用的方法,你可以不匹配你嘗試的方式的參數:因爲你需要傳遞泛型類型定義IQuerable<TSource> - 通用IQueryable<int>或什麼實際的表達是。

相反,你可以隨便找一個靜態方法的單參數化版本,稱爲「計數」的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>表達,抓住它的通用說法的原因。你也應該能夠看到我的意思是關於這裏的參數。

+0

好的,謝謝。我會試試看。 – 2012-04-23 08:36:17

+0

我試過了,但它仍然是空的: Type type = expr.Type.GetGenericArguments()[0]; MethodInfo mi = typeof(Queryable).GetMethod(「Count」,BindingFlags.Static | BindingFlags.Public,null,new [] {type},null); 但是,如果我理解正確,最後一個函數應該返回一些我提供的類型作爲第四個參數,對吧? – 2012-04-23 08:45:22

+0

@MilosMijatovic我的初步答案是不*很*已更新 – 2012-04-23 08:50:40

2

讓編譯器爲您獲取方法。

Type genericArgument = expr.GetGenericArguments()[0]; 
var fakeExp = (Expression<Func<IQueryable<int>, int>>)(q => q.Count()); 
var mi = ((MethodCallExpression)fakeExp.Body).Method.GetGenericMethodDefinition().MakeGenericMethod(genericArgument); 
+0

當我嘗試時Expression countEx = Expression.Call(propEx,mi);它給我錯誤:靜態方法需要空實例,非靜態方法需要非空實例。 參數名稱:instance – Roman 2015-05-24 14:03:34

+1

使用將MethodInfo作爲第一個參數的重載(https://msdn.microsoft.com/en-us/library/dd323922%28v=vs.110%29.aspx) Count is a System.Linq.Queryable類中的靜態擴展方法;) – MBoros 2015-05-25 10:06:00

+0

Cheeeeeers !!現在它工作了!多謝兄弟!我更喜歡這個答案,因爲這個對我來說更加清楚。 – Roman 2015-05-25 16:21:16