C# LINQ源码分析之Select

概要

在开发过程中,LINQ代码库中的Select方法经常被使用,为了更好的了解该方法,我们从源码的角度对其进行分析。了解如何以最优的方式,使用该方法,从而提升代码的性能。

Select方法介绍

Select方法的基本功能是将序列中的每个元素投影为新形式。LINQ提供了两个重载方法

方法名称 基本介绍
Select(IEnumerable, Func) 将序列中的每个元素投影为新形式。
Select(IEnumerable, Func) 通过合并元素的索引,将序列中的每个元素投影为新形式。

两个方法的主要区别是第二个方法支持序列的索引参数。

Select方法关键代码结构

与其他LINQ方法类似,Select方法是实现基础也是迭代器。基于不同的数据结构,定义了不同的迭代器。这些迭代器都继承了基类迭代器Iterator,从而获得了多线程支持和嵌套循环的支持。如果要了解更过的迭代器基础内容,请参考我的博文 C# LINQ源码分析之迭代器

编号 类名或方法名 基本功能
1. SelectEnumerableIterator迭代器 按顺序投影集合中的每个元素到一个新的集合中,投影方法作为构造方法的参数
2. SelectArrayIterator迭代器 按顺序投影数组中的每个元素到一个新的数组中,投影方法作为构造方法的参数
3. SelectListIterator迭代器 按顺序投影iList中的每个元素到一个新的数组中,投影方法作为构造方法的参数
4. SelectIListIterator 迭代器 按顺序投影List中的每个元素到一个新的数组中,投影方法作为构造方法的参数
5. SelectIterator 方法 将给定集合的每个元素投影到指定结合中,投影方法作为构造方法的参数 ,投影方法支持索引参数

Select关键源码分析

Select的各种迭代器,从源码的角度上看,差别不大。而List在项目开发中,因为其简单易用,功能强大,使用更加广泛。因此,本文主要分析SelectListIterator迭代器的源码实现。即通过List的实例来调用Select方法。

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);
}
  1. 该方法有两个参数,第一个是集合的扩展方法参数,TSource是集合内元素的类型,第二个参数是一个委托类型,它封装了一个投影方法,TResult是集合元素投影后的数据类型。
  2. 如果调用Select方法的数据源为空,抛出异常。
  3. 如果Select方法的第二个参数,投影方法为空,抛出异常。
  4. 如果调用Select方法的对象是一个Iterator的实例,例如出现xx.Select().Select()或xx.Where().Select()的情况,对于第二个Select方法,则调用迭代器自身的Select方法,此处代码是Select优化的基础,这样做可以将Where/Select或Select/Select的迭代循环合并,以优化迭代过程。
  5. 如果调用Select方法的对象是一个IList
    (1)如果source的类型是一个数组,并且是空数组,则返回一个空数组
    (2)如果source的类型是一个数组,并且不是空数组,则返回数组的Select迭代器SelectArrayIterator实例
    (3)如果source的类型是一个List,则返回SelectListIterator实例
    (4)返回SelectIListIterator实例
  6. 返回集合元素的投影迭代的迭代器实例 SelectEnumerableIterator,作为默认情况。

SelectListIterator源码分析

  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));
        }
  1. SelectListIterator类继承自Iterator类,从而获得多线程安全的支持和多重循环嵌套访问的支持。
  2. 该类包含私有成员_source,用于存储要迭代的List对象,在构造函数中初始化。
  3. 该类包含封装投影方法的系统委托_selector,在构造函数中初始化。
  4. 该类的克隆方法返回SelectListIterator对象,在多线程访问同一个SelectListIterator对象时候被调用。
  5. 该类覆写了基类的MoveNext方法,以支持List类型数据的投影操作。
    (1)其实状态_state为0,在通过foreach或其他方式调用基类中定义的GetEnumertator方法后,被修改为1。
    (2)case 1:下,实例化List对象内部迭代List数据的迭代器,将_state改为2,进入case 2。
    (3)case 2:下,调用List对象的MoveNext方法,获取List的元素,执行调用Select方法,完成投影操作。将基类对属性_current赋值为投影操作的返回值。如果以及是最后一个元素,调用Dispose方法,释放当前Select迭代器。
  6. 该类覆写了基类的Select方法,用于优化xx.Select().Select()情况,该方法调用CombineSelectors方法,将两个投影操作合并为一个投影操作。CombineSelectors源码见附录。

