[英]Why cannot use iterator block with IOrderedEnumerable
我這樣寫:
using System;using System.Linq;
static class MyExtensions
{
public static IEnumerable<T> Inspect<T> (this IEnumerable<T> source)
{
Console.WriteLine ("In Inspect");
//return source; //Works, but does nothing
foreach(T item in source){
Console.WriteLine(item);
yield return item;
}
}
}
然后去測試它:
var collection = Enumerable.Range(-5, 11)
.Select(x => new { Original = x, Square = x * x })
.Inspect()
.OrderBy(x => x.Square)
//.Inspect()
.ThenBy(x => x.Original)
;
foreach (var element in collection)
{
Console.WriteLine(element);
}
首次使用Inspect()
可以正常工作。 注釋掉的第二個不會編譯。 OrderBy
的返回值為IOrderedEnumerable
。 我還以為IOrderedEnumerable
是,一個 IEnumerable
,但是,與拳滾,我想:
public static IOrderedEnumerable<T> Inspect<T> (this IOrderedEnumerable<T> source)
{
Console.WriteLine ("In Inspect (ordered)");
foreach(T item in source){
Console.WriteLine(item);
yield return item;
}
}
但這也不會編譯。 我被告知我不能擁有迭代器塊,因為System.Linq.IOrderedEnumberable不是迭代器接口類型。
我想念什么? 我不明白為什么人們不希望像處理原始集合那樣遍歷有序集合。
(使用Mono 2.10.8.1(實際上是C#4.0)和MonoDevelop 2.8.6.3)
更新:
作為joshgo好心指出的那樣,我可以采取的輸入參數IOrderedEnumerable
,它確實起到-一個 IEnumerable
。 但是要進行迭代,我必須返回IEnumerable
,而我的原始錯誤是由ThenBy
引起的,后者堅持要求提供IOrderedEnumerable
。 也很合理。 但是在這里有什么方法可以滿足ThenBy
嗎?
UPDATE2:
在兩個答案中都使用了代碼(這兩個都是非常有用的)之后,我終於明白了為什么不能在IOrderedEnumerable返回中使用yield的原因:沒有意義,因為值必須完全可用才能執行分類。 因此,最好不要使用循環來打印所有項目,而只在最后一次返回source,而不是使用yield循環。
我相信可以在這里找到有關錯誤的解釋: 有助於理解“收益”
引用Lasse V.Karlsen:
使用yield return的方法必須聲明為返回以下兩個接口之一:IEnumerable或IEnumerator
問題似乎與yield
運算符和第二個函數IOrderedEnumerable
的返回類型有關。
如果將返回類型從IOrderedEnumerable
為IEnumerable
,則第二個Inspect()調用將不再是錯誤。 但是, ThenBy()
調用現在將引發錯誤。 如果暫時將其注釋掉,它將進行編譯,但是您確實無法訪問ThenBy()
方法。
var collection = Enumerable.Range(-5, 11)
.Select(x => new { Original = x, Square = x * x })
.Inspect()
.OrderBy(x => x.Square)
.Inspect()
//.ThenBy(x => x.Original)
;
foreach (var element in collection)
{
Console.WriteLine(element);
}
...
public static IEnumerable<T> Inspect<T> (this IOrderedEnumerable<T> source)
{
Console.WriteLine ("In Inspect (ordered)");
foreach(T item in source){
Console.WriteLine(item);
yield return item;
}
}
如果要在操作后應用擴展方法,該方法將返回IOrdereEnumerable
並繼續訂購,則需要創建第二個重載擴展:
public static IOrderedEnumerable<T> Inspect<T>(this IOrderedEnumerable<T> source)
{
Console.WriteLine("In Ordered Inspect");
// inspected items will be unordered
Func<T, int> selector = item => {
Console.WriteLine(item);
return 0; };
return source.CreateOrderedEnumerable(selector, null, false);
}
這里有趣的是:
IOrderedEnumerable
為了應用ThenBy
或ThenByDescending
IOrderedEnumerable
不是通過yield return
創建的。 在您的情況下,可以通過從源代碼創建它來實現 如果要查看訂購的商品,則需要執行OrderedEnumerable
。 這將強制執行所有在Inspect
之前出現的運算符:
public static IOrderedEnumerable<T> Inspect<T>(this IOrderedEnumerable<T> source)
{
Console.WriteLine("In Ordered Inspect");
var enumerable = source.CreateOrderedEnumerable(x => 0, null, false);
// each time you apply Inspect all query until this operator will be executed
foreach(var item in enumerable)
Console.WriteLine(item);
return enumerable;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.