簡體   English   中英

為什么不能將迭代器塊與IOrderedEnumerable一起使用

[英]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的返回類型有關。

如果將返回類型從IOrderedEnumerableIEnumerable ,則第二個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為了應用ThenByThenByDescending
  • 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM