导读: 1 预备知识
2 神马是LINQ
3 LINQ牛b的地方
4 剖析LINQ
5 LINQ扩展知识
预备知识: ① 扩展方法
.net framework 3.5中提供了扩展方法,何为扩展方法,举例如下:
假如有个string类型,我要为它写extension,那么应该如下:
public static class Extension { public static void ExtensionMethod(this string str) { Console.WriteLine("It's a extension for {0}", str); } }
需要注意,class和method都是static的,然后注意参数列表,有个“this”,这是关键,多个参数的时候,在第一个参数前添加。 写好之后,就可以为所欲为了,例如:
class Program { static void Main(string[] args) { string str = "test";
str.ExtensionMethod();
Console.ReadLine(); } }
②:lambda(λ)表达式 这个表达式说简单其实很简单,但复杂是真复杂,原因是在.net中,用到的地方太多了。一言以蔽之,arg-list => expr-body, 左边是参数,右边是方法体,操作符叫做Goes to。 举例如下:
static void Main(string[] args) { Func<int, int> b = a => { return a + 1; }; Console.WriteLine("Lambda :"+b(1)); Console.ReadLine(); }
注:Func是一种委托,输出结果是2。
也可简化下,一秒变格格,我变~:
static void Main(string[] args) { Func<int, int> b = a => a + 1; Console.WriteLine("Lambda :"+b(1)); Console.ReadLine(); }
是不是更简洁了,因为lambda的强大!
下面还原为传统的方式,格格变bra~~
class Program { delegate int DelegateLambda(int arg); static void Main(string[] args) { DelegateLambda delegateLambda = new DelegateLambda(AddMethod); int b = delegateLambda(1); Console.WriteLine("Lambda: " + b); Console.ReadLine(); } static int AddMethod(int arg) { int result = 0; result = arg + 1; return result; } }
在这段代码中,来对号入座,DelegateLambda 是自己定义的委托,对应了func;新写了个方法,AddMethod,这个方法对应了=>右边的方法体(其实是一个匿名函数,.net 3.5中的东东) ,方法体所用到的参数对应=>左边的那个a。
③:必要的sql知识:select , from , where ,orderby, groupby,。。。balabalabala&*$#@&.
④: .net framework 3.5以上版本!
神马是LINQ:
语言集成查询 (LINQ-Language Integrated Query的简称) 是一组技术的名称,这些技术建立在将查询功能直接集成到 C# 语言(以及 Visual Basic 和可能的任何其他 .NET 语言)的基础上。 借助于 LINQ,查询现在已是高级语言构造,就如同类、方法、事件等等。
对于编写查询的开发人员来说,LINQ 最明显的“语言集成”部分是查询表达式。 查询表达式是使用 C# 3.0 中引入的声明性查询语法编写的。 通过使用查询语法,甚至可以使用最少的代码对数据源执行复杂的筛选、排序和分组操作。 使用相同的基本查询表达式模式来查询和转换 SQL 数据库、ADO.NET 数据集、XML 文档和流以及 .NET 集合中的数据。
LINQ牛b的地方:
linq的牛逼之处在于,可以非常灵活的操作集合类对象(泛指继承自IEnumerable接口的对象),xml对象,以及数据库对象,linq上升到语言角度,可以做到像操作T-sql那样灵活自如而不失优雅,使我们更多的关注于业务逻辑而不至于为业务实现而费神。
linq,其实就是DSL,优雅的实现,真的是你秒杀各种需求的必备良药哦~
(DSL的编译过程应该是:DSL->Common c# code ->msil)
吹了半天牛b,来,来个实例,体会下linq这把利剑:
static void Main(string[] args) { List<int> intArr = new List<int> {5,2,7, 23,7,9,15}; var result = from i in intArr where (i > 7) select i; foreach (var ele in result) { Console.WriteLine(ele); } Console.ReadLine(); }
筛选的结果输出后为:23 9 15 是不是很有写sql语句的感觉?嘿,又要变格格了~~
static void Main(string[] args) { List<int> intArr = new List<int> {5,2,7, 23,7,9,15}; var result = intArr.Where(i => i > 7) .Select(i=>i); foreach (var ele in result) { Console.WriteLine(ele); } Console.ReadLine(); }
输出的结果是一样一样滴,为什么呢,再想想lambda表达式和扩展方法,(*^__^*) 好,再来一个:
static void Main(string[] args) { List<int> intArr = new List<int> {5,2,7, 23,7,9,15}; var result = intArr.Where(i => i > 2) .OrderByDescending(i=>i) .Select(i=>i); foreach (var ele in result) { Console.WriteLine(ele); } Console.ReadLine(); }
输出结果是:23 15 9 7 7 5
这段代码是降序排列的代码,是不是感觉还行~~,但是还有两个7,比较烦人呢,好,去掉:
static void Main(string[] args) { List<int> intArr = new List<int> {5,2,7, 23,7,9,15}; var result = intArr.Where(i => i > 2) .OrderByDescending(i=>i).Select(i=>i).Distinct(); foreach (var ele in result) { Console.WriteLine(ele); } Console.ReadLine(); }
输出结果为:23 15 9 7 5 怎么样,linq是不是不错呢,要是觉得这有些幼稚,不要捉急,还有各种操作xml的linq和数据库的呢,再这里就不写连接查询了,算是留个小悬念,要有兴趣最好写几个联合查询。
*剖析LINQ:(这个是重点,帮助你更好理解linq的幕后) linq如此强大,究竟编译器在背后干了些什么见不得人的勾当啊,其实,幕后真没有什么神奇的东东,如果反编译的话(好吧,其实我看不太懂msil ^^),你会发现,真的可以还原为普通的c#代码,这也就证明了linq的编译:DSL->common c# ->msil模式。 闲话不多说,还是用代码来说明一切:
首先定义一个Person类
public class Person { //姓名 public string name { get; set; } //年龄 public int age { get; set; } //婚姻状况 public bool isMarry { get; set; } }
初始化一些人。现在tc要跨省他们中大于20岁的人~~传统的做法是这样:
static void Main(string[] args) { IList<Person> persons = new List<Person> (); IList<Person> result = new List<Person>(); persons.Add(new Person { name = "狗剩", age = 22, isMarry = false }); persons.Add(new Person { name = "二蛋子", age = 28, isMarry = true }); persons.Add(new Person { name = "大黄", age = 10, isMarry = false }); persons.Add(new Person { name = "傻蛋", age = 30, isMarry = true }); persons.Add(new Person { name = "小李子", age = 19, isMarry = false }); foreach (Person p in persons) { if (p.age > 20) result.Add(p); } foreach (Person p in result) { Console.WriteLine(p.name); } Console.ReadLine(); }
输出结果是:狗剩 二蛋子 傻蛋
现在相关部门说了,要跨省一些结婚的,那么我们是不是还要重写这个方法呢,真tmd烦人啊,要是LD又说了,要找身高大于180cm的(当然这里我懒,没定义这个属性),我还要重写啊,LD真的好烦哎。好吧,你的老大说了,其实我们可以简单点,if里边不就是一个条件吗,我们可以单独写,是不是更好呢 于是我们可以这样来: 先定义一个委托 delegate bool Condition(Person p); 然后写将要委托的方法,领导不是说要找结了婚的吗:
class Program { public delegate bool Condition(Person p); static void Main(string[] args) { IList<Person> persons = new List<Person> (); IList<Person> result = new List<Person>(); persons.Add(new Person { name = "狗剩", age = 22, isMarry = false }); persons.Add(new Person { name = "二蛋子", age = 28, isMarry = true }); persons.Add(new Person { name = "大黄", age = 10, isMarry = false }); persons.Add(new Person { name = "傻蛋", age = 30, isMarry = true }); persons.Add(new Person { name = "小李子", age = 19, isMarry = false }); result = SearchPerson(new Condition(ConditionIsMarry),persons); foreach (Person p in result) { Console.WriteLine(p.name); } Console.ReadLine(); } public static IList<Person> SearchPerson(Condition condition, IList<Person> persons) { IList<Person> result = new List<Person>(); foreach (Person p in persons) { if (condition(p)) result.Add(p); } return result; } public static bool ConditionIsMarry(Person p) { if (p.isMarry) return true; return false; } }
这样我们可以写很多个查询条件,想用哪个用哪个,这样不用很多修改,更有利于扩展。接下来,你懂得,又要变了,还记得前面提到的匿名方法吗,好了,现在用到了,我们委托一个匿名方法:
static void Main(string[] args) { IList<Person> persons = new List<Person> (); IList<Person> result = new List<Person>(); persons.Add(new Person { name = "狗剩", age = 22, isMarry = false }); persons.Add(new Person { name = "二蛋子", age = 28, isMarry = true }); persons.Add(new Person { name = "大黄", age = 10, isMarry = false }); persons.Add(new Person { name = "傻蛋", age = 30, isMarry = true }); persons.Add(new Person { name = "小李子", age = 19, isMarry = false }); result = SearchPerson(delegate(Person p) { return p.isMarry == true; }, persons); foreach (Person p in result) { Console.WriteLine(p.name); } Console.ReadLine(); }
这段代码只修改了一句话,用到了一个匿名方法,方法体是判断是否结婚。但是有没有感觉有点不伦不类呢?啥玩意啊,一个语句里边里加了一个方法?fxxk啊!不能着急,都是优雅的人好吗?还记得之前说的lambda表达式吗,没错,来了,只改一句话,变了哦:
result = SearchPerson(p =>p.isMarry==true, persons);
优雅了没呢? 这远远不算优雅,为啥呢,每次我用到查找方法的时候,我都要用SearchPerson方法,我还要调用,真心烦啊,好吧,预备知识中的扩展方法还记得不?嘿嘿,来了:把SearchPerson方法写为扩展方法,这样岂不是以后所有的Ilist<Person>类型,都可以随便用了?为了优雅,把这个方法改名字,改为Where见名知意,而且通用,改写为:
public static class Helper { public delegate bool Condition(Person p); public static IList<Person> Where(this IList<Person> persons, Condition condition) { IList<Person> result = new List<Person>(); foreach (Person p in persons) { if (condition(p)) { result.Add(p); } } return result; } }
然后呢,在main方法里边就可以为所欲为的使用where方法了:
static void Main(string[] args) { IList<Person> persons = new List<Person> (); IList<Person> result = new List<Person>(); persons.Add(new Person { name = "狗剩", age = 22, isMarry = false }); persons.Add(new Person { name = "二蛋子", age = 28, isMarry = true }); persons.Add(new Person { name = "大黄", age = 10, isMarry = false }); persons.Add(new Person { name = "傻蛋", age = 30, isMarry = true }); persons.Add(new Person { name = "小李子", age = 19, isMarry = false }); result = persons.Where(p => p.isMarry == true); foreach (Person p in result) { Console.WriteLine(p.name); } Console.ReadLine(); }
咦,where?sql?linq?恩,有点像了,可where中,可没说一定要是person泛型的啊,好,再变,集合类都是继承与IEnumerable接口的,而person类型,也可以改为泛型T,这样一来所有的集合类是不是随便用where了?接着改:
public static class Helper { public delegate bool Condition<T>(T p); public static IEnumerable<T> Where<T>(this IEnumerable<T> items, Condition<T> condition) { foreach (T t in items) { if (condition(t)) { yield return t; } } } }
在main中可以这样写:
static void Main(string[] args) { IList<Person> persons = new List<Person>(); persons.Add(new Person { name = "狗剩", age = 22, isMarry = false }); persons.Add(new Person { name = "二蛋子", age = 28, isMarry = true }); persons.Add(new Person { name = "大黄", age = 10, isMarry = false }); persons.Add(new Person { name = "傻蛋", age = 30, isMarry = true }); persons.Add(new Person { name = "小李子", age = 19, isMarry = false }); var result = persons.Where(p => p.isMarry == true); foreach (var p in result) { Console.WriteLine(p.name); } Console.ReadLine(); }
这样一来,所有的继承于IEnumerable的类型,就都可以用where方法了,在这里还要记住一点,var是.net中的隐藏类型,也就是说在运行时的时候,编译器自动根据赋值语句判断var的类型,但是以下语句是错误的 var a;var类型一定要初始化,否则编译器不能判断。然后这里还有一个yield,这大概是framework 2.0开始使用的关键词,作用是返回迭代器中所有符合条件的对象。接下来可以如法炮制,写select,和groupby之类的。感谢ms,所有的这些方法,都给写好了,ms还给他起了个名字叫:LINQ。
LINQ扩展知识: 上面基本上是linq 对于object的操作,其实linq分好几块,按照大类分:Linq to sql,linq to object ,linq to xml.对于其他的两大类,在此就不一一赘述了,理解了一种即可触类旁通。
其实linq的学习,这些知识只是刚刚入门,想学好linq除了多多练习之外,一定要深刻得剖析linq背后的机制,只有这样才能理解深刻。否则做再多的练习都是机械性的重复,以后也根本不能很好驾驭linq。 好了,到此为止吧。
老规矩,所有的代码,都是上机跑过的~~