C#迭代器

发布于:2025-06-14 ⋅ 阅读:(15) ⋅ 点赞:(0)

文档

C# Iterators

关键内容

  1. 普通接口
public interface IEnumerable
{
    IEnumerator GetEnumerator();
}

public interface IEnumerator
{
    object Current { get; }

    bool MoveNext();
    void Reset();
}
  1. 泛型接口
public interface IEnumerable<out T> : IEnumerable
{
    IEnumerator<T> GetEnumerator();
}
public interface IEnumerator<out T> : IEnumerator, IDisposable
{
    T Current { get; }
}
  1. yield return
    使用yield return可简化迭代器的生成,不需要自己手动创建类进行实现。
    注意:使用yield return生成的迭代器,无法使用Reset。
    如需Reset,可自定义迭代器类,进行实现。

示例

TransformForeach1实现泛型接口IEnumerable,自己实现迭代器
TransformForeach2实现泛型接口IEnumerable,使用yield return实现迭代器
对比得知:yield return 可方便的简化迭代器生成
注意:如果实现泛型版本接口,yield return 返回类型要和泛型指定的类型一致

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Test04 : MonoBehaviour
{
    TransformForeach1 foreachTransform1;
    IEnumerator<Transform> ator1;

    TransformForeach2 foreachTransform2;
    IEnumerator<Transform> ator2;

    void Start()
    {
        int childCount = 5;
        for (int i = 0; i < childCount; i++)
        {
            var obj = new GameObject(i.ToString());
            obj.transform.SetParent(transform);
        }

        foreachTransform1 = new TransformForeach1(transform);
        ator1 = foreachTransform1.GetEnumerator();

        foreachTransform2 = new TransformForeach2(transform);
        ator2 = foreachTransform2.GetEnumerator();
    }

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            //使用类实现泛型迭代器接口 可使用Reset方法
            Debug.Log("1...");
            while (ator1.MoveNext())
            {
                Debug.Log(ator1.Current);
            }
            ator1.Reset();
            foreach (var item in foreachTransform1)
            {
                Debug.Log(item);
            }
            Debug.Log("2...");
            //使用yield return实现泛型迭代器接口,无法使用Reset方法
            try
            {
                while (ator2.MoveNext())
                {
                    Debug.Log(ator2.Current);
                }
                ator2.Reset();
            }
            catch (System.Exception e)
            {
               Debug.LogException(e);
            }        
            foreach (var item in foreachTransform2)
            {
                Debug.Log(item);
            }
        }
    }

    private class TransformForeach1 : IEnumerable<Transform>
    {
        Transform transform;

        public TransformForeach1(Transform transform)
        {
            this.transform = transform;
        }

        public IEnumerator<Transform> GetEnumerator()
        {
            return new Enumerator(transform);
        }

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

        private class Enumerator : IEnumerator<Transform>
        {
            int index = -1;
            Transform transform;

            public Enumerator(Transform transform)
            {
                this.transform = transform;
            }

            public Transform Current => transform.GetChild(index);

            object IEnumerator.Current => Current;

            public void Dispose()
            {

            }

            public bool MoveNext()
            {
                var childCount = transform.childCount;
                return ++index < childCount;
            }

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

    private class TransformForeach2 : IEnumerable<Transform>
    {
        Transform transform;
     
        public TransformForeach2(Transform transform)
        {
            this.transform = transform;
        }
      
        public IEnumerator<Transform> GetEnumerator()
        {
            var length = transform.childCount;
            for (int i = 0; i < length; i++)
                yield return transform.GetChild(i);
        }
      
        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }
}