c# Yield return之简单方法实现迭代器和集合初始化器

背景:最近看 C# in Depth ,谈到初始化器的时候上面说是主要看类中的Add方法,当时第一感觉是有这么神奇,有这个方法就能实现初始化器?然后我就自己写了一个只有Add()的List,初始化的时候提示要实现IComarable,想到这本书中还谈到一个简单的方法:用yield return实现用这个接口来完成迭代器功能,一举两得,学习两个知识点。

注:List代码主要是利用了微软的原代码:http://referencesource.microsoft.com/#mscorlib/system/collections/generic/list.cs,cf7f4095e4de7646

第一版

class MyList    
{
        private const int _defaultCapacity = 4;
        private T[] _items;
        private int _size;
        static readonly T[] _emptyArray = new T[0];
        public MyList()
        {
            _items = _emptyArray;
        }
        public int Capacity
        {
            get
            {
                return _items.Length;
            }
            set
            {
                if (value < _size)
                    throw new ArgumentOutOfRangeException("value");
                if (value != _items.Length)
                {
                    if (value > 0)
                    {
                        T[] newItems = new T[value];
                        if (_size > 0)
                        {
                            Array.Copy(_items, 0, newItems, 0, _size); 
                        }
                        _items = newItems;
                    }
                    else
                    {
                        _items = _emptyArray;
                    }
                }
            }
        }
        public void Add(T item)
        {
            if (_size == _items.Length)
                EnsureCapacity(_size + 1);
            _items[_size++] = item;
        }
        private void EnsureCapacity(int min)
        {
            if (_items.Length < min)
            {
                int newCapacity = _items.Length == 0 ? _defaultCapacity : _items.Length * 2;
                //if ((uint)newCapacity > Array.MaxArrayLength) newCapacity = Array.MaxArrayLength;
                if (newCapacity < min) newCapacity = min;
                Capacity = newCapacity;
            }
        }
}

static void Main(string[] args)
        {
            MyList myList = new MyList { "asdf ", "dfa" };
            Console.ReadKey();
        }
运行的时候会提示:无法使用集合初始舒畅一初始化类型,原因是它未实现”System.Colletions.IEnumberable”。

第二版:主要是实现了System.Colletions.IEnumberable接口


class MyList : IEnumerable
{
……//同上段代码
  public Enumerator GetEnumerator()
        {
            return new Enumerator(this);
        }
        IEnumerator IEnumerable.GetEnumerator()
        {
            return new Enumerator(this);
        }
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return new Enumerator(this);
        }
        public struct Enumerator : IEnumerator, IEnumerator
        {
            private MyList list;
            private int index;
            private T current;
            public Enumerator(MyList list)
            {
                this.list = list;
                index = 0;
                current = default(T);
            }
            public void Dispose()
            { }


            public bool MoveNext()
            {
                MyList localList = list;
                if ((uint)index < (uint)localList._size)
                {
                    current = localList._items[index];
                    index++;
                    return true;
                }
                return MoveNextRare();
            }

            private bool MoveNextRare()
            {
                index = list._size + 1;
                current = default(T);
                return false;
            }
            public T Current
            {
                get
                {
                    return current;
                }
            }
            object IEnumerator.Current
            {
                get
                {
                    return current;
                }
            }
            void IEnumerator.Reset()
            {
                index = 0;
                current = default(T);
            }

}

初始化器和迭代功能都可以正常使用

第三版:使用yield return完成迭代器功能

注:将上段实现迭代器代码全部用下面代码替代

 public IEnumerator GetEnumerator()
        {
            return new Enumerator(this).GetEnumerator();
        }


        public struct Enumerator : IEnumerable
        {
            private MyList list;
            private int index;
            private T current;
            public Enumerator(MyList list)
            {
                this.list = list;
                index = 0;
                current = default(T);
            }
            public void Dispose()
            { }
            public IEnumerator GetEnumerator()
            {
                for (int index = 0; index < list._size; index++)
                {
                    yield return current = list._items[index];
                }
            }
      }

另外如果把Add方法改名会提示:并不包含“Add”的定义

结论:yield return可以简单地实现迭代功能,大大的简化了代码,具体的奥秘还得深入学习。





你可能感兴趣的:(C#学习)