LINQ

19.1 LINQ provider
LINQ数据源能够是SQL数据库、数组、XML文档,每一种数据源类型,都有根据该数据源实现查询的代码模块,叫作LINQ provider。有LINQ to objects、LINQ to xml、LINQ to SQL、LINQ to Datasets、LINQ to Entities。
//一个简单的LINQ例子
             int[] nums = { 2,13,4,15};//数据源
             IEnumerable<int> lowNums = from n in nums where n < 10 select n;//定义并存储查询返回一个枚举类
             foreach (var x in lowNums)
             {
                 Console.WriteLine("{0},", x);
             }
19.2 匿名类型
匿名类型的对象建立表达式:
                 
匿名类型没有名字,必须使用var关键字来做为变量类型
            //匿名类型
             var student = new { Name = "Mary Jones", Age = 19, Major = "History" };//必须使用var {}内为匿名对象初始化语句
             Console.WriteLine("{0},{1},{2}",student.Name,student.Age,student.Major);
 
             string major = "History";
             var student1 = new { Other.name, Age = 19, major };//分别是赋值形式成员访问表达式形式和标识符形式
             Console.WriteLine("{0},{1},{2}", student.Name, student.Age, student.Major);
19.2 方法语法和查询表达式
在写LINQ查询的实收可使用两种形式的语法:查询和方法
//方法语法与查询语法
             int[] nums1 = { 2, 5, 26, 62, 45, 77, 74 };
             var numsQuery = from n in nums1 where n < 20 select n;//查询语法
             var numsMethod = nums1.Where(x => x < 20);//方法语法
             int numsCount=(from n in nums1 where n<20 select n).Count();//两种形式的组合
19.3 查询变量 
查询变量就是LINQ查询返回的值,有枚举类的IEnumerable<T>和标量int。
若是查询表达式返回枚举,查询一直处处理枚举时才执行,而若是返回标量,则当即执行,并把结果保存在查询变量中。
19.4 查询表达式的结构
顺序:from……select……这两部分是必需的;select子句在最后面
from子句 
join子句 
var query=from s in a  join c in b on a.ID= equals b.ID
let子句
where子句
例子
             var groupA=new[]{3,4,5,6};
             var groupB=new[]{6,7,8,9};
             var someInts = fromint a in groupA//必需的第一个from子句
                            fromint b in groupB//第二个from子句
                            let sum = a + b//let子句在新的变量中保存结果
                            where sum >= 11 //where条件1
                            where a == 4//where条件2
                            selectnew { a, b, sum };
orderby子句
查询中的匿名类型
    var students = new[]{
            new {LName="Jones",FName="Mary",Age=19,Major="History"},
            new {LName="Smith",FName="Bob",Age=20,Major="CompSci"},
            new {LName="Fleming",FName="Carol",Age=21,Major="Math"}
            };//定义一个匿名类型的对象数组每一个匿名类型的对应属性名字必需相同
            var query = from s in students selectnew { s.LName, s.FName, s.Major };
            //在select子句中建立一个匿名类型
group by子句
            var query = from s in students
                        group s by s.Major;
            foreach (var s in query)
            {
                Console.WriteLine("{0}",s.Key);//分组键
                foreach(var t in s)
                { Console.WriteLine("  {0},{1}", t.LName, t.FName); }
            }
into子句
           var groupA=new[]{3,4,5,6};
           var groupB=new[]{6,7,8,9}; 
           var someInts1 = fromint a in groupA
                          join b in groupB on a equals b
                          into groupAB//将前面的查询结果插入到新的groupAB中
                          from c in groupAB
                          select c;
