1. 概述
.net3.5中新添加给C#的LINQ查询,提供了直观便捷的数据查询方式。并且支持多种数据源的查询。
本章介绍标准的LINQ操作,如何用最优的方式使用LINQ 以及 LINQ to XML.
2. 主要内容
2.1 使LINQ可行的语言特性
① 隐式类型(Implicitly typed variables): 使用var标记,由编译器推断类型。也是强命名的。
② 对象初始化语法(Object initialization syntax):用一种简洁的语法进行对象初始化。
var people = new List<Person> { new Person { FirstName = “John”, LastName = “Doe” }, new Person { FirstName = “Jane”, LastName = “Doe” } };
③ Lambda表达式:是匿名方法的简化形式。使用 => 符号。
Func<int, int> myDelegate = delegate(int x) { return x * 2; }; Console.WriteLine(myDelegate(21)); // Displays 42 //用Lambda表达式改写 Func<int, int> myDelegate = x => x * 2; Console.WriteLine(myDelegate(21)); // Displays 42
④ 扩展方法
扩展方法可以在不继承某类型的情况下给其添加新的行为。扩展方法必须定义在静态类中,用this标记第一个参数。
public static class IntExtensions { public static int Multiply(this int x, int y) { return x * y; } } int x = 2; Console.WriteLine(x.Multiply(3)); // Displays 6
⑤ 匿名类:同时使用 对象初始化标记 和 隐式类型。
var person = new { FirstName = “John”, LastName = “Doe” }; Console.WriteLine(person.GetType().Name); // Displays “<>f__AnonymousType0`2”
2.2 使用LINQ查询
int[] data = { 1, 2, 5, 8, 11 }; var result = from d in data where d % 2 == 0 select d; foreach (int i in result) { Console.WriteLine(i); } // Displays 2 8
上述查询式语法可以被改写为方法式语法
var result = data.Where(d => d % 2 == 0);
*where方法就是 IEnumerable<T>上的扩展方法。
① 标准LINQ操作包括: All, Any, Average, Cast, Count, Distinct, GroupBy, Join, Max, Min, OrderBy, OrderByDescending,
Select, SelectMany, Skip, SkipWhile, Sum, Take, TakeWhile, ThenBy, ThenByDescending, and Where.
int[] data = { 1, 2, 5, 8, 11 }; var result = from d in data where d > 5 orderby d descending select d; Console.WriteLine(string.Join(“, “, result)); // Displays 11, 8
* 可以将多个数据源的数据合并操作
int[] data1 = { 1, 2, 5 }; int[] data2 = { 2, 4, 6}; var result = from d1 in data1 from d2 in data2 select d1 * d2; Console.WriteLine(string.Join(“, “, result)); // Displays 2, 4, 6, 4, 8, 12, 10, 20, 30
projection 和 grouping
var result = from o in orders from l in o.OrderLines group l by l.Product into p select new { Product = p.Key, Amount = p.Sum(x => x.Amount) };
使用Skip和Take实现分页
var pagedOrders = orders .Skip((pageIndex - 1) * pageSize) .Take(pageSize);
2.3 LINQ如何工作
实现自己的where方法
public static class LinqExtensions { public static IEnumerable<TSource> Where<TSource>( this IEnumerable<TSource> source, Func<TSource, bool> predicate) { foreach (TSource item in source) { if (predicate(item)) { yield return item; } } } }
2.4 LINQ to Xml
① 查询
XDocument doc = XDocument.Parse(xml); IEnumerable<string> personNames = from p in doc.Descendants(“Person”) where p.Descendants(“PhoneNumber”).Any() let name = (string)p.Attribute(“firstName”) + “ “ + (string)p.Attribute(“lastName”) orderby name select name;
② 创建
XElement root = new XElement(“Root”, new List<XElement> { new XElement(“Child1”), new XElement(“Child2”), new XElement(“Child3”) }, new XAttribute(“MyAttribute”, 42)); root.Save(“test.xml”); //Outputs: //<Root MyAttribute=”42”> // <Child1 /> // <Child2 /> // <Child3 /> //</Root>
③ 修改
XElement root = XElement.Parse(xml); XElement newTree = new XElement(“People”, from p in root.Descendants(“Person”) let name = (string)p.Attribute(“firstName”) + (string)p.Attribute(“lastName”) let contactDetails = p.Element(“ContactDetails”) select new XElement(“Person”, new XAttribute(“IsMale”, name.Contains(“John”)), p.Attributes(), new XElement(“ContactDetails”, contactDetails.Element(“EmailAddress”), contactDetails.Element(“PhoneNumber”) ?? new XElement(“PhoneNumber”, “112233455”) )));
3. 总结
① LINQ, 以一种统一的语法面向多种数据源编写查询语句。
② LINQ用到的一些语言特性包括:implicit typing, object initialization syntax, lambdas, extension methods, and anonymous types。
③ 可以使用查询式语法或者方法式语法来编写LINQ查询。
④ LINQ是延迟执行模式,声明的时候是不会实际执行查询的,第一次遍历开始时才会执行。调用ToList或者Count方法时会立即执行。
⑤ 可以使用LINQ to Xml 来查询、创建 和 修改 xml 数据。