首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么不能在IOrderedEnumerable中使用迭代器块

为什么不能在IOrderedEnumerable中使用迭代器块
EN

Stack Overflow用户
提问于 2012-10-17 02:41:35
回答 2查看 4.8K关注 0票数 2

我写了这个:

代码语言:javascript
复制
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;
        }
    }
}

然后用这个测试它:

代码语言:javascript
复制
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,但是,随着拳打脚踢,我试着:

代码语言:javascript
复制
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不是迭代器接口类型。

我遗漏了什么?我不明白为什么人们不想像对待原始集合那样迭代有序集合。

(使用Mono2.10.8.1,即有效的C# 4.0和MonoDevelop 2.8.6.3)

更新:

正如joshgo亲切地指出的,我可以接受IOrderedEnumerable的一个输入参数,它确实充当-一个IEnumerable。但是要迭代,我必须返回IEnumerable,而我最初的错误是由ThenBy引起的,它坚持要得到IOrderedEnumerable。也很合理。但是,这里有满足ThenBy的方法吗?

UPDATE2:

在两个答案中都使用了代码(这两个答案都非常有用)之后,我终于理解了为什么不能使用IOrderedEnumerable返回时的结果:没有意义,因为要进行排序,这些值必须是完全可用的。因此,我可以使用一个循环来打印出所有的项目,然后在结束时只返回一次源,而不是一个包含产额的循环。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-10-17 03:19:23

我相信对这个错误的解释可以在这里找到:Some help understanding "yield"

引用Lasse V. Karlsen的话:

必须将使用收益率返回的方法声明为返回以下两个接口之一: IEnumerable或IEnumerator

问题似乎与yield操作符和第二个函数IOrderedEnumerable的返回类型有关。

如果您将返回类型从IOrderedEnumerable更改为IEnumerable,那么第二个IEnumerable()调用将不再是一个错误。但是,ThenBy()调用现在将抛出一个错误。如果您暂时注释掉它,它将编译,但您确实失去了对ThenBy()方法的访问权限。

代码语言:javascript
复制
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);
}

..。

代码语言:javascript
复制
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;
    }
}
票数 2
EN

Stack Overflow用户

发布于 2012-10-17 09:12:45

如果要在操作后应用扩展方法(返回IOrdereEnumerable并继续排序),则需要创建第二个重载扩展:

代码语言:javascript
复制
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之前

代码语言:javascript
复制
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;    
}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/12926313

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档