【问题标题】:Override IEnumerable<T> Where覆盖 IEnumerable<T> 在哪里
【发布时间】:2015-08-25 16:07:41
【问题描述】:

我写了一个实现 IEnumerable 的类:

public class MyEnumerable : IEnumerable<MyClass>
{ 
    IEnumerator IEnumerable.GetEnumerator()
    {
        return this.GetEnumerator();
    }
    public IEnumerator<MyClass> GetEnumerator()
    {
        //Enumerate
    }
}

我想“覆盖” Where 方法。我想做的是:

MyEnumerable myEnumerable = new MyEnumerable();
MyEnumerable myEnumerable2 = myEnumerable.Where(/*some predicate*/);

目前这是不可能的,因为 myEnumerable.Where() 返回一个 IEnumerable。 我想要的是 myEnumerable.Where() 返回一个 MyEnumerable。

这样可以吗?

谢谢

【问题讨论】:

  • 你为什么要实现自己的 Enumerable?它给你买了什么?使用 yield 和 Linq,越来越少需要实现自己的可枚举类。

标签: c# generics ienumerable


【解决方案1】:

当然 - 只需将 Where 方法添加到 MyEnumerable。 Linq Where 方法是一个extension 方法,所以它在技术上不是一个覆盖。您正在“隐藏” linq 方法。

public class MyEnumerable : IEnumerable<MyClass>
{ 
    IEnumerator IEnumerable.GetEnumerator()
    {
        return this.GetEnumerator();
    }
    public IEnumerator<MyClass> GetEnumerator()
    {
        //Enumerate
    }

    public MyEnumerable Where()
    {
       // implement `Where`
    }
}

不过有一些注意事项:

  • 只有在声明的类型为 MyEnumerable 时才会调用您的 Where 方法 - 它不会在 IEnumerable&lt;MyClass&gt; 类型的变量上调用(或任何实现它的集合,如 List&lt;MyClass&gt;
  • 如果您想与 Linq 保持一致,还需要实现 Where 的多个重载。

【讨论】:

  • 认为特定类的显式扩展将优先于通用版本 - public static MyEnumerable Where(this IEnumerator&lt;MyClass&gt; sequence, ...) 所以第一个警告可能会得到解决。
【解决方案2】:

更新

根据您的评论,您的枚举器是一个惰性文件枚举器,您希望能够根据谓词从中选择项目并且仍然具有惰性。

您可以创建另一个继承该类的类或接口来帮助解决此问题。

这是一个例子

public class FileItem
{
    //Some properties
}

public interface IFileEnumerator : IEnumerable<FileItem>
{
    IFileEnumerator Where(Func<FileItem, bool> predicate);
}

public class FileEnumerator : IFileEnumerator
{
    private readonly string fileName;

    public FileEnumerator(string fileName)
    {
        this.fileName = fileName;
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return this.GetEnumerator();
    }

    public IEnumerator<FileItem> GetEnumerator()
    {
        var items = new List<FileItem>();

        //Read from file and add lines to items

        return items.GetEnumerator();
    }

    public IFileEnumerator Where(Func<FileItem, bool> predicate)
    {
        return new MemoryEnumerator(ToEnumerable(GetEnumerator()).Where(predicate));
    }

    private static IEnumerable<T> ToEnumerable<T>(IEnumerator<T> enumerator) 
    {
        while (enumerator.MoveNext()) 
        {
            yield return enumerator.Current;
        }
    }
}

public class MemoryEnumerator : IFileEnumerator
{
    private readonly IEnumerable<FileItem> items;

    public MemoryEnumerator(IEnumerable<FileItem> items)
    {
        this.items = items;
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return this.GetEnumerator();
    }

    public IEnumerator<FileItem> GetEnumerator()
    {
        return items.GetEnumerator();
    }

    public IFileEnumerator Where(Func<FileItem, bool> predicate)
    {
        return new MemoryEnumerator(items.Where(predicate));
    }
}

【讨论】:

  • 谢谢,我想我需要做这样的事情,但是...我从文件中读取项目。因此,项目列表填充在 GetEnumerator 中,以进行延迟加载。所以当调用 Where 方法时,items 为 null(或为空)。
  • 我根据您的评论做了一些更改。这对您有帮助吗?
  • 谢谢,它有效。我以同样的方式完成了 Take 和 Concat。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多