2010-09-27 44 views
2

你會如何建議在非泛型IQueryable上使用AsEnumerable非泛型AsEnumerable

我不能底層IQueryProvider使用Cast<T>OfType<T>方法調用AsEnumerable之前得到一個IQueryable<object>,因爲這些方法都有自己明確的翻譯,如果我有一個非映射實體使用它們會破壞查詢翻譯(明顯對象未映射)。

現在,我有我自己的擴展方法(下面),但我想知道是否有一種方法內置到框架。

public static IEnumerable AsEnumerable(this IQueryable queryable) 
{ 
    foreach (var item in queryable) 
    { 
     yield return item; 
    } 
} 

因此,上述擴展方法,我現在可以做的事:

IQueryable myQuery = // some query... 

// this uses the built in AsEnumerable, but breaks the IQueryable's provider because object is not mapped to the underlying datasource (and cannot be) 
var result = myQuery.Cast<object>().AsEnumerable().Select(x => ....); 

// this works (and uses the extension method defined above), but I'm wondering if there's a way in the framework to accomplish this 
var result = myQuery.AsEnumerable().Cast<object>().Select(x => ...); 

回答

4

由於接口IQueryableIEnumerable繼承爲什麼不:

IQueryable queryable; 
IEnumerable<T> = (queryable as IEnumerable).Cast<T>(); 

編輯
有兩種Cast<>擴展方法:

public static IQueryable<TResult> Cast<TResult>(this IQueryable source) 
public static IEnumerable<TResult> Cast<TResult>(this IEnumerable source) 

哪一個被稱爲靜態編譯器決定。因此將IQueryable作爲IEnumerable將導致第二個擴展方法被調用,在那裏它將被視爲IEnumerable

+0

嗯......實際上是否會調用Cast 或IEnumerable實現的IQueryable實現?也就是說,第二行真的只是一個IEnumerable,還是它實際上仍然是一個IQueryable? – Jeff 2010-09-27 14:54:02

+0

@Jeff - 請參閱我的編輯 – Greg 2010-09-27 15:00:04

+1

@ JeffN825,編譯器只會知道它是IEnumerable,因此會鏈接到Enumerable.Cast 實現。 – 2010-09-27 15:01:02

3

類型IQueryable從非通用IEnumerable繼承所以這種擴展方法似乎並不起任何作用。爲什麼不直接使用它作爲IEnumerable

+5

它通過強制查詢來枚舉併成爲內存來達到目的。我使用它,因爲我可以隨後使用Cast 或OfType 具有所需的效果。 – Jeff 2010-09-27 14:47:17

4

JaredPar的答案換句話說:

public static IEnumerable AsEnumerable(this IEnumerable source) 
{ 
    return source; 
} 

用法:

IQueryable queryable = // ... 
IEnumerable enumerable = queryable.AsEnumerable(); 
IEnumerable<Foo> result = enumerable.Cast<Foo>(); 
//          ↑ 
//       Enumerable.Cast<TResult>(this IEnumerable source) 
+0

這是不正確的,參見上文。 – Jeff 2010-09-27 14:50:49

+0

@ JeffN825:這完全是*通用的Enumerable.AsEnumerable 擴展方法。您可以使用反射器來確認這一點。 – dtb 2010-09-27 14:53:15

+0

@dtb,但它是一個IQueryable。當然這就是Enumerable版本所做的...注意不同的簽名:'公共靜態IEnumerable AsEnumerable (這個IEnumerable 源)' – 2010-09-27 14:56:38

3

爲了澄清,您試圖向您的linq表達式樹添加一個「強制表達式評估」,以便部分表達式樹針對底層提供者進行評估(例如,linq to SQL),其餘部分在內存中計算(linq到對象)。但是您希望能夠指定整個快速樹,而無需實際執行查詢或將任何結果讀入內存。

這是一件好事,它展示了Linq工作方式的一些洞察。做得好。

我在這裏看到的混淆是你使用「AsEnumerable」作爲方法名稱。對我來說(我認爲許多thinq linq)「AsEnumerable」與「AsQueryable」方法過於相似,它本質上是一個演員,而不是實際的評估者。我建議您將您的方法重命名爲「評估」。這是我的個人Linq擴展庫中的Evaluate()方法。

/// <summary> 
    /// This call forces immediate evaluation of the expression tree. 
    /// Any earlier expressions are evaluated immediately against the underlying IQueryable (perhaps 
    /// a Linq to SQL provider) while any later expressions are evaluated against the resulting object 
    /// graph in memory. 
    /// This is one way to determine whether expressions get evaluated by the underlying provider or 
    /// by Linq to Objects in memory. 
    /// </summary> 
    public static IEnumerable<T> Evaluate<T>(this IEnumerable<T> expression) 
    { 
     foreach (var item in expression) 
     { 
      yield return item; 
     } 
    } 

    /// <summary> 
    /// This call forces immediate evaluation of the expression tree. 
    /// Any earlier expressions are evaluated immediately against the underlying IQueryable (perhaps 
    /// a Linq to SQL provider) while any later expressions are evaluated against the resulting object 
    /// graph in memory. 
    /// This is one way to determine whether expressions get evaluated by the underlying provider or 
    /// by Linq to Objects in memory. 
    /// </summary> 
    public static IEnumerable Evaluate(this IEnumerable expression) 
    { 
     foreach (var item in expression) 
     { 
      yield return item; 
     } 
    } 

這允許您編寫一個查詢,其中某些查詢由SQL進行評估(例如),其餘查詢在內存中進行評估。一件好事。