朋友,或许你了解委托,熟悉监视者模式,常用lambda表达式或者linq查询,自定义过扩展方法,但假如你没留意过他们之间的关系,不清楚委托是如何演变为lambda表达式,再如何导出linq语句的,又或者想了解以上知识内容的,那么就进来一起学习本节吧。本节我们要了解委托和监视者模式,然后再由匿名委托一步步导出lambda表达式,最后用lambda表达式结合扩展方法来举例阐释Linq查询。这节是委托到Linq集成化查询的小小推导,希望能对大家有所帮助。本人新手上路,难免纰漏重重,还望大伙儿海涵。更希望大家能提出宝贵意见,鄙人感激不尽。下面咱们就一起探讨学习本节内容吧……
委托:
用Delegate 关键字声明委托,下面要引用MSDN上的一段内容,它们概括出我不能解释的隐含知识:委托是一种引用方法的类型。一旦为委托分配了方法,委托将与该方法具有完全相同的行为。委托方法的调用可以像其他任何方法一样,具有参数和返回值。委托是一种安全地封装方法的类型,它与 C 和 C++ 中的函数指针类似。与 C 中的函数指针不同,委托是面向对象的、类型安全的和保险的。委托的类型由委托的名称定义。下面的示例声明了一个名为 Del 的委托,该委托可以封装了采用字符串作为参数并返回 void类型 的方法。public delegate void Del(string message); 下面写个委托的例子来帮组大家理解,重点是要理解其中为什么可以把方法名赋值给委托对象。可以参考例子:int a = 0;因为等号左右同为数值类型,类型一致,所以可以赋值。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 using System; 2 //这个委托的名字是MyDel,委托的类型是MyDel 3 //这个委托代表了一系列函数,这一些函数必须是没有返回值,没有参数。 4 public delegate void MyDel(); 5 //这个委托代表了一系列函数,这一系列函必须是返回值为String,并且有一个String类型的参数。 6 public delegate void MyDel2(string name); 7 //这个委托代表了一系列函数,这一系列函数必须是返回值为String,并且有一个String类型的参数。 8 public delegate int MyDel3(int a,int b); 9 public class StudyDelegate 10 { 11 public static void Main() 12 { 13 //创建委托对象的两种方法: 14 //1.如果使用new关键字来创建委托对象,则必须使用一个函数初始化这个委托对象。 15 MyDel2 my = new MyDel2(print); 16 //2.如果不使用new关键字来创建委托对象,则可以直接赋值。 17 MyDel2 m1 = print2; 18 //委托和他封装的方法具有相同的功能。 19 //my("ss"); 20 //m1("ww"); 21 //4,既然委托代表了一系列函数,那么一个委托对象可以承接多个函数。 22 my += print2; 23 my("ss"); 24 //在承接的函数集中删减函数 25 my -= print2; 26 my("ss"); 27 28 29 } 30 public static void print(string name) 31 { 32 33 Console.WriteLine("print----------"+name); 34 35 } 36 public static void print2(string n) 37 { 38 Console.WriteLine("2222----------"+n); 39 } 40 41 }
既然我们初步了解了委托,知道委托的定义和形式,那么咱们再一起学习一下委托的常用环境:我举几个简单小例子来引如今天所要说的委托,仔细体会其中的区别:
1.
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 using System; 2 public class StudyDelegate1 3 { 4 public static void Main() 5 { 6 SayHello("中国"); 7 } 8 public static void SayHello(string county) 9 { 10 if(country=="中国") 11 { 12 Say(content); 13 } 14 if(country=="USA") 15 { 16 Say(content); 17 } 18 if(country=="England") 19 { 20 Say(content); 21 } 22 23 } 24 }
如果有必要加入新的成员国家,则整个程序都要变动,程序健壮性很差。下面我稍加修改:
2.
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 using System; 2 //相比上面方法,抽象出了枚举 3 public enum Country 4 { 5 中国,American,England,Japan,Koran 6 } 7 public class StudyDelegate1 8 { 9 public static void Main() 10 { 11 SayHello("中国"); 12 } 13 public static void SayHello( Country country,string content) 14 { 15 if(country== Country."中国") 16 { 17 Say(content); 18 } 19 if(country==Country."USA") 20 { 21 Say(content); 22 } 23 if(country==Country."England") 24 { 25 Say(content); 26 } 27 28 } 29 //抽象出了共同的方法体 30 public void Say(string content) 31 { 32 Console.WriteLine(content); 33 } 34 }
加入新的成员国家时候,if语句内容,枚举内容都要更改,健壮性依然很差,下面我用委托知识再稍加修改:
3.
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 using System; 2 public delegate void DelSay(string content); 3 public class StudyDelegate1 4 { 5 public static void Main() 6 { 7 //采用委托,根据不同国家调用不同内容 8 SayHello("你好",CSay); 9 SayHello("Hello",ESay); 10 11 } 12 //方法主题部分 13 public static void SayHello(string content,DelSay ds) 14 { 15 ds(content); 16 17 } 18 public static void CSay(string content) 19 { 20 Console.WriteLine(content); 21 } 22 public static void ESay(string content) 23 { 24 Console.WriteLine(content); 25 } 26 }
上述委托是当做参数来传递的,传递之后就可以当做方法使用。封装了共同方法,又传入委托做参数来调用方法后,当添加新的成员国家,我们就不必再更改方法的主题部分,相比之上的两个程序,它安全性、可拓展性就好很多。了解了什么是委托了,我们就要来看看什么是监视者模式。
监视者模式:
监视者模式是在微软平台上大量存在的一种模式,通俗一点它就是事件,事件就是监视者模式。比如生活中,你睡觉的时候委托同学上课叫醒你,这就是一个监视者模式,你是被监视者,是委托方,同学是被委托方,监视者。下面给大家举个例子:考试的时候自己委托父母监视自己,考的好的话让父母奖励,考差了则受罚的监视者模式:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 using System; 2 public delegate void Del(); 3 4 public class StudyObserver 5 { 6 public static void Main() 7 { 8 //创建对象 9 Student s = new Student(); 10 //Parent pp = new Parent(); 11 //Parent1 pp1 = new Parent1(); 12 13 //s发布两个奖励委托 14 s.p = ()=>{Console.WriteLine("sss");}; 15 s.k =()=>{Console.WriteLine("wwww");}; 16 //s发布两个个惩罚委托 17 //s.k = pp.KKit; 18 //s.k+=pp1.KKit; 19 //s开始执行考试 20 s.Exam(); 21 } 22 } 23 /* 24 发布委托者 25 被监视方、 26 */ 27 public class Student 28 { 29 //声明两个委托变量 30 public Del p = null; 31 public Del k = null; 32 //执行考试(用循环语句模拟考试过程) 33 public void Exam() 34 { 35 for(int i=0;i<=100;i++) 36 { 37 if(i<60) 38 { 39 k(); 40 }else 41 { 42 p(); 43 } 44 } 45 } 46 } 47 /* 48 接受委托方 49 监视方 50 */ 51 public class Parent 52 { 53 //监视者的方法 54 public void PPrice() 55 { 56 Console.WriteLine("考的不错,奖励个馒头"); 57 } 58 public void KKit() 59 { 60 Console.WriteLine("考的太差,面壁思过"); 61 } 62 } 63 /* 64 接受委托方 65 监视方 66 */ 67 //追加的监视者,因为委托可以承接多个函数 68 public class Parent1 69 { 70 public void PPrice() 71 { 72 Console.WriteLine("多奖励一个馒头"); 73 } 74 public void KKit() 75 { 76 Console.WriteLine("考的太差"); 77 } 78 }
平常生活中遇到的监视者模式的例子很多很多,像在visual studio中窗体的button等控件和窗体之间就是监视者模式,当点击button控件时候,不是空间本身字节处理,而是通过form窗体 做出处理(单击button按钮后form窗体来做出反应,弹出对话框)。整个过程不是button自己处理事件,而是button按钮委托form窗体来处理,这时候button就是委托方,form窗体就是监视方。监视者模式其实就是一种委托类型,了解了日常生活中的监视者模式,我们就来看看一种另类的委托------匿名委托…
匿名委托:
匿名委托也是一种委托,只不过没有方法名,可以理解为用delegate代替了匿名委托的方法名,很多情况在不必要创建方法,需要临时创建方法来调用时使用 ,下面例子能很好说明匿名委托的不同用法
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 using System; 2 public delegate void Delsing(); 3 public delegate int DelPlus(int a, int b); 4 public delegate string DelString(string a, int b); 5 public class StudyDelegate 6 { 7 public static void Main() 8 { 9 //委托 10 Delsing d = Sing; 11 d(); 12 //匿名委托 13 Delsing d1 = delegate(){Console.WriteLine("匿名委托");}; 14 d1(); 15 //带参数且有返回值的匿名委托 16 DelPlus d2 = delegate(int j, int k){return j+k;}; 17 Console.WriteLine(d2(1,2)); 18 //带参数且有返回值的匿名委托,当做参数来传,然后调用函数实现功能 19 DelString d3 = delegate(string a, int b){return a+b;}; 20 Test(d3,"1+1=",2); 21 } 22 public static void Test(DelString del,string a, int b) 23 { 24 string str = del(a,b); 25 Console.WriteLine(str); 26 } 27 public static void Sing() 28 { 29 Console.WriteLine("I'm singing"); 30 } 31 public static void Print() 32 { 33 } 34 35 }
熟悉了匿名委托之后,我们就可以推导lambda表达式了,lambda表达式其实就是匿名委托的‘变种’:
lambda表达式:
lambda表达式其实就是匿名委托精简之后的形式,在参数和方法体中间补上 ‘=>’(称作goes to)来表示这是lambda表达式。下面来看一下lambda表达式具体例子:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 using System; 2 public delegate void Delsing(int c); 3 public delegate int DelPlus(int a, int b); 4 public delegate string DelString(string a, int b); 5 public class StudyDelegate 6 { 7 public static void Main() 8 { 9 //匿名函数 10 //Delsing d1 = delegate(int c){Console.WriteLine(c);}; 11 //转化lambda表达式时候要去掉delegate 加上=> 12 //Delsing d1 = (int c)=>{Console.WriteLine(c);}; 13 //一个参数的时候可以去掉括号,不论什么时候参数类型可以省略系统根据委托名自动判断 14 Delsing d1 = c=>{Console.WriteLine(c);}; 15 //函数调用 16 //Test(d1,45); 17 Test(c=>{Console.WriteLine(c);},45); 18 19 /*-----下面委托到lambda表达式的一步步变形同上-------*/ 20 //匿名函数转化为lambda表达式的最初形式 21 DelPlus d2 = (a,b)=>{int c = a+b;return c;} ; 22 //Test(d2,1,2); 23 Test((a,b)=>{int c = a+b;return c;},8,9); 24 //当有返回值,并且直接返回时候,匿名函数中{}可以换做(),并且省略return 25 DelPlus d3 = (a,b)=>(a+b); 26 //调用方法时候,最前面始传的是委托对象,后面是参数 27 //Test(d3,6,5); 28 Test((a,b)=>(a+b),6,7); 29 30 31 DelString d4 = (a,b)=>(a+" "+b); 32 //Test(d4,"h",34); 33 Test((a,b)=>(a+" "+b),"h",45); 34 35 } 36 //函数的重载 37 public static void Test(Delsing d,int a) 38 { 39 d(a); 40 } 41 42 public static void Test(DelPlus d,int a,int b) 43 { 44 int c = d(a,b); 45 Console.WriteLine(c); 46 } 47 public static void Test(DelString d,string a ,int b) 48 { 49 string s = d(a,b); 50 Console.WriteLine(s); 51 } 52 53 }
看了上面例子后,相信你对lambda表达式已有初步印象,下面我做一下lambda表达式不同形式的小总结:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 先定义一个Del开头的委托 2 1. public delegate void Del1(); 3 匿名委托 4 Del1 d1 = delegate(){Console.WriteLine("ss");}; 5 d1 = ()=>{Console.WriteLine("ss");}; 6 //由于没有参数,那么()不能省略 7 2.public delegate int Del2(); 8 Del2 d2 = delegate(){return 1;}; 9 d2 = ()=>{return 1;}; 10 //如果是直接返回,换句话说就是没有业务逻辑处理,也就是只有一条返回语句,可以把{}换成()同时去掉return关键字 11 d2=()=>(1); 12 //如果方法体中有业务逻辑,则必须使用{} 13 d2=()=>{if(2>1){return 1;}else{return 2;}}; 14 3.public delegate void Del3(string a); 15 Del3 d3 = delegate(string a){Console.WriteLine(a);}; 16 d3 = (stirng a)=>{Console.WriteLine(a);}; 17 //可以把参数的类型给去掉,因为系统会自行的判断参数的类型,毕竟是把这个lambda赋值给了对应的委托。 18 d3 = (a)=>{Console.WriteLine(a);}; 19 //如果说只有一个参数,则不需要() 20 d3 = a =>{Console.WriteLine(a);}; 21 4.public delegate string Del4(string a); 22 Del4 d4 = delegate(string a){string c = a+78;return c;} 23 d4 = (string a)=>{a+78;return a;}; 24 d4 = a=>{a+78;return a;} 25 d4 = a=>("gg"); 26 5.public delegate int Del5(int a,int b); 27 Del5 d5 = delegate(int a,int b){return a+b;}' 28 d5 = (int a,int b)=>{return a+b;}; 29 d5 = (a,b)=>{return a+b;}; 30 //如果参数个数是大于1的时候,不能把小括号给去掉 31 d5 = (a,b)=>(a+b); 32 d5 = (a,b)=>a+b; 33 d5 = a=>a+1;
lambda表达式的内容就先说到这里,如果大家还要了解更多相关知识,请查看博客园中其他更多有关文章。下面我们小看一下linq
Linq语言集成化查询:
linq不同与结构化查询语言(SQL)它不仅可以查询数据而且可以查询对象。
LINQ 的官方中文名称为“.NET 语言集成查询”,英文全称为 Language-Integrated Query。它提供了类似于 SQL 语法的遍历,筛选与投影功能,LINQ 不仅能完成对于对象的查询,它可以透过 DLINQ 操纵数据库,或是透过 XLINQ 控制 XML.我们来比较下两个不同方法来求出数组中大于20的数据的例子:
1.常用方法:结合上一节讲述的泛型知识,可以把数据放入泛型列表中,再用foreach语句循环输出:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 using System; 2 using System.Collections.Generic; 3 public class StudyLinq 4 { 5 public static void Main() 6 { 7 int[] a = {2,23,25,14,1,80,16,26,30}; 8 //求出数组中大于20的数据 9 List<int> list = new List<int>(); 10 foreach(int b in a) 11 { 12 if(b>20) 13 { 14 list.Add(b); 15 } 16 } 17 foreach(int c in list) 18 { 19 Console.WriteLine(c); 20 } 21 } 22 }
2.用IEnumerable的Where扩展方法,通过lambda表达式,精简程序执行过程,需要导入命名空间:using System.Linq;
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 public class StudyLinq 5 { 6 public static void Main() 7 { 8 int[] a = {2,23,25,14,1,80,16,26,30}; 9 //求出数组中大于20的数据 10 //lambda表达式 11 //var c =a.Where(p=>{return p > 20;}); 12 //化简后 var可以接受任何类型 13 var c =a.Where(p=> p > 20); 14 //Where 返回类型是IEnumerable 15 //IEnumerable<int> c =a.Where(p=> p > 20); 16 foreach(int i in c) 17 { 18 Console.WriteLine(i); 19 } 20 21 } 22 }
上面可以算作小的linq查询,但能算真正的linq,我暂时理解为广义的linq。 例子中(p=> p > 20)其实就是个lambda表达式,是微软定义好的一个委托,从这个委托的特点我们知道它有一个参数,返回值是bool类型。数组肯定实现了IEnumerable接口,而Where是IEnumerable<(Of <(T>)>) 成员 的一个扩展方法,MSDN中定义为 Where(Func<(Of <(UMP, Boolean>)>)) 基于谓词筛选值序列。 (由 Enumerable 定义。)
public static IEnumerable<TSource> Where<TSource>(
this IEnumerable<TSource> source,
Func<TSource, bool> predicate
)
public delegate TResult Func<T, TResult>(
T arg
)
结合本例子上面两句则可以删减为以下两种形式:
public delegate bool Func(T arg)
Func = p=>{return p > 10;};
p=>()p>10
p=>p>10
上面的三个lambda其实是等效的,实现的一个功能
public static IEnumerable Where(Func<TSource, bool> predicate)
linq查询语句就是利用微软定义好的方法,执行一定条件的查询语句。(好像表达的不够明白,下面再做一个例子来说明,希望能帮组大家理解):
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 public class StudyLinq 5 { 6 public static void Main() 7 { 8 List<Student> list = new List<Student>(); 9 list.Add(new Student(){Age=10,Name="Jack"}); 10 list.Add(new Student(){Age=67,Name="Mack"}); 11 list.Add(new Student(){Age=23,Name="Dack"}); 12 list.Add(new Student(){Age=56,Name="Cack"}); 13 list.Add(new Student(){Age=8,Name="Eack"}); 14 list.Add(new Student(){Age=34,Name="Hack"}); 15 list.Add(new Student(){Age=18,Name="小红"}); 16 //查询出结合中年龄大于45的学生 17 Func<Student,bool> f = p=>p.Age>45; 18 IEnumerable<Student> result = list.Where<Student>(f); 19 foreach(Student s in result) 20 { 21 Console.WriteLine(s.Age+" "+s.Name); 22 } 23 //查询出集合中年令小于30的,并且名字已E得学生 24 var result1 = list.Where(p=>p.Age<30 && p.Name.StartsWith("E")); 25 foreach(Student s in result1) 26 { 27 Console.WriteLine(s.Age+" "+s.Name); 28 } 29 30 } 31 32 } 33 public class Student 34 { 35 public int Age 36 { 37 get; 38 set; 39 } 40 public string Name 41 { 42 get;set; 43 } 44 }
linq查询调用了微软定义好的扩展方法进行查询,下面我们插入一段扩展方法的内容,帮助理解上面linq中的Where扩展方法。
扩展方法:
通俗点说就是在不更改原来类的基础山,为类添加方法。需要注意的是:1,扩展方法必须写静态类中。 2,扩展方法必须是静态方法,虽然是静态方法,但是这个扩张方法是为对象扩展的,只能由对象调用。它的定义是:
public static class 类名
{
public static 返回值 方法名(this 要扩展的类型 对象名[,参数列表])
{
}
}
我们来做三个扩展方法,1.为string类扩展个获取文件类型的方法。2.为自定义的People类扩展一个看时间的方法。3.扩展一个获取姓名的方法,下面我们一起来看看:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 public class StudyExtendMethod 5 { 6 public static void Main() 7 { 8 //调用扩展方法获取文件类型 9 string file = @"E:\FTPPUBLISH\学习资料\KindEditor\kindeditor-v4.0.3\examples\colorpicker.html"; 10 Console.WriteLine(file.GetFileType()); 11 string sss = "78.9.09.mp3"; 12 Console.WriteLine(sss.GetFileType()); 13 //调用扩展方法获取时间 14 People pp = new People(); 15 pp.WatchTime("www"); 16 //获取信息 17 string od = pp.GetInfo("张三"); 18 Console.WriteLine(od); 19 //为IEnumerable扩展获取IEnumerable<int>中前十个元素的方法 20 List<int> list = new List<int>(); 21 list.Add(1); 22 list.Add(19); 23 list.Add(34); 24 list.Add(56); 25 list.Add(2); 26 list.Add(90); 27 list.Add(23); 28 list.Add(27); 29 var c = list.GetBigTen(10); 30 foreach(int d in c) 31 { 32 Console.WriteLine(d); 33 } 34 35 } 36 } 37 public static class ExtendMethod 38 { 39 /* 40 this string ss 41 这个参数只起到一个说明性作用。 42 这个扩展方法是为string的对象扩展的,只能有string的对象来使用 43 str值得是使用这个扩展方的对象。 44 */ 45 public static string GetFileType(this string str) 46 { 47 string[] strs = str.Split('.'); 48 return strs[strs.Length-1]; 49 } 50 //this People p说明这个扩展方法是为people对象扩展的,只能由People对象调用 51 public static void WatchTime(this People p,string name) 52 { 53 Console.WriteLine(name +" "+DateTime.Now); 54 } 55 public static string GetInfo(this People p,string name) 56 { 57 return name+"sssss"; 58 } 59 public static IEnumerable<int> GetBigTen(this List<int> list,int a) 60 { 61 return list.Where(p=>p>a); 62 } 63 64 } 65 public class People 66 { 67 68 }
理解了这些扩展方法,相信会有助于你理解上面linq查询时所用的Where扩展方法。下面我们继续来看linq查询,把上面的linq再做一步扩展:
用linq语句进行查询,并将结果降序分组排列的三种方法
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 public class StudyLinq 5 { 6 public static void Main() 7 { 8 List<Student> list = new List<Student>(); 9 list.Add(new Student(){Age=10,Name="Jack",Address="bj"}); 10 list.Add(new Student(){Age=67,Name="Mack",Address="郑州"}); 11 list.Add(new Student(){Age=23,Name="Dack",Address="USA"}); 12 list.Add(new Student(){Age=56,Name="Cack",Address="bj"}); 13 list.Add(new Student(){Age=8,Name="Eack",Address="郑州"}); 14 list.Add(new Student(){Age=34,Name="Hack",Address="bj"}); 15 list.Add(new Student(){Age=18,Name="小红",Address="USA"}); 16 //查询出结合中年龄大于45的学生(完整的形式,一般不这样写) 17 Func<Student,bool> f = p=>p.Age>45; 18 IEnumerable<Student> result = list.Where<Student>(f); 19 foreach(Student s in result) 20 { 21 Console.WriteLine(s.Age+" "+s.Name); 22 } 23 //查询出集合中年令小于30的,并按年龄降序排列,并按城市分组 24 //第一种方法 25 IEnumerable<Student> result1 = list.Where(p=>p.Age<30).OrderByDescending(p=>p.Age); 26 27 foreach(Student s in result1) 28 { 29 Console.WriteLine(s.Age + " "+s.Name); 30 } 31 IEnumerable<IGrouping<string,Student>> result2 = result1.GroupBy<Student,string>(p=>p.Address); 32 33 foreach(IGrouping<string,Student> gg in result2) 34 { 35 foreach(Student s in gg) 36 { 37 Console.WriteLine(s.Age + " "+s.Name+" "+s.Address); 38 } 39 } 40 41 42 43 44 45 /*分组的第二种方法 46 var result1 = list.Where(p=>p.Age<30).OrderByDescending(p=>p.Age).GroupBy(p=>p.Address); 47 var c = result1.GetEnumerator(); 48 while(c.MoveNext()) 49 { 50 var d = c.Current.GetEnumerator(); 51 52 while(d.MoveNext()) 53 { 54 Console.WriteLine(d.Current.Name+" "+d.Current.Address); 55 } 56 57 }*/ 58 /*分组的第三种方法 59 var result1 = list.Where(p=>p.Age<30).OrderByDescending(p=>p.Age); 60 var result2 = from p in result1 group p by p.Address; 61 foreach(Student s in result1) 62 { 63 Console.WriteLine( s.Age + " "+s.Name+" "+s.Address); 64 }*/ 65 66 } 67 68 } 69 public class Student 70 { 71 public int Age 72 { 73 get; 74 set; 75 } 76 public string Name 77 { 78 get;set; 79 } 80 public string Address 81 {get;set;} 82 }
理解了上面例子的查询过程,你就掌握了基本的linq查询了。仔细领会其执行顺序,要理清各语句关系。
再做两个小例子,这是我理解的完全的linq查询:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 public class StudyLinq3 5 { 6 public static void Main() 7 { 8 9 List<Student> list = new List<Student>(); 10 list.Add(new Student(){Age=10,Name="Jack",Address="bj"}); 11 list.Add(new Student(){Age=67,Name="Mack",Address="郑州"}); 12 list.Add(new Student(){Age=23,Name="Dack",Address="USA"}); 13 list.Add(new Student(){Age=56,Name="Cack",Address="bj"}); 14 list.Add(new Student(){Age=8,Name="Eack",Address="郑州"}); 15 list.Add(new Student(){Age=34,Name="Hack",Address="bj"}); 16 list.Add(new Student(){Age=18,Name="小红",Address="USA"}); 17 IEnumerable<IGrouping<string,Student>> result = from p in list 18 where p.Age > 30 19 orderby p.Age ascending 20 group p by p.Address; 21 // select p; 22 foreach(IGrouping<string,Student> s in result) 23 { 24 foreach(Student ss in s) 25 { 26 Console.WriteLine(ss.Age +" "+ss.Address); 27 } 28 } 29 30 /*用前面讲到的扩展方法来查询长度大于三的元素 31 string[] str = {"a","bb","abc","中华民谣","USA"}; 32 33 IEnumerable<string> result = from p in str 34 where p.Length>3 35 select p; 36 foreach(string s in result) 37 { 38 Console.WriteLine(s); 39 } 40 41 42 IEnumerable<string> result = str.Where<string>(p=>p.Length>3); 43 foreach(string s in result) 44 { 45 Console.WriteLine(s); 46 }*/ 47 } 48 } 49 50 public class Student 51 { 52 public int Age 53 { 54 get; 55 set; 56 } 57 public string Name 58 { 59 get;set; 60 } 61 public string Address 62 {get;set;} 63 }
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 public class StudyLinq3 5 { 6 public static void Main() 7 { 8 9 List<Student> list = new List<Student>(); 10 list.Add(new Student(){Age=10,Name="Jack",Address="bj"}); 11 list.Add(new Student(){Age=67,Name="Mack",Address="郑州"}); 12 list.Add(new Student(){Age=23,Name="Dack",Address="USA"}); 13 list.Add(new Student(){Age=56,Name="Cack",Address="bj"}); 14 list.Add(new Student(){Age=8,Name="Eack",Address="郑州"}); 15 list.Add(new Student(){Age=34,Name="Hack",Address="bj"}); 16 list.Add(new Student(){Age=18,Name="小红",Address="USA"}); 17 var result = ( from p in list 18 where p.Age >30 19 select p).OrderByDescending(pp=>pp.Age); 20 21 foreach(Student s in result) 22 { 23 Console.WriteLine(s.Age); 24 } 25 26 } 27 } 28 29 public class Student 30 { 31 public int Age 32 { 33 get; 34 set; 35 } 36 public string Name 37 { 38 get;set; 39 } 40 public string Address 41 {get;set;} 42 }
最后我们做个小小的linq总结:Linq语言集成化查询基础是泛型和lambda表达式他的形式是:
from 元素 in 集合
where 元素条件
orderby 元素.属性 ascending
group 元素 by 元素.属性
select 元素
和SQL查询很类似,上面例子中以表明如果使用group by语句,则不需要select。
非常感谢大家腾出宝贵时间来阅读本节,本节的讲解很凌乱,如果有表达不明确之处,希望咱们私下能认真交流,共同学习。新手上路,大家多多关照…………