19.5 标准查询运算符
标准运算符就是一系列的API方法,可以查询任何.NET数组和集合。
对于标准查询运算符,被查询的集合对象叫作序列。
序列:它必须实现IEnumerable<T>接口,包括List<>、Dictionary<>、Stack<>、Array等。
标准查询运算符:Where Select SelectMane Take Skip TakeWhile SkipWhile Join GroupJoin Concat ……Count Sum Contains All Any Max Last First Range FirstOrDefalut…
19.6.1标准查询运算符的签名
System.Linq.Enumerable类声明了标准查询运算符方法,这些方法不单单是一些方法,它们是扩展了IEnumerable<T>泛型类的扩展方法,IEnumerable<T>就是实现了接口IEnumerable的全部类类型。例子以下:
  int[] array = newint[] { 3,4,5,6,7,9};
            var c1 = Enumerable.Count(array);
            var f1 = Enumerable.First(array);//方法语法
            var c2 = array.Count();
           //扩展语法 int数组继承自Array类 该类实现了IENumerable<T>接口 因此能够是被扩展对象
            var f2 = array.First();
Count方法签名 
publicstaticint Count<TSource>(thisIEnumerable<TSource> source);
扩展方法是公共的静态方法,尽管定义在一个类中,但目的是为了另外一个类(第一个形参)增长功能,因此叫扩展方法。


19.6.2 将委托做为参数
委托能够理解为:一个包含特殊签名和返回类型的方法或方法列表的对象,当委托被调用时,包含它的方法会被依次调用。
Count方法还有一种重载形式:
public static int Count<TSource>(thisIEnumerable<TSource> source, Func<TSource, bool> predicate);
其中第二个参数就是泛型委托参数。Func<TSource, bool> predicate:接受单个T类型的参数做为方法参数而且返回一个bool类型的值。这种委托成为谓词。
LINQ预约义委托:Func委托和Action委托,各有17个成员。咱们用做实参的委托对象必须是这些类型之一。Fuc委托有返回类型,而Action没有。
Func委托:

委托的几种定义方式:方法、匿名方法、Lambda表达式
Func<string, string, string> func1 = Hello;
 // Func委托,是微软为咱们预约义的经常使用委托前面的T参数都表示的是方法的输入参数最后一个TResult参数是方法返回结果参数
Func<string, string, string> func2 = delegate(string a, string b) { return"func2" + Environment.NewLine + a + " " + b; };
//匿名方法  delegate+(参数列表)+{方法体}
Func<string, string, string> func3 = (a, b) => { return"func3" + Environment.NewLine + a + " " + b; };
//Lambda表达式 (,,) => { } 左边为参数列表右边为表达式体
匿名对象
var person = new { name = "yuanxiaoxia", age = 27 };//定义了一个匿名对象person,有两个属性string和int类型

例子:--使用委托对象来调用标准查询运算符方法Count
   static bool IsOdd(int x)
   {
      return x % 2 == 1;
   }
   static void Main()
   {
        int[] array = new int[] { 3, 4, 5, 6, 7, 9 };
        Func<int, bool> myDel = newFunc<int, bool>(IsOdd);
        var countOdd = array.Count(myDel);
        var countOdd1 = Enumerable.Count(array,myDel);//两种调用委托的方式
    }

燕青解答:
Count是一个扩展方法,是IEnumerable<TSourse>泛型的一个扩展方法,它接受一个委托类型的参数:Func<Tsource,bool>
Lambda表达式就是一个方法的简写
委托是一个数据类型,实例化一个委托对象时 把具备委托定义的方法签名的方法 作为参数传入,因此这个方法能够是任何形式,能够传入一个Lambda表达式也能够是一个普通的方法,或是匿名方法
还可使用更简洁的方法,Lambda表达式来做为参数
例子:--使用Lambda表达式来调用标准查询运算符方法Count
var countOdd2 = array.Count(x => x % 2 == 1);
也可使用匿名方法
例子:--使用匿名方法来调用标准查询运算符方法Count
Func<int, bool> Del = delegate(int x) { return x % 2 == 1; };//匿名方法:delegate+(参数列表)+{方法体}
var countOdd3 = array.Count(Del);
19.6 LINQ to XML
LINQ与xml能够经过两种方式配合使用:第一种是xml操做API;第二种是使用LINQ查询工具
19.6.1 API:

