23.自定义容器支持foreach循环

  1. 23.自定义容器支持foreach循环
    1. 23.1 题目
    2. 23.2 深入解析
      1. 传统方式
      2. 语法糖方式
      3. 总结
    3. 23.3 答题示例
    4. 23.4 关键词联想

23.自定义容器支持foreach循环


23.1 题目

C#中如何让自定义容器类能够使用foreach循环遍历?


23.2 深入解析

通过为自定义容器类实现迭代器,可以使其能够使用foreach循环遍历。下面介绍两种实现方式:

传统方式

实现 IEnumerable / IEnumerable<T>IEnumerator / IEnumerator<T>(或仅用 yield 实现 GetEnumerator),并提供相应成员。

步骤

  1. 实现IEnumerable接口的GetEnumerator方法。
  2. 实现IEnumerator接口的Current属性和MoveNext方法。

代码示例

using System;
using System.Collections;
using System.Collections.Generic;

public class MyContainer<T> : IEnumerable<T>
{
    private T[] items;
    private int count;

    public MyContainer(int capacity)
    {
        items = new T[capacity];
        count = 0;
    }

    public void Add(T item)
    {
        if (count < items.Length)
        {
            items[count++] = item;
        }
    }

    public IEnumerator<T> GetEnumerator()
    {
        return new MyEnumerator(this);
    }

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

    private class MyEnumerator : IEnumerator<T>
    {
        private MyContainer<T> container;
        private int index;

        public MyEnumerator(MyContainer<T> container)
        {
            this.container = container;
            index = -1;
        }

        public T Current
        {
            get
            {
                if (index >= 0 && index < container.count)
                {
                    return container.items[index];
                }
                throw new InvalidOperationException();
            }
        }

        object IEnumerator.Current => Current;

        public bool MoveNext()
        {
            return ++index < container.count;
        }

        public void Reset()
        {
            index = -1;
        }

        public void Dispose() { }
    }
}

语法糖方式

利用yield return语法糖,只需实现GetEnumerator方法即可完成迭代器的实现。

代码示例

using System;
using System.Collections.Generic;

public class MyContainer<T> : IEnumerable<T>
{
    private T[] items;
    private int count;

    public MyContainer(int capacity)
    {
        items = new T[capacity];
        count = 0;
    }

    public void Add(T item)
    {
        if (count < items.Length)
        {
            items[count++] = item;
        }
    }

    public IEnumerator<T> GetEnumerator()
    {
        for (int i = 0; i < count; i++)
        {
            yield return items[i];
        }
    }

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

总结

  • 传统方式:手动实现 IEnumerator<T>IEnumerable<T> 的成员。适合需要更多控制的复杂场景。
  • 语法糖方式:利用yield return语法糖,简化了迭代器的实现,适合大多数场景。

通过上述两种方式,可以让自定义容器类支持foreach循环遍历,使代码更加简洁和易于维护。


23.3 答题示例

“在C#中让自定义容器支持foreach循环遍历需实现迭代器(Iterator),核心是通过实现IEnumerable<T>接口并提供GetEnumerator方法。具体实现方式有两种:

  1. 传统接口实现
    • 容器类需继承IEnumerable<T>接口,并实现GetEnumerator方法返回一个IEnumerator<T>对象。
    • 枚举器类需实现IEnumerator<T>接口的MoveNext(移动游标)、Current(获取当前元素)和Reset(重置游标)方法。
    • 示例代码
      public class MyContainer<T> : IEnumerable<T> {  
          private T[] items;  
          public IEnumerator<T> GetEnumerator() {  
              return new MyEnumerator(this);  
          }  
          private class MyEnumerator : IEnumerator<T> {  
              private MyContainer<T> container;  
              private int index = -1;  
              public T Current => container.items[index];  
              object IEnumerator.Current => Current;  
              public bool MoveNext() => ++index < container.items.Length;  
              public void Reset() => index = -1;  
              public void Dispose() { }  
          }  
      }  
      
  2. 语法糖方式(推荐)
    • 利用yield return关键字简化迭代器实现,只需在GetEnumerator方法中使用循环逐个返回元素。
    • 示例代码
      public class MyContainer<T> : IEnumerable<T> {  
          private T[] items;  
          public IEnumerator<T> GetEnumerator() {  
              for (int i = 0; i < items.Length; i++) {  
                  yield return items[i];  // 自动生成迭代器逻辑  
              }  
          }  
      }  
      
  3. 使用场景
    • 传统方式:适合需要自定义迭代逻辑(如延迟加载、复杂过滤)的场景。
    • 语法糖方式:适用于简单线性遍历,代码简洁且不易出错。
      最终,通过实现IEnumerable<T>接口,容器类即可直接使用foreach循环遍历元素。”

23.4 关键词联想

  • IEnumerable 接口
  • IEnumerator 枚举器
  • yield return 语法糖
  • MoveNext() 方法
  • Current 属性
  • 迭代器模式(Iterator Pattern)
  • 泛型集合(Generic Collection)
  • 延迟加载(Lazy Loading)
  • 枚举器状态管理
  • Dispose() 方法


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