發(fā)文章
發(fā)文工具
撰寫
網(wǎng)文摘手
文檔
視頻
思維導(dǎo)圖
隨筆
相冊
原創(chuàng)同步助手
其他工具
圖片轉(zhuǎn)文字
文件清理
AI助手
留言交流
一,概念
1.1 查詢表達(dá)式起源
C#語言的設(shè)計(jì)者決定在C#3中提供一個(gè)新的語法:查詢表達(dá)式。
以此彌補(bǔ)復(fù)雜語句中標(biāo)準(zhǔn)查詢運(yùn)算符的難以理解、復(fù)雜與提高與Sql語句的相似度來便于學(xué)習(xí)(查詢表達(dá)式與SQL最大的區(qū)別是from與Select的位置倒置,這是為IDE提供智能感知的”推斷“類型功能)。
1 string[] Keywords = { "abstract", "Int", "base"}; 2 3 // “標(biāo)準(zhǔn)”查詢表達(dá)式例子 4 var query = from word in Keywords 5 where !word.Contains("a") 6 select word; // 自處select最后會(huì)被編譯器省略,稍后會(huì)講到。
上面的例子是簡潔版查詢表達(dá)式的一個(gè)Demo,查詢表達(dá)式其實(shí)是對底層API的一系列方法的調(diào)用。CIL本身并不理解“查詢表達(dá)式”的概念。事實(shí)上,除了涉及表達(dá)式樹的地方能使用查詢表達(dá)式,但底層CLR根本沒有改動(dòng),相反,查詢表達(dá)式是通過
C#編譯器的改動(dòng)來支持這一特性的。
以上代碼編譯之后通過,IL查看的部分編碼如下:
1 .field private static class [mscorlib]System.Func`2<string,bool> 'CS$<>9__CachedAnonymousMethodDelegate1' 2 .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
1 .method private hidebysig static bool '<MyDemo>b__0'(string word) cil managed 2 { 3 .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) 4 // Code size 19 (0x13) 5 .maxstack 2 6 .locals init ([0] bool CS$1$0000) 7 IL_0000: ldarg.0 8 IL_0001: ldstr "a" 9 IL_0006: callvirt instance bool [mscorlib]System.String::Contains(string) 10 IL_000b: ldc.i4.0 11 IL_000c: ceq 12 IL_000e: stloc.0 13 IL_000f: br.s IL_0011 14 IL_0011: ldloc.0 15 IL_0012: ret 16 } // end of method '查詢表達(dá)式'::'<MyDemo>b__0'
通過對編譯后的DLL分析,得出兩個(gè)結(jié)論:
1) 查詢表達(dá)式確實(shí)被編譯成了委托,也就是說是編譯器執(zhí)行了代碼,而非運(yùn)行時(shí)或CLR支持。
2) 由于編譯時(shí)已經(jīng)生成了委托,所以大多數(shù)查詢表達(dá)式也是”延遲執(zhí)行“方式。
注:
1.2 查詢表達(dá)式的流處操作與緩沖操作
1) 緩沖操作:將所有數(shù)據(jù)一次性加載進(jìn)內(nèi)存,然后運(yùn)算,最后輸出結(jié)果。如Enumerable.Revense。
2) 流操作:一次處理每個(gè)序列的一個(gè)元素,提高效率。如下:
1 // 偽代碼 2 var query = from file in Directory.GetFiles(@"C:\CSharpInDepthLogs", "*.log") 3 from line in ReadLines(file) 4 let entry = new LogEntry(line) 5 where entry.Type == EntryType.Error 6 select entry; 7 8 Console.WriteLine("Total errors: {0}", query.Count());
3)join子句的內(nèi)聯(lián):左邊的子句是流處理方式,右邊的子句是緩沖方式,這種操作依然是延遲操作。(原則:效率至上,所以盡可能的右邊序列要小。)
1 // 語法 2 join right-range-variable in right-sequence 3 on left-key-selector equals right-key-selector
1.3 查詢表達(dá)式與點(diǎn)標(biāo)記(Dot notation)之間做出的選擇
點(diǎn)標(biāo)記:用普通的C#調(diào)用Linq查詢操作符來代替查詢表達(dá)式。(實(shí)際上編譯器轉(zhuǎn)化查詢表達(dá)式也是如此的過程)
原則:更加的可讀性及習(xí)慣性。查詢表達(dá)式更像是函數(shù)式編程,結(jié)構(gòu)化思維;而點(diǎn)標(biāo)記適合查詢條件比較少時(shí)清晰易懂。
查詢表達(dá)式是”說明性“的,與之相對的是”命令性“的語言,說明性的語言關(guān)心的是操作步驟而絕非僅僅是結(jié)果。
1 // 查詢表達(dá)式(復(fù)雜些) 2 var adults = from person in people 3 where person .Age > 18 4 select new { Name = person .Name, Age = person .Age} into result 5 orderby result.Age descending 6 select result; 7 8 // 點(diǎn)標(biāo)記(簡單些) 9 var adults2 = people.where(person => person.Age > 18);
二,查詢表達(dá)式操作符
2.1 From 與 Select
2.1.1 語法: from element select source, 以from開頭,以select結(jié)尾,其中 element 只是一個(gè)標(biāo)示符,select子句被稱為投影。
1 // 查詢表達(dá)式 2 var query = from user in SampleData.Allusers 3 select user; 4 5 // 編譯器轉(zhuǎn)換后的點(diǎn)標(biāo)記 6 var query = SampleData.Allusers.Select(user => user);
2.1.2 退化的查詢表達(dá)式
當(dāng)select子句什么都不做時(shí)會(huì)發(fā)生什么?答:編譯器依然會(huì)生成select方法的調(diào)用。
1 from item in SampleData.AllUsers select item;// 編譯器: SampleData.Allusers.Select(item=>item); 這就是退化查詢表達(dá)式
然而,這個(gè)表達(dá)式和簡單表達(dá)式Sample.Allusers還是有很大不同的,雖說他們返回的數(shù)據(jù)項(xiàng)時(shí)相同的,不同的是查詢表達(dá)式返回的是一個(gè)新的結(jié)果集,對結(jié)果集順序改變不會(huì)改變原數(shù)據(jù)集順序,但如果改變數(shù)據(jù)項(xiàng),則原數(shù)據(jù)也會(huì)改變。
1 var query = from word in Keywords 2 orderby word.Length 3 select word; 4 foreach (var item in query) 5 { 6 Console.WriteLine(item); 7 } 8 9 foreach (var item in Keywords) 10 { 11 Console.WriteLine(item); 12 } 13 14 List<string> target = query.toList(); // IEnumerable<T>.ToList方法為深拷貝。原型如下:15 //public static List<TSource> ToList<TSource>(this IEnumerable<TSource> source) 16 //{ 17 // if (source == null) 18 // { 19 // throw Error.ArgumentNull("source"); 20 // } 21 // return new List<TSource>(source); 22 //}
2.2 Where和OrderBy
2.2.1 OrderBy:ascending升序,descending降序 或者 OrderByDescending。OrderBy如果要繼續(xù)查詢需跟隨ThenBy,如若存在多個(gè)OrderBy,則最后一個(gè)OrderBy“獲勝”。
2.2.2 Where:
1 // 查詢表達(dá)式 2 var query = from c in cc 3 where c.Length == 7 4 where c.Name == Stephen 5 select c.Name; 6 // 查詢表達(dá)式被轉(zhuǎn)換為 7 cc.where(c=>c.Length ==7).where(c=>c.Name == Stephen);
2.3 let子句
消除不必要的重復(fù)“調(diào)用”
// 壞代碼:調(diào)用了兩次Name。Length var query = from user in Users orderby user.Name.Length select user.Name; foreach(var name in query) { Console.WriteLine("{0}:{1}",name.Length,name); } // 改造后的代碼 var queryNew = from user in Users let len = user.Name.Length orderby len select new {Name = user.Name,Length = len}; foreach(var entry in queryNew) { Console.WriteLine("{0}:{1}",entry.Name,entry.Length); }
2.4 聯(lián)接join
2.4.1 定義:他使用兩張數(shù)據(jù)表(視圖,表值函數(shù)等),通過匹配兩者之間的數(shù)據(jù)行來創(chuàng)建結(jié)果。
左邊序列進(jìn)行“流處理“,右邊序列進(jìn)行緩沖處理。
1 var query = from a in Sample.aa 2 join b in Sample.bb 3 on a.Name equals b.Name 4 select new { a.Name,b.Name};
2.4.2 join子句的內(nèi)連接
1 // 有過濾的內(nèi)聯(lián) 2 var query = from defect in Sample.AllDefects 3 where defect.Status == Status.Closed 4 join subscription in 5 (from sub in Sample.AllSubscriptions 6 where sub.Status == Status.Open 7 select sub) 8 on defect.Name equals subscription.Name 9 select new { defect.Summary, subscription.EmailAddress };
2.4.3 使用join...into 子句進(jìn)行分組聯(lián)接
1 var query = from defect in SampleData.AllDefects 2 join subscription in SampleData.AllSubscriptions 3 on defect.Project equals subscription.Project 4 into groupedSubscriptions 5 select new { Defect=defect, Subscriptions=groupedSubscriptions }; 6 7 foreach (var entry in query) 8 { 9 Console.WriteLine(entry.Defect.Summary); 10 foreach (var subscription in entry.Subscriptions) 11 { 12 Console.WriteLine (" {0}", subscription.EmailAddress); 13 } 14 }
2.5 分組和查詢延續(xù)
2.5.1 語法: group 投影 by 分組
1 // 分組 2 var query = from defect in SampleData.AllDefects 3 where defect.AssignedTo != null 4 group defect by defect.AssignedTo; 5 6 foreach (var entry in query) 7 { 8 Console.WriteLine(entry.Key.Name); 9 foreach (var defect in entry) 10 { 11 Console.WriteLine(" ({0}) {1}", 12 defect.Severity, 13 defect.Summary); 14 } 15 Console.WriteLine(); 16 } 17 ... 18 // 查詢延續(xù) 19 var query = from defect in SampleData.AllDefects 20 where defect.AssignedTo != null 21 group defect by defect.AssignedTo into grouped 22 select new { Assignee = grouped.Key, Count = grouped.Count() }; 23 24 foreach (var entry in query) 25 { 26 Console.WriteLine("{0}: {1}", 27 entry.Assignee.Name, 28 entry.Count); 29 }
來自: 昵稱10504424 > 《C#》
0條評(píng)論
發(fā)表
請遵守用戶 評(píng)論公約
LINQ基本子句
Linq學(xué)習(xí)筆記
Linq包括Linq to Objects, Linq to SQL,Linq to XML, Linq to DataSet等,本篇從Linq to Objects開始了解Linq的皮毛。擴(kuò)展方法是后文的基礎(chǔ),C#3.0中的Linq的實(shí)現(xiàn)都是基于擴(kuò)展方法,通過對IEnumerable&...
C# lamda表達(dá)式練習(xí)實(shí)例
static void Main(string[] args) { students = new List<Student> { new Student {Name = "Aaa",Age = 17 }, new Student {Name = "Bbb",Age = 18 }, new Student {Name = ...
C#高級(jí)篇——初識(shí)LINQ
//var res = from m in game// where m.gameID >1// select m.gameName;static void Main(string[] args){var res = from g in game ...
LINQ標(biāo)準(zhǔn)查詢操作符詳解
LINQ標(biāo)準(zhǔn)查詢操作符詳解。這是一個(gè)簡單的LINQ表達(dá)式,其中where和select是LINQ眾多標(biāo)準(zhǔn)查詢操作符中的兩個(gè),select是投影操作符,它在某個(gè)系列(即實(shí)現(xiàn)了Ienumerable<string>接口的對象上)上進(jìn)...
LINQ操作符四:排序操作符
LINQ操作符四:排序操作符。6 7 namespace 排序操作符 8 { 9 /// <summary>10 /// Teacher類11 /// </summary>12 public c...
一步一步學(xué)Linq to sql(一):預(yù)備知識(shí)
Linq to sql(或者叫DLINQ)是LINQ(.NET語言集成查詢)的一部分,全稱基于關(guān)系數(shù)據(jù)的 .NET 語言集成查詢,用于以對象形式管理關(guān)系數(shù)據(jù),并提供了豐富的查詢功能,它和Linq to xml、Linq to objects、L...
LINQ學(xué)習(xí)(五):Select子句
} } List<Student> students = new List<Student>{ new Student {Name="Terry", Scores=new List<int> {97, 72, 81, 60}}, new Student {Name="AI", Scores=new...
lambda表達(dá)式之進(jìn)化
lambda表達(dá)式之進(jìn)化。var preList = list.lambda表達(dá)式。那就是lambda表達(dá)式,匿名方法已經(jīng)夠簡潔的了,但是lambda表達(dá)式是比匿名方法更...
微信掃碼,在手機(jī)上查看選中內(nèi)容