在开发过程中,LINQ代码库中的Select方法经常被使用,为了更好的了解该方法,我们从源码的角度对其进行分析。了解如何以最优的方式,使用该方法,从而提升代码的性能。
Select方法的基本功能是将序列中的每个元素投影为新形式。LINQ提供了两个重载方法
方法名称 | 基本介绍 |
---|---|
Select |
将序列中的每个元素投影为新形式。 |
Select |
通过合并元素的索引,将序列中的每个元素投影为新形式。 |
两个方法的主要区别是第二个方法支持序列的索引参数。
与其他LINQ方法类似,Select方法是实现基础也是迭代器。基于不同的数据结构,定义了不同的迭代器。这些迭代器都继承了基类迭代器Iterator,从而获得了多线程支持和嵌套循环的支持。如果要了解更过的迭代器基础内容,请参考我的博文 C# LINQ源码分析之迭代器
编号 | 类名或方法名 | 基本功能 |
---|---|---|
1. | SelectEnumerableIterator迭代器 | 按顺序投影集合中的每个元素到一个新的集合中,投影方法作为构造方法的参数 |
2. | SelectArrayIterator迭代器 | 按顺序投影数组中的每个元素到一个新的数组中,投影方法作为构造方法的参数 |
3. | SelectListIterator迭代器 | 按顺序投影iList中的每个元素到一个新的数组中,投影方法作为构造方法的参数 |
4. | SelectIListIterator 迭代器 | 按顺序投影List中的每个元素到一个新的数组中,投影方法作为构造方法的参数 |
5. | SelectIterator 方法 | 将给定集合的每个元素投影到指定结合中,投影方法作为构造方法的参数 ,投影方法支持索引参数 |
Select的各种迭代器,从源码的角度上看,差别不大。而List在项目开发中,因为其简单易用,功能强大,使用更加广泛。因此,本文主要分析SelectListIterator迭代器的源码实现。即通过List的实例来调用Select方法。
Select是IEnumerable接口的一个扩展方法,代码如下:
public static IEnumerable<TResult> Select<TSource, TResult>(
this IEnumerable<TSource> source, Func<TSource, TResult> selector)
{
if (source == null)
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source);
}
if (selector == null)
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.selector);
}
if (source is Iterator<TSource> iterator)
{
return iterator.Select(selector);
}
if (source is IList<TSource> ilist)
{
if (source is TSource[] array)
{
return array.Length == 0 ?
Empty<TResult>() :
new SelectArrayIterator<TSource, TResult>(array, selector);
}
if (source is List<TSource> list)
{
return new SelectListIterator<TSource, TResult>(list, selector);
}
return new SelectIListIterator<TSource, TResult>(ilist, selector);
}
return new SelectEnumerableIterator<TSource, TResult>(source, selector);
}
private sealed partial class SelectListIterator<TSource, TResult> : Iterator<TResult>
{
private readonly List<TSource> _source;
private readonly Func<TSource, TResult> _selector;
private List<TSource>.Enumerator _enumerator;
public SelectListIterator(List<TSource> source, Func<TSource, TResult> selector)
{
Debug.Assert(source != null);
Debug.Assert(selector != null);
_source = source;
_selector = selector;
}
private int CountForDebugger => _source.Count;
public override Iterator<TResult> Clone() => new SelectListIterator<TSource, TResult>(_source, _selector);
public override bool MoveNext()
{
switch (_state)
{
case 1:
_enumerator = _source.GetEnumerator();
_state = 2;
goto case 2;
case 2:
if (_enumerator.MoveNext())
{
_current = _selector(_enumerator.Current);
return true;
}
Dispose();
break;
}
return false;
}
public override IEnumerable<TResult2> Select<TResult2>(Func<TResult, TResult2> selector) =>
new SelectListIterator<TSource, TResult2>(_source, CombineSelectors(_selector, selector));
}
本文将源码中的Select.cs文件抽取了出来,增加了一些日志,以方便我们更好的了解Select方法的执行流程。增加日志的源码文件详见附录。为了避免命名冲突,我们将Select方法名称改为Select2。
我们以一个学生列表的List对象执行Select2方法,将学生的名字和数学成绩筛选出来。
static void Main(string[] args)
{
Student s = new Student("x001", "Tom", "CN-1", 88);
List<Student> studentList = new List<Student>(){
new Student("x001", "Tom", "CN-1" , 90),
new Student("x002", "Jack", "CN-1", 88),
new Student("x003", "Mary", "CN-2", 87),
new Student("x004", "Frank", "CN-2", 97),
};
var iterator = studentList.Select2(s =>new {Name= s.Name, Math = s.MathResult});
}
Select方法是支持延迟加载的,所以在不真正使用投影操作的返回值的时候,它也只返回一个投影操作迭代器SelectListIterator对象,不返回具体迭代结果。
static void Main(string[] args)
{
Student s = new Student("x001", "Tom", "CN-1", 88);
List<Student> studentList = new List<Student>(){
new Student("x001", "Tom", "CN-1" , 90),
new Student("x002", "Jack", "CN-1", 88),
new Student("x003", "Mary", "CN-2", 87),
new Student("x004", "Frank", "CN-2", 97),
};
var iterator = studentList.Select2(s =>new {Name= s.Name, Math = s.MathResult});
foreach(var stu in iterator){
System.Console.WriteLine(stu);
}
}
执行结果如下:
Select方法的迭代器在和其它LINQ扩展方放在一起,可以自动触发其优化的特性,加速完成整个投影过程。
static void Main(string[] args)
{
Student s = new Student("x001", "Tom", "CN-1", 88);
List<Student> studentList = new List<Student>(){
new Student("x001", "Tom", "CN-1" , 90),
new Student("x002", "Jack", "CN-1", 88),
new Student("x003", "Mary", "CN-2", 87),
new Student("x004", "Frank", "CN-2", 97),
};
var iterator = studentList
.Select2(s => new {Id = s.Id ,Name= s.Name, Math = s.MathResult})
.Select2(s => new {Name= s.Name, Math = s.Math });
foreach(var stu in iterator){
System.Console.WriteLine(stu);
}
}
从执行结果来看,Select2方法被执行了两次, 虽然有两个SelectListIterator对象的被创建,但是MoveNext方法只执行了4次,并不是8次。
原因很明显,两个selector的投影方法被合并成了一个,所以MoveNext方法被调用4次就可以了。
具体优化流程如下:
因此List对象只被遍历了一次。
static void Main(string[] args)
{
Student s = new Student("x001", "Tom", "CN-1", 88);
List<Student> studentList = new List<Student>(){
new Student("x001", "Tom", "CN-1" , 90),
new Student("x002", "Jack", "CN-1", 88),
new Student("x003", "Mary", "CN-2", 87),
new Student("x004", "Frank", "CN-2", 97),
};
var iterator = studentList
.Where2(s=>s.MathResult >= 90)
.Select2(s => new {Name= s.Name, Math = s.MathResult});
foreach(var stu in iterator){
System.Console.WriteLine(stu.Name + " " + stu.Math);
}
}
执行结果如下:
从执行结果来看,Where2和Select2方法各自被执行了1次,但是MoveNext方法只执行了4次,并不是8次。
原因很明显,两个selector的投影方法和Where的过滤操作被合并到一起执行了,所以MoveNext方法被调用4次就可以了。
具体优化过程请参考我的博文C# Linq源码分析之Where
static void Main(string[] args)
{
Student s = new Student("x001", "Tom", "CN-1", 88);
List<Student> studentList = new List<Student>(){
new Student("x001", "Tom", "CN-1" , 90),
new Student("x002", "Jack", "CN-1", 88),
new Student("x003", "Mary", "CN-2", 87),
new Student("x004", "Frank", "CN-2", 97),
};
var iterator = studentList
.Select2(s =>new {Name= s.Name, Math = s.MathResult})
.Where2(s => s.Math >= 90 );
foreach(var stu in iterator){
System.Console.WriteLine(stu);
}
}
执行结果如下:
从执行结果来看,很遗憾,MoveNext方法执行了8次,没有获得优化。
原因如下:
Where相关的代码分析请参考我的博文C# Linq源码分析之Where
namespace Iterator.MyLinq
{
using System.Collections.Generic;
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using static Iterator.MyLinq.Utilities;
public static partial class MyEnumerable {
public static IEnumerable<TResult> Select2<TSource, TResult>(
this IEnumerable<TSource> source, Func<TSource, TResult> selector)
{
System.Console.WriteLine("Select2 function is called");
if (source == null)
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source);
}
if (selector == null)
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.selector);
}
if (source is Iterator<TSource> iterator)
{
System.Console.WriteLine("source is Iterator iterator" );
return iterator.Select(selector);
}
if (source is IList<TSource> ilist)
{
System.Console.WriteLine("source is IList ilist" );
if (source is TSource[] array)
{
return array.Length == 0 ?
null :
new SelectArrayIterator<TSource, TResult>(array, selector);
}
if (source is List<TSource> list)
{
System.Console.WriteLine("source is List list" );
return new SelectListIterator<TSource, TResult>(list, selector);
}
System.Console.WriteLine("SelectIListIterator is created");
return new SelectIListIterator<TSource, TResult>(ilist, selector);
}
/* if (source is IPartition partition)
{
IEnumerable? result = null;
CreateSelectIPartitionIterator(selector, partition, ref result);
if (result != null)
{
return result;
}
} */
System.Console.WriteLine("SelectEnumerableIterator is created");
return new SelectEnumerableIterator<TSource, TResult>(source, selector);
}
/* static partial void CreateSelectIPartitionIterator(
Func selector, IPartition partition, [NotNull] ref IEnumerable? result);
*/
public static IEnumerable<TResult> Select2<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, int, TResult> selector)
{
if (source == null)
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source);
}
if (selector == null)
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.selector);
}
return SelectIterator(source, selector);
}
private static IEnumerable<TResult> SelectIterator<TSource, TResult>(IEnumerable<TSource> source, Func<TSource, int, TResult> selector)
{
int index = -1;
foreach (TSource element in source)
{
System.Console.WriteLine("SelectIterator");
checked
{
index++;
}
yield return selector(element, index);
}
}
///
/// An iterator that maps each item of an .
///
/// The type of the source enumerable.
/// The type of the mapped items.
private sealed partial class SelectEnumerableIterator<TSource, TResult> : Iterator<TResult>
{
private readonly IEnumerable<TSource> _source;
private readonly Func<TSource, TResult> _selector;
private IEnumerator<TSource>? _enumerator;
public SelectEnumerableIterator(IEnumerable<TSource> source, Func<TSource, TResult> selector)
{
Debug.Assert(source != null);
Debug.Assert(selector != null);
_source = source;
_selector = selector;
}
public override Iterator<TResult> Clone() =>
new SelectEnumerableIterator<TSource, TResult>(_source, _selector);
public override void Dispose()
{
if (_enumerator != null)
{
_enumerator.Dispose();
_enumerator = null;
}
base.Dispose();
}
public override bool MoveNext()
{
System.Console.WriteLine("SelectEnumerableIterator move next");
switch (_state)
{
case 1:
_enumerator = _source.GetEnumerator();
_state = 2;
goto case 2;
case 2:
Debug.Assert(_enumerator != null);
if (_enumerator.MoveNext())
{
_current = _selector(_enumerator.Current);
return true;
}
Dispose();
break;
}
return false;
}
public override IEnumerable<TResult2> Select<TResult2>(Func<TResult, TResult2> selector) =>
new SelectEnumerableIterator<TSource, TResult2>(_source, CombineSelectors(_selector, selector));
}
///
/// An iterator that maps each item of a array.
///
/// The type of the source array.
/// The type of the mapped items.
[DebuggerDisplay("Count = {CountForDebugger}")]
private sealed partial class SelectArrayIterator<TSource, TResult> : Iterator<TResult>
{
private readonly TSource[] _source;
private readonly Func<TSource, TResult> _selector;
public SelectArrayIterator(TSource[] source, Func<TSource, TResult> selector)
{
Debug.Assert(source != null);
Debug.Assert(selector != null);
Debug.Assert(source.Length > 0); // Caller should check this beforehand and return a cached result
_source = source;
_selector = selector;
}
private int CountForDebugger => _source.Length;
public override Iterator<TResult> Clone() => new SelectArrayIterator<TSource, TResult>(_source, _selector);
public override bool MoveNext()
{
if (_state < 1 | _state == _source.Length + 1)
{
Dispose();
return false;
}
int index = _state++ - 1;
_current = _selector(_source[index]);
return true;
}
public override IEnumerable<TResult2> Select<TResult2>(Func<TResult, TResult2> selector) =>
new SelectArrayIterator<TSource, TResult2>(_source, CombineSelectors(_selector, selector));
}
///
/// An iterator that maps each item of a .
///
/// The type of the source list.
/// The type of the mapped items.
[DebuggerDisplay("Count = {CountForDebugger}")]
private sealed partial class SelectListIterator<TSource, TResult> : Iterator<TResult>
{
private readonly List<TSource> _source;
private readonly Func<TSource, TResult> _selector;
private List<TSource>.Enumerator _enumerator;
public SelectListIterator(List<TSource> source, Func<TSource, TResult> selector)
{
System.Console.WriteLine("SelectListIterator is created");
Debug.Assert(source != null);
Debug.Assert(selector != null);
_source = source;
_selector = selector;
}
private int CountForDebugger => _source.Count;
public override Iterator<TResult> Clone() => new SelectListIterator<TSource, TResult>(_source, _selector);
public override bool MoveNext()
{
switch (_state)
{
case 1:
_enumerator = _source.GetEnumerator();
_state = 2;
goto case 2;
case 2:
if (_enumerator.MoveNext())
{
System.Console.WriteLine("SelectListIterator move next");
_current = _selector(_enumerator.Current);
return true;
}
Dispose();
break;
}
return false;
}
public override IEnumerable<TResult2> Select<TResult2>(Func<TResult, TResult2> selector) =>
new SelectListIterator<TSource, TResult2>(_source, CombineSelectors(_selector, selector));
}
///
/// An iterator that maps each item of an .
///
/// The type of the source list.
/// The type of the mapped items.
[DebuggerDisplay("Count = {CountForDebugger}")]
private sealed partial class SelectIListIterator<TSource, TResult> : Iterator<TResult>
{
private readonly IList<TSource> _source;
private readonly Func<TSource, TResult> _selector;
private IEnumerator<TSource>? _enumerator;
public SelectIListIterator(IList<TSource> source, Func<TSource, TResult> selector)
{
Debug.Assert(source != null);
Debug.Assert(selector != null);
_source = source;
_selector = selector;
}
private int CountForDebugger => _source.Count;
public override Iterator<TResult> Clone() => new SelectIListIterator<TSource, TResult>(_source, _selector);
public override bool MoveNext()
{
switch (_state)
{
case 1:
_enumerator = _source.GetEnumerator();
_state = 2;
goto case 2;
case 2:
Debug.Assert(_enumerator != null);
if (_enumerator.MoveNext())
{
_current = _selector(_enumerator.Current);
return true;
}
Dispose();
break;
}
return false;
}
public override void Dispose()
{
if (_enumerator != null)
{
_enumerator.Dispose();
_enumerator = null;
}
base.Dispose();
}
public override IEnumerable<TResult2> Select<TResult2>(Func<TResult, TResult2> selector) =>
new SelectIListIterator<TSource, TResult2>(_source, CombineSelectors(_selector, selector));
}
}
}
namespace Iterator.MyLinq
{
using System.Collections.Generic;
using System.Diagnostics;
using System;
using static Iterator.MyLinq.Utilities;
public static partial class MyEnumerable
{
public static IEnumerable<TSource> Where2<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
System.Console.WriteLine("Where2 is called");
if (source == null)
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source);
}
if (predicate == null)
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.predicate);
}
if (source is Iterator<TSource> iterator)
{
return iterator.Where(predicate);
}
if (source is TSource[] array)
{
return array.Length == 0 ?
null :
new WhereArrayIterator<TSource>(array, predicate);
}
if (source is List<TSource> list)
{
System.Console.WriteLine("source is List list" );
return new WhereListIterator<TSource>(list, predicate);
}
return new WhereEnumerableIterator<TSource>(source, predicate);
}
public static IEnumerable<TSource> Where2<TSource>(this IEnumerable<TSource> source, Func<TSource, int, bool> predicate)
{
if (source == null)
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source);
}
if (predicate == null)
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.predicate);
}
return WhereIterator(source, predicate);
}
private static IEnumerable<TSource> WhereIterator<TSource>(IEnumerable<TSource> source, Func<TSource, int, bool> predicate)
{
int index = -1;
foreach (TSource element in source)
{
System.Console.WriteLine("WhereIterator");
checked
{
index++;
}
if (predicate(element, index))
{
yield return element;
}
}
}
///
/// An iterator that filters each item of an .
///
/// The type of the source enumerable.
private sealed partial class WhereEnumerableIterator<TSource> : Iterator<TSource>
{
private readonly IEnumerable<TSource> _source;
private readonly Func<TSource, bool> _predicate;
private IEnumerator<TSource>? _enumerator;
public WhereEnumerableIterator(IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
System.Console.WriteLine("WhereEnumerableIterator is created");
Debug.Assert(source != null);
Debug.Assert(predicate != null);
_source = source;
_predicate = predicate;
}
public override Iterator<TSource> Clone() => new WhereEnumerableIterator<TSource>(_source, _predicate);
public override void Dispose()
{
if (_enumerator != null)
{
_enumerator.Dispose();
_enumerator = null;
}
base.Dispose();
}
public override bool MoveNext()
{
switch (_state)
{
case 1:
_enumerator = _source.GetEnumerator();
_state = 2;
goto case 2;
case 2:
Debug.Assert(_enumerator != null);
while (_enumerator.MoveNext())
{
System.Console.WriteLine("WhereEnumerableIterator move next");
TSource item = _enumerator.Current;
if (_predicate(item))
{
_current = item;
return true;
}
}
Dispose();
break;
}
return false;
}
public override IEnumerable<TResult> Select<TResult>(Func<TSource, TResult> selector) =>
new WhereSelectEnumerableIterator<TSource, TResult>(_source, _predicate, selector);
public override IEnumerable<TSource> Where(Func<TSource, bool> predicate) =>
new WhereEnumerableIterator<TSource>(_source, CombinePredicates(_predicate, predicate));
}
///
/// An iterator that filters each item of an array.
///
/// The type of the source array.
internal sealed partial class WhereArrayIterator<TSource> : Iterator<TSource>
{
private readonly TSource[] _source;
private readonly Func<TSource, bool> _predicate;
public WhereArrayIterator(TSource[] source, Func<TSource, bool> predicate)
{
Debug.Assert(source != null && source.Length > 0);
Debug.Assert(predicate != null);
_source = source;
_predicate = predicate;
}
public override Iterator<TSource> Clone() =>
new WhereArrayIterator<TSource>(_source, _predicate);
public override bool MoveNext()
{
int index = _state - 1;
TSource[] source = _source;
while (unchecked((uint)index < (uint)source.Length))
{
TSource item = source[index];
index = _state++;
if (_predicate(item))
{
_current = item;
return true;
}
}
Dispose();
return false;
}
public override IEnumerable<TResult> Select<TResult>(Func<TSource, TResult> selector) =>
new WhereSelectArrayIterator<TSource, TResult>(_source, _predicate, selector);
public override IEnumerable<TSource> Where(Func<TSource, bool> predicate) =>
new WhereArrayIterator<TSource>(_source, CombinePredicates(_predicate, predicate));
}
///
/// An iterator that filters each item of a .
///
/// The type of the source list.
private sealed partial class WhereListIterator<TSource> : Iterator<TSource>
{
private readonly List<TSource> _source;
private readonly Func<TSource, bool> _predicate;
private List<TSource>.Enumerator _enumerator;
public WhereListIterator(List<TSource> source, Func<TSource, bool> predicate)
{
System.Console.WriteLine("WhereListIterator is created");
Debug.Assert(source != null);
Debug.Assert(predicate != null);
_source = source;
_predicate = predicate;
}
public override Iterator<TSource> Clone() =>
new WhereListIterator<TSource>(_source, _predicate);
public override bool MoveNext()
{
switch (_state)
{
case 1:
_enumerator = _source.GetEnumerator();
_state = 2;
goto case 2;
case 2:
while (_enumerator.MoveNext())
{
TSource item = _enumerator.Current;
if (_predicate(item))
{
_current = item;
return true;
}
}
Dispose();
break;
}
return false;
}
public override IEnumerable<TResult> Select<TResult>(Func<TSource, TResult> selector) =>
new WhereSelectListIterator<TSource, TResult>(_source, _predicate, selector);
public override IEnumerable<TSource> Where(Func<TSource, bool> predicate) =>
new WhereListIterator<TSource>(_source, CombinePredicates(_predicate, predicate));
}
///
/// An iterator that filters, then maps, each item of an array.
///
/// The type of the source array.
/// The type of the mapped items.
private sealed partial class WhereSelectArrayIterator<TSource, TResult> : Iterator<TResult>
{
private readonly TSource[] _source;
private readonly Func<TSource, bool> _predicate;
private readonly Func<TSource, TResult> _selector;
public WhereSelectArrayIterator(TSource[] source, Func<TSource, bool> predicate, Func<TSource, TResult> selector)
{
Debug.Assert(source != null && source.Length > 0);
Debug.Assert(predicate != null);
Debug.Assert(selector != null);
_source = source;
_predicate = predicate;
_selector = selector;
}
public override Iterator<TResult> Clone() =>
new WhereSelectArrayIterator<TSource, TResult>(_source, _predicate, _selector);
public override bool MoveNext()
{
int index = _state - 1;
TSource[] source = _source;
while (unchecked((uint)index < (uint)source.Length))
{
TSource item = source[index];
index = _state++;
if (_predicate(item))
{
_current = _selector(item);
return true;
}
}
Dispose();
return false;
}
public override IEnumerable<TResult2> Select<TResult2>(Func<TResult, TResult2> selector) =>
new WhereSelectArrayIterator<TSource, TResult2>(_source, _predicate, CombineSelectors(_selector, selector));
}
///
/// An iterator that filters, then maps, each item of a .
///
/// The type of the source list.
/// The type of the mapped items.
private sealed partial class WhereSelectListIterator<TSource, TResult> : Iterator<TResult>
{
private readonly List<TSource> _source;
private readonly Func<TSource, bool> _predicate;
private readonly Func<TSource, TResult> _selector;
private List<TSource>.Enumerator _enumerator;
public WhereSelectListIterator(List<TSource> source, Func<TSource, bool> predicate, Func<TSource, TResult> selector)
{
System.Console.WriteLine("WhereSelectListIterator is created");
Debug.Assert(source != null);
Debug.Assert(predicate != null);
Debug.Assert(selector != null);
_source = source;
_predicate = predicate;
_selector = selector;
}
public override Iterator<TResult> Clone() =>
new WhereSelectListIterator<TSource, TResult>(_source, _predicate, _selector);
public override bool MoveNext()
{
switch (_state)
{
case 1:
_enumerator = _source.GetEnumerator();
_state = 2;
goto case 2;
case 2:
while (_enumerator.MoveNext())
{
System.Console.WriteLine("WhereSelectListIterator move next");
TSource item = _enumerator.Current;
if (_predicate(item))
{
_current = _selector(item);
return true;
}
}
Dispose();
break;
}
return false;
}
public override IEnumerable<TResult2> Select<TResult2>(Func<TResult, TResult2> selector) =>
new WhereSelectListIterator<TSource, TResult2>(_source, _predicate, CombineSelectors(_selector, selector));
}
///
/// An iterator that filters, then maps, each item of an .
///
/// The type of the source enumerable.
/// The type of the mapped items.
private sealed partial class WhereSelectEnumerableIterator<TSource, TResult> : Iterator<TResult>
{
private readonly IEnumerable<TSource> _source;
private readonly Func<TSource, bool> _predicate;
private readonly Func<TSource, TResult> _selector;
private IEnumerator<TSource>? _enumerator;
public WhereSelectEnumerableIterator(IEnumerable<TSource> source, Func<TSource, bool> predicate, Func<TSource, TResult> selector)
{
Debug.Assert(source != null);
Debug.Assert(predicate != null);
Debug.Assert(selector != null);
_source = source;
_predicate = predicate;
_selector = selector;
}
public override Iterator<TResult> Clone() =>
new WhereSelectEnumerableIterator<TSource, TResult>(_source, _predicate, _selector);
public override void Dispose()
{
if (_enumerator != null)
{
_enumerator.Dispose();
_enumerator = null;
}
base.Dispose();
}
public override bool MoveNext()
{
switch (_state)
{
case 1:
_enumerator = _source.GetEnumerator();
_state = 2;
goto case 2;
case 2:
Debug.Assert(_enumerator != null);
while (_enumerator.MoveNext())
{
TSource item = _enumerator.Current;
if (_predicate(item))
{
_current = _selector(item);
return true;
}
}
Dispose();
break;
}
return false;
}
public override IEnumerable<TResult2> Select<TResult2>(Func<TResult, TResult2> selector) =>
new WhereSelectEnumerableIterator<TSource, TResult2>(_source, _predicate, CombineSelectors(_selector, selector));
}
}
}
using System;
using System.Collections;
using System.Collections.Generic;
namespace Iterator
{
public class Student {
public string Id { get; set; }
public string Name { get; set; }
public string Classroom { get; set; }
public int MathResult { get; set; }
public Student(string id, string name, string classroom, int math)
{
this.Id = id;
this.Name = name;
this.Classroom = classroom;
this.MathResult = math;
}
}
}