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個基本子句也都是延時執行的。注意延時執行的查詢程序的執行流程。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM