LINQ中延時(shí)執(zhí)行的Enumerable類方法成員
Enumerable的擴(kuò)展方法采用線性流程,每個(gè)運(yùn)算法會(huì)被線性執(zhí)行。這種執(zhí)行方法如果操作類似關(guān)系型數(shù)據(jù)庫(kù)數(shù)據(jù)源,效率會(huì)非常低下,所以Queryable重新定義這些擴(kuò)展方法,把LINQ表達(dá)式拆解為表達(dá)式樹,提供程序就可以根據(jù)表達(dá)式樹生成關(guān)系型數(shù)據(jù)庫(kù)的查詢語(yǔ)句,即SQL命令,然后進(jìn)行相關(guān)操作。
每個(gè)查詢運(yùn)算符的執(zhí)行行為不同,大致分為立即執(zhí)行和延時(shí)執(zhí)行。延時(shí)執(zhí)行的運(yùn)算符將在枚舉元素的時(shí)候被執(zhí)行。
Enumerable類位于程序集System.Core.dll中,System.Linq命名空間下,并且直接集成自System.Object,存在于3.5及以上的.NET框架中。Enumerable是靜態(tài)類,不能實(shí)例化和被繼承,其成員只有一組靜態(tài)和擴(kuò)展方法。
LINQ不僅能夠查詢實(shí)現(xiàn)IEnumerable<T>或IQueryable<T>的類型,也能查詢實(shí)現(xiàn)IEnumerable接口的類型。關(guān)于Enumerable方法的詳細(xì)說(shuō)明,請(qǐng)參考MSDN Enumerable 類
理解LINQ首先必須理解擴(kuò)展方法
msdn是這樣規(guī)定擴(kuò)展方法的:“擴(kuò)展方法被定義為靜態(tài)方法,但它們是通過(guò)實(shí)例方法語(yǔ)法進(jìn)行調(diào)用的。 它們的***個(gè)參數(shù)指定該方法作用于哪個(gè)類型,并且該參數(shù)以 this 修飾符為前綴。”
下面給個(gè)擴(kuò)展方法的例子如下:
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- namespace 擴(kuò)展方法
- {
- /// <summary>
- /// 為string類型定義一個(gè)擴(kuò)展方法
- /// </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 = "擴(kuò)展方法示例";
- Console.WriteLine(s.MyExtenMethod());//調(diào)用
- Console.ReadKey(false);
- }
- }
- }
程序的運(yùn)行結(jié)果如下:
-----插曲,想到了就加進(jìn)來(lái),有助于理解開頭的幾段話及LINQ原理
---------------------------------------------------------------”
為了方便理解和記憶,DebugLZQ將常用的延時(shí)執(zhí)行的Enumerable類方法成員分了下組,具體如下:
1.Take用于從一個(gè)序列的開頭返回指定數(shù)量的元素
2.TakeWhile 用于獲取指定序列從頭開始符合條件的元素,直到遇到不符合條件的元素為止
3.Skip跳過(guò)序列中指定數(shù)量的元素
4.SkipWhile 用于跳過(guò)序列總滿足條件的元素,然會(huì)返回剩下的元素
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- namespace 延時(shí)執(zhí)行的Enumerable類方法
- {
- /// <summary>
- /// 延時(shí)執(zhí)行的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用于從一個(gè)序列的開頭返回指定數(shù)量的元素
- //
- //a.在數(shù)組上直接使用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跳過(guò)序列中指定數(shù)量的元素
- //
- 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 用于跳過(guò)序列總滿足條件的元素,然會(huì)返回剩下的元素
- //跳過(guò)名字長(zhǎng)度大于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);
- //小結(jié)Take、Skip獲得第N到第M個(gè)元素
- 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);
- }
- }
- }
程序中有詳細(xì)的注釋不再多做說(shuō)明,程序運(yùn)行結(jié)果如下:
5.Reverse用于翻轉(zhuǎn)序列中的元素的順序
6.Distinct過(guò)濾掉重復(fù)的元素
- 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用于翻轉(zhuǎn)序列中的元素的順序
- string str = "反轉(zhuǎn)字符串";
- 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 過(guò)濾掉重復(fù)的元素
- var takenames_Distinct = names.Distinct();
- foreach (var c in takenames_Distinct)
- {
- Console.WriteLine(c);
- }
- Console.WriteLine("----------------------------");
- Console.ReadKey(false);
- }
- }
- }
程序的運(yùn)行結(jié)果如下:
7.Union用于合并兩個(gè)序列,并去掉重復(fù)項(xiàng)
8.Concat用于連接兩個(gè)序列,不會(huì)去掉重復(fù)項(xiàng)
9.Intersect用于獲得連個(gè)序列的交集
10.Except用于獲得兩個(gè)結(jié)合的差集
- 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用于合并兩個(gè)序列,并去掉重復(fù)項(xiàng)
- var names_Union = names1.Union(names2);
- //8.Concat用于連接兩個(gè)序列,不會(huì)去掉重復(fù)項(xiàng)
- var names_Concat = names1.Concat(names2);
- //9.Intersect用于獲得連個(gè)序列的交集
- var names_Intersect = names1.Intersect(names2);
- //10.Except用于獲得兩個(gè)結(jié)合的差集
- 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);
- }
- }
- }
程序的運(yùn)行結(jié)果如下:
11.Range 用于生成指定范圍內(nèi)的“整數(shù)”序列
12.Repeat用于生成指定數(shù)量的重復(fù)元素
13.Empty 用于獲得一個(gè)指定類型的空序列
14.DefaultIfEmpty 用于獲得序列,如果為空,則添加一個(gè)默認(rèn)類型元素
- 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 用于生成指定范圍內(nèi)的“整數(shù)”序列
- var num2 = Enumerable.Range(10, 15);
- //12.Repeat用于生成指定數(shù)量的重復(fù)元素
- var guest = new {Name="橙子",Age=25 };
- var Guests = Enumerable.Repeat(guest, 5);
- //13.Empty 用于獲得一個(gè)指定類型的空序列
- var empty = Enumerable.Empty<string>();
- //14.DefaultIfEmpty 用于獲得序列,如果為空,則添加一個(gè)默認(rèn)類型元素
- //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());//默認(rèn)為null
- foreach (var n in query.DefaultIfEmpty())
- {
- Console.WriteLine(n);
- }
- Console.WriteLine("---------------");
- Console.ReadKey(false);
- //c指定一個(gè)默認(rèn)值
- 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);
- }
- }
- }
程序的運(yùn)行結(jié)果如下:
15.OfType篩選指定類型的元素
16.Cast類型轉(zhuǎn)換
17.AsEnumerable有些數(shù)據(jù)源類型不支持Enumerable的部分查詢關(guān)鍵字,需要轉(zhuǎn)換下,譬如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類型轉(zhuǎn)換
- 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);
- }
- }
- }
程序運(yùn)行結(jié)果如下:
延時(shí)執(zhí)行,顧名思義就是不是立即執(zhí)行,即不是在查詢語(yǔ)句定義的時(shí)候執(zhí)行,而是在處理結(jié)果集(如遍歷)的時(shí)候執(zhí)行,在Enumerable類方法成員中,除了本節(jié)總結(jié)的這常用的17個(gè)外,前面博文---LINQ基本子句 中總結(jié)的8個(gè)基本子句也都是延時(shí)執(zhí)行的。注意延時(shí)執(zhí)行的查詢程序的執(zhí)行流程。
原文鏈接:http://www.cnblogs.com/DebugLZQ/archive/2012/11/08/2759543.html
【編輯推薦】
- Linq to xml操作XML
- XML之父解讀未來(lái)互聯(lián)網(wǎng)"游戲化"的三個(gè)真諦
- Ajax和Web服務(wù)數(shù)據(jù)格式:XML SOAP HTML
- 超強(qiáng)解析XML——簡(jiǎn)單直接的來(lái)
- 解析PHP中的XML數(shù)據(jù)