zoukankan      html  css  js  c++  java
  • 组内Linq培训记录

    注: 由于该培训是在组内分享,先写成了Word,而word中的代码都以截图方式呈现了,而在博客园不能很方便的粘贴截图进来,所以我用插入代码的方式加进来,如果文中说“如下图”或“如下图代码”,那么就直接看下面的代码块就可以了。

    Linq基本用法

    1. 1.       前言:

    要说Linq,要先做一些相关内容的铺垫。请稍安勿躁,下面马上开始。

     

    1. 2.       集合和IEnumerable

    集合包括数组、字典、列表等类型,这些类型都实现了IEnumerable(可枚举)接口。

    1. 3.       隐式类型和var关键字

    从.net 3.0开始,引入了隐式类型var,隐式类型的本地变量是强类型变量(就好像您已经声明该类型一样),但由编译器确定类型。 下面的两个声明在功能上是等效的:

    double num = 1.0;

    var num = 1.0;

    由于var关键字声明的变量的类型是由编译器决定的,编译器判断的方法是在声明时,根据变量被赋值的类型来决定变量类型, 所以要求在声明时就进行赋值,否则编译器无法确定变量的类型, 所以如下写法是无效的:

    var num;

             日常开发中,可以都用var来声明变量,据说这样性能更优。

    1. 4.       扩展方法

    扩展方法使您能够向现有类型“添加”方法,而无需创建新的派生类型、重新编译或以其他方式修改原始类型。 扩展方法是一种特殊的静态方法,但可以像扩展类型上的实例方法一样进行调用。 

    a)         如何实现扩展方法

    实现一个空的Cat类,并在该类外进行扩展,扩展一个Eat方法。扩展类CatExtend可以随便命名,但一定要是静态(Static)类,而且扩展的方法需要是静态方法,扩展方法的第一个参数的类型为(this关键字加要扩展的类)

     1 public class Cat 
     2     {
     3     }
     4 
     5     public static class CatExtend
     6     {
     7         public static void Eat(this Animal c, string foodName)
     8         {
     9             Console.WriteLine("Animal eat {0}", foodName);
    10         }
    11     }
    View Code

    调用该方法的代码为:

    1 var myCat = new Cat();
    2 myCat.Eat('fish');
    3 
    4 // 输出 Cat eat fish
    View Code

             我们也可以扩展现有的类型,如Int32:

    1 public static class Int32Extend
    2 {
    3     public static int Pow(this Int32 i, int power)
    4     {
    5 
    6         var pow = Math.Pow(i, power);
    7         int result = Int32.TryParse(pow.ToString(), out result) ? result : 0;    
    8     }   
    9 }
    View Code

            

    1. 5.       委托和Lambda表达式

    在说Lambda之前,需要先简单提一下委托

    a)         委托:

    委托是一种定义方法签名的类型,可以与具有兼容签名的任何方法关联。您可以通过委托调用方法。委托用于将方法作为参数传递给其他方法。事件处理程序就是通过委托调用的方法。你可以用委托创建一个自定义方法,并将这个方法作为参数传递给其他方法。 这类似于JS中的回调函数。

    b)         Lambda表达式:

    “Lambda 表达式”是一个匿名函数,它可以包含表达式和语句,并且可用于创建委托或表达式目录树类型。

    所有 Lambda 表达式都使用 Lambda 运算符 =>,该运算符读为“goes to”。该 Lambda 运算符的左边是输入参数(如果有),右边包含表达式或语句块。Lambda 表达式 x => x * x 读作“x goes to x times x”。可以将此表达式分配给委托类型,如下所示:

    delegate int del(int i);
    del myDelegate = x => x * x;
    int j = myDelegate(5); //j = 25
    其中的 x => x * x;  就是Lambda表达式。
     
    Lambda表达式的标准形式为:
                          (input parameters) => expression
     
    Input parameters为传入参数,当有多个时,用逗号分隔,可以不指定类型,编译器会自动判断,但也有些情况编译器无法自动判断,这是可以给参数指定类型。仅当传入参数个数为一个时,左边的括号可以忽略,否则必须写括号,如:
                          (x, y)=> x * y;
                          () => return 0;   // 当无传入参数时,也要写上括号。
     
    Expression为该匿名函数的处理逻辑, 当该函数是直接通过一个语句返回结果,可以像上面的代码那么写,但如果需要一些逻辑处理语句,那么,可以像下面这么写:

    (x, y) => { var i = x + 1; return i * y; }

    具体可查看http://msdn.microsoft.com/zh-cn/library/bb397687(v=vs.90).aspx

    c)         Func<>和Action<>

    Func和Action都是函数类型,即上述的所有Lambda表达式都可赋值给相应的函数类型,以便之后调用。如:

    1 Func<int, int> fn1 = (x,y) => { var i = x+1; return i * y; };
    2 Action<string> ac1 = (name) => {Console.WriteLine("Hello {0}.", name); };
    View Code

    Func和Action的区别在于,Func有一个返回值,而Action没有返回值。

    根据上述代码,可看出Func和Action后的尖括号中,有逗号分隔的各种类型,这些类型表示的意思为:

    l  Func: 最后一个类型为返回值的类型,之前的所有类型都是传入参数的类型,当只有一个类型时,为返回值的类型。

    l  Action:全部类型都是传入参数的类型,也可以用不带尖括号的形式来声明,此时没传入参数。

    Func和Action都能最多接受16个传入参数。

    1. 6.       Linq表达式

    Linq表达式接近于SQL的语法,书写起来比扩展方法具有更高的可读性,基本上熟悉SQL语法的程序员一看到Linq表达式,即使没用过,也能大概猜出语句的含义。这也是Linq的优势之一。

    当引用了System.Linq命名空间后,就可以对所有可枚举类型使用Linq的方法和特性。包括Array,List,DataTable,各类型数组的对象等等。其中对DataTable等对象使用时,需要用AsEnumerable方法先转换成可枚举类型。

    比较简单的Linq表达式:

    1 int[] numbers = new int[7] { 0, 1, 2, 3, 4, 5, 6 };
    2 var numQuery = 
    3     from num in numbers
    4     where ( num%2 ) == 0
    5     select num;
    6 
    7 // return 0,2,4,6
    View Code

    其中numbers是数据源。一般linq的查询结果的类型都用var。

    a)         和扩展方法的关系

    Linq表达式在编译器中编译后,都会先变成扩展方法的样子,即上述例子在编译后会先变成:

    Var numQuery = numbers.Where(num=>num%2==2).Select(num=> num);

    b)         常用关键字及用法

    以下大多数的关键字作用和SQL中的关键字或方法一一对应,作用一样。

                             i.              From、Select、Where

    Linq表达式都需要用到From关键字。

    var q = from num in numbers select num;

    其中的num是对numbers集合中的每个元素自定义的别名。

    1  var q = from i in intArray
    2             where i >100
    3             select i;
    View Code

                           ii.              Count、Max、Min、Average、Sum、First

    1 q=  from i in intArray
    2        select i;
    3 
    4 Console.WriteLine("There are {0} numbers in intArray ", q.Count());
    5 Console.WriteLine("The max number is : {0} ", q.Max());
    6 Console.WriteLine("The min number is : {0} ", q.Min());
    7 Console.WriteLine("The average number is : {0} ", q.Average());
    8 Console.WriteLine("The sum of all numbers is : {0} ", q.Sum());
    9 Console.WriteLine("The first number is : {0} ", q.First());
    View Code

                          iii.              Concat、Union、Distinct

    Concat为直接拼接2个同类型数组,并返回。

    Union为拼接拼接2个同类型数组,并过滤掉重复项,并返回结果。

    Distinct为过滤一个数组中的重复项并返回结果。

    示例,有如下数据源:

    1 var intArr1 = new int[] { 1, 2, 3 };
    2 var intArr2 = new int[] { 1, 2, 4 };
    3 var intArr3 = intArr1.Concat(intArr2);
    4 var intArr4 = intArr1.Union(intArr2);
    5 var intArr5 = intArr3.Distinct();
    View Code

    这么输出的话,结果如下:

     1 foreach(var i in intArr3)
     2 {
     3      Console.Write("{0},", i);   
     4 }
     5 
     6 foreach(var i in intArr4)
     7 {
     8      Console.Write("{0},", i);   
     9 }
    10 
    11 foreach(var i in intArr5)
    12 {
    13      Console.Write("{0},", i);   
    14 }
    15 
    16 
    17 // intArr3:  1,2,3,1,2,4
    18 // intArr4:  1,2,3,4
    19 // intArr5:  1,2,3,4
    View Code

                          iv.              Group、Group Join

    Group的作用和SQL中的GROUP BY一样,GROUP JOIN和SQL中的JOIN一样。

    示例: 假如有如下数据源:

     1 Person[] persons = new Person[]{
     2     new Person("Peter", sex.Male),
     3     new Person("Tom", sex.Male),
     4     new Person("Sue", sex.Female),
     5     new Person("Ken", sex.Male),
     6     new Person("Linda", sex.Female)
     7 };
     8 
     9 Sport[] sports = new Sport[]{
    10     new Sport(sex.Male, "Swim"),
    11     new Sport(sex.Male, "Tennis"),
    12     new Sport(sex.Female, "Draw")
    13 };
    View Code

    现在要按性别对persons数组进行group的话,可以这么写:

    1 var personQuery = from p in persons
    2                             group p by p.sex into g
    3                             select new { Sex = g.Key, Persons = g};
    View Code

    这里personQuery会得到两个集合,一个是性别为男的Person集合,一个是性别为女的Person集合。 Select new中的Sex,是性别, Persons是该性别的对象集合。

    如果这样输出:

    1 foreach(var g in personQuery)
    2 {
    3     Console.WriteLine("{0} are:", g.Sex);
    4     foreach(Person pp in g.Persons)
    5     {
    6         Console.Write("{0},", pp.name);
    7     }
    8     Console.WriteLine();
    9 }
    View Code

    可以得到以下结果:

    1 /*
    2 Male are:
    3 Peter,Tom,Ken
    4 Female are:
    5 Sue,Linda
    6 */
    View Code

                           v.              OrderBy、ThenBy

    Order by作用和SQL中一样,可指定升序和降序,linq表达式的orderby支持多字段排序。如下:

     1 var orderByQ = from p in persons
     2                         order by p.sex descending, p.name descending
     3                         select p;
     4 
     5 Console.WriteLine("The person after order by sex and name");
     6 foreach( var p in orderByQ)
     7 {
     8     Console.Wirte("{0}," p.name);
     9 }
    10 Console.WirteLine();
    View Code

    输出为:

    1 /*
    2 The person after order by sex and name
    3 Sue,Linda,Tom,Peter,Ken,
    4 
    5 */
    View Code

     注:这里之所以Female会排在Male之前,因为性别是枚举类型,这里性别的排序不是根据Female和Male的拼写进行排序,而是根据其对应的枚举值进行排序。 Male的枚举值是1,Female是2,所以降序时,Female排在Male之前。

    ThenBy主要用在扩展方法,上述查询如果要用扩展方法书写,应该这么写:

    var orderByQ = persons.OrderByDescending(p => p.sex).ThenByDescending(p => p.name);

    如果要多字段排序,要用ThenBy,否则只会按照最后一个OrderBy进行排序。

    扩展方法中,有OrderBy、OrderByDescending、ThenBy、ThenByDescending,分别对应了升序和降序。

                          vi.              ToArray、ToList

    这两个都属于扩展方法,可以将Linq查询结果转换成对应的类型或泛型。用起来非常简单,用上述的orderByQ的查询结果来转换,

    1 Person[] personArr = orderByQ.ToArray();
    2 List<Person> personList = orderByQ.ToList();
    View Code
  • 相关阅读:
    对进程空间的认识
    自己实现智能指针
    实现一个string类
    常见问题总结
    pong game using ncurses
    知识梳理
    经典算法回顾
    自己实现more命令
    表的垂直拆分和水平拆分-zz
    MySQL索引原理及慢查询优化-zz
  • 原文地址:https://www.cnblogs.com/bee0060/p/3467979.html
Copyright © 2011-2022 走看看