zoukankan      html  css  js  c++  java
  • LINQ to Objects延时执行的Enumerable类方法

      LINQ标准查询运算法是依靠一组扩展方法来实现的。而这些扩展方法分别在System.Linq.Enumerable和System.Linq.Queryable这连个静态类中定义。

      Enumerable的扩展方法采用线性流程,每个运算法会被线性执行。这种执行方法如果操作类似关系型数据库数据源,效率会非常低下,所以Queryable重新定义这些扩展方法,把LINQ表达式拆解为表达式树,提供程序就可以根据表达式树生成关系型数据库的查询语句,即SQL命令,然后进行相关操作。

      每个查询运算符的执行行为不同,大致分为立即执行和延时执行。延时执行的运算符将在枚举元素的时候被执行。

      Enumerable类位于程序集System.Core.dll中,System.Linq命名空间下,并且直接集成自System.Object,存在于3.5及以上的.NET框架中。Enumerable是静态类,不能实例化和被继承,其成员只有一组静态和扩展方法。

      LINQ不仅能够查询实现IEnumerable<T>或IQueryable<T>的类型,也能查询实现IEnumerable接口的类型。关于Enumerable方法的详细说明,请参考MSDN  Enumerable 类

     “--------------------------------------------------------------

      理解LINQ首先必须理解扩展方法

      msdn是这样规定扩展方法的:“扩展方法被定义为静态方法,但它们是通过实例方法语法进行调用的。 它们的第一个参数指定该方法作用于哪个类型,并且该参数以 this 修饰符为前缀

    下面给个扩展方法的例子如下:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace 扩展方法
    {
        /// <summary>
        /// 为string类型定义一个扩展方法
        /// </summary>
        static class Helper
        { 
            public static string MyExtenMethod(this string s)
            {
                return s.Substring(0, 2);
            }
        }
        class Program
        {
            static void Main(string[] args)
            {
                string s = "扩展方法示例";
                Console.WriteLine(s.MyExtenMethod());//调用
                Console.ReadKey(false);
            }
        }
    }

    程序的运行结果如下:

     -----插曲,想到了就加进来,有助于理解开头的几段话及LINQ原理

    参考DebugLZQ前面的博文:浅析EF涉及的一些C#语言特性

     ---------------------------------------------------------------”

     为了方便理解和记忆,DebugLZQ将常用的延时执行的Enumerable类方法成员分了下组,具体如下:

    1.Take用于从一个序列的开头返回指定数量的元素

    2.TakeWhile 用于获取指定序列从头开始符合条件的元素,直到遇到不符合条件的元素为止

    3.Skip跳过序列中指定数量的元素

    4.SkipWhile 用于跳过序列总满足条件的元素,然会返回剩下的元素

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace 延时执行的Enumerable类方法
    {
        /// <summary>
        /// 延时执行的Enumerable类方法
        /// DebugLZQ
        /// http://www.cnblogs.com/DebugLZQ
        /// </summary>
        class Program
        {
            static void Main(string[] args)
            {
                string[] names = { "DebugLZQ","DebugMan","Sarah","Jerry","Tom","Linda","M&M","Jeffery"};
                //1.Take用于从一个序列的开头返回指定数量的元素
                //
                //a.在数组上直接使用Take方法
                foreach (string name in names.Take(3))
                {
                    Console.Write("{0}    ", name); 
                }
                Console.WriteLine();
                Console.WriteLine("-----");
                //b.在LINQ返回的IEnumerable<T>序列上使用Take方法
                var query = from string name in names
                            where name.Length <=3
                            select name;
                foreach (string  name in query.Take(1))
                {
                    Console.Write("{0}    ",name);
                }
                Console.WriteLine();
                Console.WriteLine("----------------------------");
                Console.ReadKey(false);
                //2.TakeWhile 用于获取指定序列从头开始符合条件的元素,直到遇到不符合条件的元素为止
                //
                var takenames = names.TakeWhile(n => n.Length>4);
                var takenames2 = names.TakeWhile((n,i)=>n.Length<10&&i<3);
                foreach (string name in takenames)
                {
                    Console.Write("{0}    ", name);
                }
                Console.WriteLine();
                Console.WriteLine("-----");
                foreach (string name in takenames2)
                {
                    Console.Write("{0}    ", name);
                }
                Console.WriteLine();
                Console.WriteLine("----------------------------");
                Console.ReadKey(false);
                //3.Skip跳过序列中指定数量的元素
                //
                foreach (string name in names.Skip(5))
                {
                    Console.Write("{0}    ", name);
                }
                Console.WriteLine();
                Console.WriteLine("-----");
                var query_skip = (from name in names
                                  where name.Length >= 3
                                  select name).Skip(2);
                foreach (string name in query_skip.Skip(2) )
                {
                    Console.Write("{0}    ", name);
                }
                Console.WriteLine();
                Console.WriteLine("----------------------------");
                Console.ReadKey(false);
                //4.SkipWhile 用于跳过序列总满足条件的元素,然会返回剩下的元素
                //跳过名字长度大于3的
                var takenames_SkipWhile = names.SkipWhile(n => n.Length >3);
                foreach (string name in takenames_SkipWhile)
                {
                    Console.Write("{0}    ", name);
                }
                Console.WriteLine();
                Console.WriteLine("-----");
                var takenames_SkipWhile2 = names.SkipWhile((n,i)=>n.Length>3&&i>2);
                foreach (string name in takenames_SkipWhile2)
                {
                    Console.Write("{0}    ", name);
                }
                Console.WriteLine();
                Console.WriteLine("----------------------------");
                Console.ReadKey(false);
    
                //小结Take、Skip获得第N到第M个元素
                var names_TakeAndSkip = names.Skip(5).Take(3);
    
                var names_TakeAndSkip2 = (from name in names
                                          select name).Skip(5).Take(3);
    
                foreach (string name in names_TakeAndSkip)
                {
                    Console.Write("{0}    ", name);
                }
                Console.WriteLine();
                Console.WriteLine("-----");
                foreach (string name in names_TakeAndSkip2)
                {
                    Console.Write("{0}    ", name);
                }
                Console.WriteLine();
                Console.WriteLine("----------------------------");
                Console.ReadKey(false);
    
            }
        }
    }

    程序中有详细的注释不再多做说明,程序运行结果如下:

    5.Reverse用于翻转序列中的元素的顺序

    6.Distinct过滤掉重复的元素

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace Reverse_Distinct等
    {
        /// <summary>
        /// DebugLZQ
        /// http://www.cnblogs.com/DebugLZQ
        /// </summary>
        class Program
        {
            static void Main(string[] args)
            {
                string[] names = { "DebugLZQ", "Jerry", "Sarah", "Jerry", "Tom", "Linda", "M&M", "Jeffery" };
                //5.Reverse用于翻转序列中的元素的顺序
               string str = "反转字符串";
    
               var strre = str.ToCharArray().Reverse();
               var takenames = names.Reverse();
    
               foreach (var c in strre)
               {
                   Console.Write(c);
               }
               Console.WriteLine();
               Console.WriteLine("-----");
               foreach (var c in takenames )
               {
                   Console.WriteLine(c);
               }
               Console.WriteLine("----------------------------");
               Console.ReadKey(false);
    
                //6.Distinct  过滤掉重复的元素
               var takenames_Distinct = names.Distinct();
    
               foreach (var c in takenames_Distinct)
               {
                   Console.WriteLine(c);
               }
               Console.WriteLine("----------------------------");
               Console.ReadKey(false);
            }
        }
    }

    程序的运行结果如下:

    7.Union用于合并两个序列,并去掉重复项

    8.Concat用于连接两个序列,不会去掉重复项

    9.Intersect用于获得连个序列的交集

    10.Except用于获得两个结合的差集

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace Union_Concat_Intersect_Except
    {
        /// <summary>
        /// DebugLZQ
        /// http://www.cnblogs.com/DebugLZQ
        /// </summary>
        class Program
        {
            static void Main(string[] args)
            {
                string[] names1 = { "DebugLZQ", "Jerry", "Sarah", "Jerry", "Tom", "Linda", "M&M", "Jeffery" };
                string[] names2 = { "DebugLZQ", "Jerry", "Sarah" };
    
                //7.Union用于合并两个序列,并去掉重复项
                var names_Union = names1.Union(names2);
    
                //8.Concat用于连接两个序列,不会去掉重复项
                var names_Concat = names1.Concat(names2);
    
                //9.Intersect用于获得连个序列的交集
                var names_Intersect = names1.Intersect(names2);
    
                //10.Except用于获得两个结合的差集
                var names_Except = names1.Except(names2);
    
                foreach (string name in names_Union)
                {
                    Console.WriteLine(name);
                }
                Console.WriteLine("-----");
                Console.ReadKey(false);
                foreach (string name in names_Concat)
                {
                    Console.WriteLine(name);
                }
                Console.WriteLine("-----");
                Console.ReadKey(false);
                foreach (string name in names_Intersect)
                {
                    Console.WriteLine(name);
                }
                Console.WriteLine("-----");
                Console.ReadKey(false);
                foreach (string name in names_Except)
                {
                    Console.WriteLine(name);
                }
                Console.WriteLine("-----");
                Console.ReadKey(false);
            }
        }
    }

    程序的运行结果如下:

    11.Range 用于生成指定范围内的“整数”序列

    12.Repeat用于生成指定数量的重复元素

    13.Empty 用于获得一个指定类型的空序列

    14.DefaultIfEmpty 用于获得序列,如果为空,则添加一个默认类型元素

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace Range_Empty_DefalultIfEmpty
    {
        /// <summary>
        /// DebugLZQ
        /// http://www.cnblogs.com/DebugLZQ
        /// </summary>
        class Program
        {
            static void Main(string[] args)
            {
                //11.Range 用于生成指定范围内的“整数”序列
                var num2 = Enumerable.Range(10, 15);
    
                //12.Repeat用于生成指定数量的重复元素
                var guest = new {Name="橙子",Age=25 };
                var Guests = Enumerable.Repeat(guest, 5);
    
                //13.Empty 用于获得一个指定类型的空序列
                var empty = Enumerable.Empty<string>();
    
                //14.DefaultIfEmpty 用于获得序列,如果为空,则添加一个默认类型元素
                //a
                var intempty = Enumerable.Empty<int>();
                Console.WriteLine(intempty.Count());
                Console.WriteLine("-----------");
                foreach (var n in intempty)
                {
                    Console.WriteLine(n);            
                }
                Console.WriteLine("-----------");
                Console.WriteLine(intempty.DefaultIfEmpty().Count());
                Console.WriteLine("-----------");
                foreach (var n in intempty.DefaultIfEmpty())
                {
                    Console.WriteLine(n);
                }
                Console.WriteLine("--------------------------");
                Console.ReadKey(false);
                //b
                string[] names = { "DebugLZQ", "DebugMan", "Sarah", "Jerry", "Tom", "Linda", "M&M", "Jeffery" };
                var query = from name in names
                            where name == "LBJ"
                            select name;
                Console.WriteLine(query.Count());
                Console.WriteLine(query.DefaultIfEmpty().Count());//默认为null
                foreach (var n in query.DefaultIfEmpty())
                {
                    Console.WriteLine(n);
                }
                Console.WriteLine("---------------");
                Console.ReadKey(false);
                //c指定一个默认值
                foreach (var n in intempty.DefaultIfEmpty(100))
                {
                    Console.WriteLine(n);
                }
                Console.WriteLine("--------------------------");
                Console.ReadKey(false);
    
                foreach (var n in query.DefaultIfEmpty("James"))
                {
                    Console.WriteLine(n);
                }
                Console.ReadKey(false);
            }
        }
    }

    程序的运行结果如下:

    15.OfType筛选指定类型的元素

    16.Cast类型转换

    17.AsEnumerable有些数据源类型不支持Enumerable的部分查询关键字,需要转换下,譬如IQueryable

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Collections;
    
    namespace Cast_OfType_AsEnumerable
    {
        /// <summary>
        /// DebugLZQ
        /// http://www.cnblogs.com/DebugLZQ
        /// </summary>
        class Program
        {
            static void Main(string[] args)
            {
                ArrayList names = new ArrayList();
                names.Add("DebugLZQ");
                names.Add("Jerry");
                names.Add(100);
                names.Add(new {Name="LZQ",Age=26});
                names.Add(new Stack());
                //15.OfType筛选指定类型的元素
                var takenames = names.OfType<string>();
    
                //16.Cast类型转换
                var takenames2 = names.OfType<string>().Cast<string>();
    
                //17.AsEnumerable
                var takenames3 = takenames2.AsEnumerable();
    
                foreach (var name in takenames3)
                {
                    Console.Write("{0}  ",name);
                }
                Console.ReadKey(false);
    
            }
        }
    }

    程序运行结果如下:

     延时执行,顾名思义就是不是立即执行,即不是在查询语句定义的时候执行,而是在处理结果集(如遍历)的时候执行,在Enumerable类方法成员中,除了本节总结的这常用的17个外,前面博文---LINQ基本子句 中总结的8个基本子句也都是延时执行的。注意延时执行的查询程序的执行流程。

     

  • 相关阅读:
    秋色园QBlog技术原理解析:系列终结篇:最后的AOP策略(十九)
    半解TextBox灵异事件背后神秘的深度灵异事件
    SQLite julianday DateTime日期时区问题小记录
    Winform 多组合老板键Alt_Ctrl_Shift
    性能杀手之异常霸气外露!找死!
    DataReader不奇怪,该出手时就出手!
    DBImport v3.0 中文版发布:支持各大数据库数据互导(IT人员必备工具)
    文本数据库.Net界未来的一朵奇葩
    TextBox灵异事件之背后神秘的深度灵异事件真相揭秘
    秋色园QBlog技术原理解析:性能优化篇:读写分离与文本数据库(十八)
  • 原文地址:https://www.cnblogs.com/DebugLZQ/p/2759543.html
Copyright © 2011-2022 走看看