Select的基本执行流程

本文将源码中的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});
 }

执行结果如下:
在这里插入图片描述

  1. Select2方法被调用,当前集合是一个List
    (1) List继承自iList,所以首先被判断为是一个iList
    (2) 最后成功推断出source是一个List
  2. 实例化一个SelectListIterator对象,先调用基类的构造方法,再调用派生类的构造方法。

Select方法是支持延迟加载的,所以在不真正使用投影操作的返回值的时候,它也只返回一个投影操作迭代器SelectListIterator对象,不返回具体迭代结果。

foreach循环遍历迭代器

 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);
     }
  }

执行结果如下:

C# LINQ源码分析之Select_第1张图片

  1. Select2方法被调用,当前集合是一个List
    (1) List继承自iList,所以首先被判断为是一个iList
    (2) 最后成功推断出source是一个List
  2. 实例化一个SelectListIterator对象,先调用基类的构造方法,再调用派生类的构造方法。
  3. foreach调用SelectListIterator实例的GetEnumerator方法,判断是否当前迭代器是否可用,包含是否被其他线程使用,是否被其他代码调用。如果可用,给当前迭代器加锁,将_state改为1,否则调用SelectListIterator对象的Clone方法,返回一个新的迭代器对象。
  4. foreach调用SelectListIterator对象的MoveNext方法。开始为每个元素执行投影操作。

Select的优化处理

Select方法的迭代器在和其它LINQ扩展方放在一起,可以自动触发其优化的特性,加速完成整个投影过程。

Select.Select 情况

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);
      }
}

执行结果如下:
C# LINQ源码分析之Select_第2张图片

从执行结果来看,Select2方法被执行了两次, 虽然有两个SelectListIterator对象的被创建,但是MoveNext方法只执行了4次,并不是8次。

原因很明显,两个selector的投影方法被合并成了一个,所以MoveNext方法被调用4次就可以了。

具体优化流程如下:

  1. 第一个Select2方法被调用,创建SelectListIterator对象。该对象内包含要执行投影操作的List对象和投影方法。Select2返回SelectListIterator对象。
  2. 第二个Select2方法被调用,此时souce不再是List对象而是一个terator的派生类SelectListIterator的对象,所以 if (source is Iterator iterator)判断成立,直接返回SelectListIterator对象。
  3. 第二个Select直接调用SelectListIterator对象自身的Select方法作为返回结果,而SelectListIterator的Select方法是包含两个投影器的合并操作的,所以最后是将两个投影器方法合并后,再进行迭代的。

因此List对象只被遍历了一次。

Where.Select 情况

  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);
            } 
       }

执行结果如下:
C# LINQ源码分析之Select_第3张图片
从执行结果来看,Where2和Select2方法各自被执行了1次,但是MoveNext方法只执行了4次,并不是8次。

原因很明显,两个selector的投影方法和Where的过滤操作被合并到一起执行了,所以MoveNext方法被调用4次就可以了。

具体优化过程请参考我的博文C# Linq源码分析之Where

Select.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);
       } 
     }

执行结果如下:
C# LINQ源码分析之Select_第4张图片
从执行结果来看,很遗憾,MoveNext方法执行了8次,没有获得优化。

原因如下:

  1. 在Select2方法执行完成后,返回了SelectListIterator对象
  2. 在进入Where2方法后 if (source is Iterator iterator)返回为真,执行iterator.Where(predicate); 此时的iterator是SelectListIterator对象,SelectListIterator类不包含Where方法,其基类Iterator才包含Where方法,因此调用的是基类的Where方法,返回的是WhereEnumerableIterator对象,该对象的MoveNext方法被直接调用。WhereEnumerableIterator优化方法并没有被触发。

Where相关的代码分析请参考我的博文C# Linq源码分析之Where

附录

增加日志的Select代码

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));
        }
    }
}

增加日志的Where代码

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));
        }
    }
}

Student类

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;     
        }
              
    }
}

你可能感兴趣的:(.Net,.Net,Core,C#基础,linq,c#,microsoft)