zoukankan      html  css  js  c++  java
  • [.NET] : LINQ Deferred Execution

    前言 :

    看到91跟小朱都分享了,延迟执行的文章。
    - 91 : [.NET]延迟执行(Deferred Execution) 简单概念实作
    - 小朱 :[.NET] LINQ 的延迟执行 (Deferred Execution)
    唤醒了许久之前的记忆,记得也有对LINQ的运作下了一番功夫。
    趁记忆还没有消失。简单的做个记录,也希望对有需要的开发人员有帮助。

    说明 :

    简单的说,在 Linq的延迟执行运作,主要有三个要点。
    1. IEnumerable跟 foreach是 LINQ运作的核心。
    2. IEnumerable套用 Decorator模式,对IEnumerable加入功能。
    3. 使用 IEnumerable的扩充方法生成套用 Decorator的 IEnumerable,方便串接程序。

    1. IEnumerable跟 foreach是 LINQ运作的核心。

    在LINQ里是以IEnumerable做为运作的目标跟结果,并且以foreach来做结果列举的动作。
    了解IEnumerable跟foreach之间的运作流程,是理解LINQ运作很重要的一步。

    下面这段Code展示了拆解 Foreach机制后的程序代码,用来说明使用foreach列举IEnumerable时的程序流程。
    (更细节的数据,可以参考 Design Patterns里 Iterator模式。)

    原始码 :

    public static void Test001()
    {
        // 建立字符串数组,并且转型为IEnumerable
        string[] stringArray = new string[] { "A", "B", "C" };
        IEnumerable<string> stringEnumerable = stringArray;
    
        // 列举 IEnumerable使用 Foreach
        foreach (string item in stringEnumerable)
        {
            Console.WriteLine(item);
        }
    
        // 拆解 Foreach得到的程序
        IEnumerator<string> stringEnumerator = stringEnumerable.GetEnumerator();
        while (stringEnumerator.MoveNext() == true)
        {
            string item = stringEnumerator.Current;
            Console.WriteLine(item);
        }
    }
    

    2. IEnumerable套用 Decorator模式,对IEnumerable加入功能。

    Decorator模式的主要功能是 :「将额外权责动态附加于对象身上,不必延生子类别及可弹性扩增功能。」
    将 Decorator模式套用到 IEnumerable之后,
    可以将功能附加到 IEnumerable接口,却又不改变使用foreach列举的用法。

    下面这段Code实做一个过滤字符串用的Decorator,用来说明如何将 Decorator模式套用到 IEnumerable
    (更细节的数据,可以参考 Design Patterns里 Decorator模式。)

    原始码 :

    public class StringFilterEnumerable : IEnumerable<string>
    {
        // Fields
        private readonly IEnumerable<string> _sourceEnumerable;
    
        private readonly string _filterArgument = null;
    
    
        // Constructor
        public StringFilterEnumerable(IEnumerable<string> sourceEnumerable, string filterArgument)
        {
            #region Require
    
            if (sourceEnumerable == null) throw new ArgumentNullException();
            if (string.IsNullOrEmpty(filterArgument) == true) throw new ArgumentNullException();
    
            #endregion
            _sourceEnumerable = sourceEnumerable;
            _filterArgument = filterArgument;
        }
    
    
        // Methods
        public IEnumerator<string> GetEnumerator()
        {
            return new StringFilterEnumerator(_sourceEnumerable.GetEnumerator(), _filterArgument);
        }
    
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }
    }
    
    public class StringFilterEnumerator : IEnumerator<string>
    {
        // Fields
        private readonly IEnumerator<string> _sourceEnumerator;
    
        private readonly string _filterArgument = null;
    
        private string _currentResult = null;
    
    
        // Constructor
        public StringFilterEnumerator(IEnumerator<string> sourceEnumerator, string filterArgument)
        {
            #region Require
    
            if (sourceEnumerator == null) throw new ArgumentNullException();
            if (string.IsNullOrEmpty(filterArgument) == true) throw new ArgumentNullException();
    
            #endregion
            _sourceEnumerator = sourceEnumerator;
            _filterArgument = filterArgument;
        }
    
        public virtual void Dispose()
        {
            _sourceEnumerator.Dispose();
            _currentResult = null;
        }
    
    
        // Methods 
        public string Current
        {
            get
            {
                return _currentResult;
            }
        }
    
        object System.Collections.IEnumerator.Current
        {
            get
            {
                return this.Current;
            }
        }
    
        public bool MoveNext()
        {
            while (_sourceEnumerator.MoveNext() == true)
            {
                if (_sourceEnumerator.Current != _filterArgument)
                {
                    _currentResult = _sourceEnumerator.Current;
                    return true;
                }
            }
            return false;
        }
    
        public void Reset()
        {
            _sourceEnumerator.Reset();
            _currentResult = null;
        }
    }
    

    使用范例1 :

    public static void Test002()
    {
        // 建立字符串数组,并且转型为IEnumerable
        string[] stringArray = new string[] { "A", "B", "C" };
        IEnumerable<string> stringEnumerable = stringArray;
    
        // 生成并且套用StringFilterEnumerable对象,过滤字符串"B"
        stringEnumerable = new StringFilterEnumerable(stringEnumerable, "B");
    
        // 列举 IEnumerable使用 Foreach
        foreach (string item in stringEnumerable)
        {
            Console.WriteLine(item);
        }
    }
    

    使用范例2 :

    public static void Test002_1()
    {
        // 建立字符串数组,并且转型为IEnumerable
        string[] stringArray = new string[] { "A", "B", "C" };
        IEnumerable<string> stringEnumerable = stringArray;
    
        // 生成并且套用StringFilterEnumerable对象,过滤字符串"B"+"A"
        stringEnumerable = new StringFilterEnumerable(new StringFilterEnumerable(stringEnumerable, "B"), "A");
    
        // 列举 IEnumerable使用 Foreach
        foreach (string item in stringEnumerable)
        {
            Console.WriteLine(item);
        }
    }
    

    3. 使用 IEnumerable的扩充方法生成套用 Decorator的 IEnumerable,方便串接程序。

    这段就比较好理解,只是将上一个要点建立的使用扩充方法来做对象生成动作。
    主要要达成的目的就是将一些程序做隐藏的动作,在使用的时候可以比较方便。
    (更细节的数据,可以参考:[扩充方法 (C# 程序设计手册)])

    原始码 :

    public static class StringEnumerableExtensions
    {
        public static IEnumerable<string> Filter(this IEnumerable<string> sourceEnumerable, string filterArgument)
        {
            #region Require
    
            if (sourceEnumerable == null) throw new ArgumentNullException();
            if (string.IsNullOrEmpty(filterArgument) == true) throw new ArgumentNullException();
    
            #endregion
            return new StringFilterEnumerable(sourceEnumerable, filterArgument);
        }
    }   
    

    使用范例1 :

    public static void Test003()
    {
        // 建立字符串数组,并且转型为IEnumerable
        string[] stringArray = new string[] { "A", "B", "C" };
        IEnumerable<string> stringEnumerable = stringArray;
    
        // 使用扩充方法套用StringFilterEnumerable对象,过滤字符串"B"
        stringEnumerable = stringEnumerable.Filter("B");
    
        // 列举 IEnumerable使用 Foreach
        foreach (string item in stringEnumerable)
        {
            Console.WriteLine(item);
        }
    }
    

    使用范例2 :

    public static void Test003_1()
    {
        // 建立字符串数组,并且转型为IEnumerable
        string[] stringArray = new string[] { "A", "B", "C" };
        IEnumerable<string> stringEnumerable = stringArray;
    
        // 使用扩充方法套用StringFilterEnumerable对象,过滤字符串"B"+"A"
        stringEnumerable = stringEnumerable.Filter("B").Filter("A");
    
        // 列举 IEnumerable使用 Foreach
        foreach (string item in stringEnumerable)
        {
            Console.WriteLine(item);
        }
    }
    

    后记 :

    依照前面章节的说明,细细去分析程序。
    不难看出 LINQ的执行的时间点,不是在呼叫扩充方法的当下。
    而是在使用foreach列举IEnumerable时,才去执行。
    这也就是 LINQ的延迟执行(Deferred Execution)。

  • 相关阅读:
    面试题(三)
    面试题(二)
    经典面试题(一)
    $.ajax()实现简单计算器
    [hdu5373 The shortest problem]模拟
    [hdu5371 Hotaru's problem]最大回文半径
    [hdu5372 Segment Game]树状数组
    [zoj3813]Alternating Sum 公式化简,线段树
    [hdu5348]图上找环,删环
    [hdu5360]贪心
  • 原文地址:https://www.cnblogs.com/clark159/p/2320931.html
Copyright © 2011-2022 走看看