自己的Linq学习心得

时间:2022-06-30 14:00:18

 导读:     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(); 
        }

输出结果是:狗剩 二蛋子 傻蛋

 

现在相关部门说了,要跨省一些结婚的,那么我们是不是还要重写这个方法呢自己的Linq学习心得,真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);

优雅了没呢?自己的Linq学习心得 这远远不算优雅,为啥呢,每次我用到查找方法的时候,我都要用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。 好了,到此为止吧。

老规矩,所有的代码,都是上机跑过的~~