1、建立、保存、加载和显示xml文档
XDocument employees1 = newXDocument(newXElement("Employees",newXElement("Name","Bob"),newXElement("NAme","Sally")));
employees1.Save("EmployeesFile.xml");
XDocument employees2 = XDocument.Load("EmployeesFile.xml");
Console.WriteLine(employees2);

2、获取xml树的值
            XDocument employeeDoc = newXDocument(
                                      newXElement("Employees", newXElement("Employee", newXElement("Name", "Bob"), newXElement("PhoneNum", "13468654108")),
                                                                newXElement("Employee",newXElement("Name","Sally"),newXElement("PhoneNum","13468654102"),newXElement("PhoneNum","13468654101")))); 
            XElement root = employeeDoc.Element("Employees");
            IEnumerable<XElement> employees=root.Elements();
            foreach (XElement emp in employees)
            {
                XElement empNameNode = emp.Element("Name");
                Console.WriteLine(empNameNode.Value);
                IEnumerable<XElement> empPhones = emp.Elements("PhoneNum");
                foreach (XElement empPhone in empPhones)
                {
                    Console.WriteLine("   {0}", empPhone.Value);
                }
            }



3、增长节点以及操做xml XDocument xd = newXDocument( newXElement("root", newXElement("first")) ); Console.WriteLine("Original tree"); Console.WriteLine(xd); XElement rt = xd.Element("root"); rt.Add(newXElement("Second")); rt.Add(newXElement("Third"), newXComment("Important Comment"), newXElement("Fourth")); Console.WriteLine("Modified tree"); Console.WriteLine(xd);
4、xml特性(XAttribute) XDocument xd = newXDocument( newXElement("root", newXAttribute("color","red"),//特性构造函数,接受两个参数name和value newXAttribute("size","large"), newXElement("first"), newXElement("Second")) ); //建立xml树 Console.WriteLine(xd); XElement rt = xd.Element("root");//获取元素 XAttribute color = rt.Attribute("color");//获取节点特性 Console.WriteLine("color is {0}",color.Value);//读取特性的value值 rt.Attribute("color").Remove();//移除节点的一个color特性 rt.SetAttributeValue("size", null);//size特性赋值为空,其实也就是移除节点的一个size特性 rt.SetAttributeValue("size", "medium");//改变特性值 rt.SetAttributeValue("width", "narrow");//添加特性width Console.WriteLine(xd); 5、节点的其余类型 (1)XComment 注释 <!--内容--> (2)XDeclaration xml声明 (3)XProcessingInstruction XDocument xd = newXDocument( newXDeclaration("1.0", "utf-8", "yes"), newXDocument("This is a comment"), newXProcessingInstruction("xml-stylesheet", @"href=""stories.css"" type=""test/css"""), newXElement("root", newXElement("first"), newXElement("Second") ) ); 结果: 19.6.2 LINQ查询 使用LINQ查询来获得节点的子集 XDocument xd = newXDocument( newXElement("MyElements", newXElement("first", newXAttribute("color", "red"), newXAttribute("size", "small")), newXElement("second", newXAttribute("color", "red"), newXAttribute("size", "medium")), newXElement("third", newXAttribute("color", "blue"), newXAttribute("size", "large"))) ); Console.WriteLine(xd); xd.Save("SimpleSample.xml"); xd = XDocument.Load("SimpleSample.xml");//加载文档 XElement rt = xd.Element("MyElements");//获取根元素 var xyz = from e in rt.Elements() where e.Name.ToString().Length == 5 select e;//选择名称包含5个字符的元素 foreach (XElement x in xyz) Console.WriteLine(x.Name.ToString());//所选的元素 Console.WriteLine(); foreach (XElement x in xyz) Console.WriteLine("Name:{0},color:{1},size:{2}",x.Name,x.Attribute("color").Value,x.Attribute("size").Value); var xyz1 = from e in rt.Elements() selectnew { e.Name,color=e.Attribute("color")};//建立匿名类型 foreach (var x in xyz1) Console.WriteLine(x); 结果: