背景:最近看 C# in Depth ,谈到初始化器的时候上面说是主要看类中的Add方法,当时第一感觉是有这么神奇,有这个方法就能实现初始化器?然后我就自己写了一个只有Add()的List,初始化的时候提示要实现IComarable,想到这本书中还谈到一个简单的方法:用yield return实现用这个接口来完成迭代器功能,一举两得,学习两个知识点。
注:List代码主要是利用了微软的原代码:http://referencesource.microsoft.com/#mscorlib/system/collections/generic/list.cs,cf7f4095e4de7646
第一版
class MyList<T>
{
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<string> myList = new MyList<string> { "asdf ", "dfa" };
Console.ReadKey();
}
运行的时候会提示:无法使用集合初始舒畅一初始化类型,原因是它未实现”System.Colletions.IEnumberable”。
第二版:主要是实现了System.Colletions.IEnumberable接口
class MyList<T> : IEnumerable
{
……//同上段代码
public Enumerator GetEnumerator()
{
return new Enumerator(this);
}
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return new Enumerator(this);
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return new Enumerator(this);
}
public struct Enumerator : IEnumerator<T>, IEnumerator
{
private MyList<T> list;
private int index;
private T current;
public Enumerator(MyList<T> list)
{
this.list = list;
index = 0;
current = default(T);
}
public void Dispose()
{ }
public bool MoveNext()
{
MyList<T> 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<T> list;
private int index;
private T current;
public Enumerator(MyList<T> 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可以简单地实现迭代功能,大大的简化了代码,具体的奥秘还得深入学习。