【问题标题】:Implementing filtered Iterator without using yield return在不使用 yield return 的情况下实现过滤的 Iterator
【发布时间】:2014-07-24 03:21:00
【问题描述】:

我正在尝试显示带有过滤器和不带过滤器的列表元素。在这里,我使用过滤器来显示可被 3 整除的元素。我将使用 Enumerable 和 Enumerator 接口来实现列表迭代。我正在努力解决这个问题,但我空手而归,我确信逻辑并且无法追踪我犯错的地方。所以,我只是把我所有的代码放在下面。

在FilterDisplay类中,定义了list并调用了GetEnumerator()方法,它被用作

     public class FilterDisplay {
           public void TestIterators(){
          List<int> myList = new List<int> { 3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5 };
          for (int i = 0; i < myList.Count; i++)
            Console.Write("{0} ", myList[i]);
          Console.WriteLine();

          IEnumerator<int> pi = myList.GetEnumerator();
          while (pi.MoveNext()){
            int x = pi.Current;
            Console.Write("{0} ", x);
          }
          Console.WriteLine();

          MyIntList myIntList = new MyIntList { 3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5 };
          IEnumerator<int> px = myIntList.GetEnumerator(x => 0 == x % 3);
          while ( px.MoveNext())
            Console.Write("{0} ", px.Current);
          Console.WriteLine();         // displays 3 9 6 3

          Console.ReadKey();
        }
      }
     }

MyIntList 类实现列表接口,GetEnumerator 在类中被定义和覆盖为;

public class MyIntList : IList<int>{
    public List<int> MyList = new List<int>();
    public MyIntList() {  }

    public void Add(int item) { MyList.Add(item); }

    public IEnumerator<int> GetEnumerator(){
        return new Enumerator1(MyList);
    }

    public IEnumerator<int> GetEnumerator(Func<int, bool> filter){
        return new Enumerator1(filter, MyList);
    }

在 Enumerator1 类中,我将定义两个构造函数来实现 list 和 list with filter。在这里,我试图覆盖 MoveNext() 和 Current。当我尝试调试项目时,它在 Current 显示错误。但是,我确信这样定义没有错误。

class Enumerator1 : IEnumerator<int>{
        private int i = -1;
        private MyIntList IntList;

        private Func<int, bool> NewFilter;
        private IEnumerator<int> NewMyList;

        public Enumerator1(IEnumerable<int> list){
            this.NewMyList = list.GetEnumerator();
        }

        public Enumerator1(Func<int, bool> filter, IEnumerable<int> list){
            this.NewFilter = filter;
            this.NewMyList = list.GetEnumerator();
        }

        public bool MoveNext(){
            i++;
            return i < IntList.MyList.Count;
        }

        public int Current { get { return IntList.MyList[i]; } }
        object IEnumerator<int>.Current { get { return NewMyList.Current; } }

        public void Dispose() { }
        public void Reset() { throw new NotSupportedException(); }
    }

除了使用收益回报之外,我欢迎任何建议,谢谢。

【问题讨论】:

  • 哪个Current?由于MoveNext 没有反映它,因此显式实现的可能表现得很奇怪(阅读:损坏)。
  • object IEnumerator.Current 给出错误 - 显式接口声明不是接口的成员。 @Telastyn
  • 我没明白你的意思 MoveNext 没有反映它。
  • 为什么不想使用yield?为什么不简单地使用 Linq 的 Where(i => i % 3 == 0)?
  • 这和your earlier question有什么区别?

标签: c# design-patterns oop


【解决方案1】:

我不明白您为什么要这样做(可能是因为“yield return”会破坏 Visual Studio 中的修复并继续?),但如果您尝试创建过滤枚举器,这里有一个:

public class FilteredEnumerator<T> : System.Collections.Generic.IEnumerator<T>
{
    readonly System.Collections.Generic.IEnumerator<T> enumerator;
    readonly System.Func<T, bool> filter; // could be null

    public FilteredEnumerator(System.Collections.Generic.IEnumerable<T> enumerable) : this(enumerable, null) { }

    public FilteredEnumerator(System.Collections.Generic.IEnumerable<T> enumerable, System.Func<T, bool> filter)
    {
        if (enumerable == null)
            throw new System.ArgumentNullException();
        this.enumerator = enumerable.GetEnumerator();
        this.filter = filter; // could be null for unconditional enumeration.
    }

    #region IEnumerator<T> Members

    public T Current { get { return enumerator.Current; } }

    #endregion

    #region IDisposable Members

    public void Dispose()
    {
        enumerator.Dispose();
    }

    #endregion

    #region IEnumerator Members

    object System.Collections.IEnumerator.Current { get { return Current; } }

    public bool MoveNext()
    {
        while (enumerator.MoveNext())
        {
            if (filter == null || filter(enumerator.Current))
                return true;
        }
        return false;
    }

    public void Reset()
    {
        enumerator.Reset();
    }

    #endregion
}

【讨论】:

  • 我也反映了同样的情况。但是错误没有解决。 FilteredEnumerator 没有实现接口成员 IEnumerator.Current,因为它没有匹配的返回类型 'object' 和另一个:显式接口声明中的 'IEnumerator.Current' 不是接口的成员。 @dbc
  • "FilteredEnumerator 没有实现接口成员 IEnumerator.Current" -- 就在这里:object IEnumerator.Current { get { return Current; } }。 IEnumerable&lt;T&gt; 扩展 IEnumerable 所以它必须在那里编译。你在评论之前有没有尝试编译和测试代码?
  • 是的,出现了同样的错误。我在上面的评论中复制了错误。 @dbc
  • 我能想到的就是你以某种方式重新定义了 IEnumerable 的含义。我修改了代码以使用完全限定名称,这样就不会混淆命名空间。除此之外,它对我有用,祝你好运。
猜你喜欢
  • 2023-03-21
  • 2018-01-19
  • 2011-06-14
  • 1970-01-01
  • 1970-01-01
  • 2016-06-21
  • 1970-01-01
  • 2022-08-09
  • 2018-08-19
相关资源
最近更新 更多