linq-Where
public static IEnumerableWhere (this IEnumerable source, Func bool> predicate) { if (source == null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source); } if (predicate == null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.predicate); } if (source is Iterator iterator) { return iterator.Where(predicate); } if (source is TSource[] array) { return array.Length == 0 ? Empty () : new WhereArrayIterator (array, predicate); } if (source is List list) { return new WhereListIterator (list, predicate); } return new WhereEnumerableIterator (source, predicate); }
public WhereEnumerableIterator(IEnumerablesource, Func bool> predicate) { Debug.Assert(source != null); Debug.Assert(predicate != null); _source = source; _predicate = predicate; }
原理中有一个延迟返回的方式yield,表示当实际需要数据的时候才会去执行predicate方法。返回数据。多次循环原理都是一样的,都要再去执行一下。一般都会把where到的数据存起来的。
public static class IEnumerableExtension { public static IEnumerableNewWhere (this IEnumerable items,Func bool> predicate) { //List data=new List foreach(var item in items) { if(predicate(item)) { //data.Add(item); yield return item; } } //return data; } }();
在自己的内部类中使用yield
public class Iteration: IEnumerable { public List<int> lstInfo = new List<int>() { 1, 3, 5, 7, 9, 11 }; public IEnumerator GetEnumerator() { for (int i = 0; i < lstInfo.Count; ++i) { yield return lstInfo[i]; } } }
看一案例:
class IteratorWorkflow { static readonly string Padding = new string(' ', 30); static IEnumerable<int> GetEnumerable() { Console.WriteLine("{0}Start of GetEnumerator()", Padding); for (int i = 0; i < 3; i++) { Console.WriteLine("{0}About to yield {1}", Padding, i); yield return i; Console.WriteLine("{0}After yield", Padding); } Console.WriteLine("{0}Yielding final value", Padding); yield return -1; Console.WriteLine("{0}End of GetEnumerator()", Padding); } public static void Main() { IEnumerable<int> iterable = GetEnumerable(); IEnumerator<int> iterator = iterable.GetEnumerator(); Console.WriteLine("Starting to iterate"); while (true) { Console.WriteLine("Calling MoveNext()..."); bool result = iterator.MoveNext(); Console.WriteLine("... MoveNext result={0}", result); if (!result) { break; } Console.WriteLine("Fetching Current..."); Console.WriteLine("... Current result={0}", iterator.Current); } }
结果是:
Starting to iterate Calling MoveNext()... Start of GetEnumerator() About to yield 0 ... MoveNext result=True Fetching Current... ... Current result=0 Calling MoveNext()... After yield About to yield 1 ... MoveNext result=True Fetching Current... ... Current result=1 Calling MoveNext()... After yield About to yield 2 ... MoveNext result=True Fetching Current... ... Current result=2 Calling MoveNext()... After yield Yielding final value ... MoveNext result=True Fetching Current... ... Current result=-1 Calling MoveNext()... End of GetEnumerator() ... MoveNext result=False
来看下List的迭代器实现:
public struct Enumerator : IEnumerator, System.Collections.IEnumerator { private List list; private int index; private int version; private T current; internal Enumerator(List list) { this.list = list; index = 0; version = list._version; current = default(T); } public void Dispose() { } public bool MoveNext() { List localList = list; if (version == localList._version && ((uint)index < (uint)localList._size)) { current = localList._items[index]; index++; return true; } return MoveNextRare(); } private bool MoveNextRare() { if (version != list._version) { ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion); } index = list._size + 1; current = default(T); return false; } public T Current { get { return current; } } Object System.Collections.IEnumerator.Current { get { if( index == 0 || index == list._size + 1) { ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumOpCantHappen); } return Current; } } void System.Collections.IEnumerator.Reset() { if (version != list._version) { ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion); } index = 0; current = default(T); } }