• Linq学习笔记(转)


    开始Linq前你要知道的

      扩展方法

      顾名思义就是对现有类进行扩展的的方法,扩展方法可以在不修改现有类的情况下,为现有类增加公共的接口(不是C#中的interface)。

      扩展方法本质上是一个静态方法,不同之处在于它的第一个参数必须有this关键字声明,并且第一个参数的类型即为要扩展的类型。如

    public static double ToDouble(this string source)
    {
        double res = 0d;
        double.TryParse(source, out res);
        return res;
    }
    
    public static void SimpleExtesionMethod()
    {
        double d = "12345.54321".ToDouble();
        Console.WriteLine(d);
    }

    这里是个简单的将字符串转为double类型的扩展方法,只要引用了该方法的命名空间,则都可以直接用string类型来调用ToDouble方法。

      扩展方法是后文的基础,C#3.0中的Linq的实现都是基于扩展方法,通过对IEnumerable<T>接口(Linq to Objects)的扩展和对IQueryable<T>的扩展来实现Linq的相关功能,而Linq的相关关键字最终都是转化为对IEnumerable<T>(IQueryable<T>)的调用。

      Lambda表达式

      lambda表达式其实就是.net2.0中的匿名方法,然后再3.0中以一种更优美的姿态呈现出来。

      lambda表达式的基本语法为

      (参数列表) =>{语句块;}    或者  ( 参数列表) =>表达式

      当参数列表中只有一个参数的时候,圆括号可以省略

    Func<string, string> func = x => x + x;
    Console.WriteLine(func("a")); 

    Var:隐式类型化变量

      使用与可以由编译器推导出的变量的声明,不需要显式指定对象的类型。

    var container = new List<string> { "张三", "李四", "王五" };
    IEnumerable<string> query = from name in container
                select name;

    上例中由于定义中已经指明了对象的类型,声明中已经完全没有必要使用显示的类型定义,所以可以使用var关键字。

      对于匿名对象

    var test = new { Name = "Sth.", Type = "UnKnown" };

    由于无法用一个类型类声明匿名对象,此时可以用var是声明。

      注意var只是省下了显式声明的过程,而C#本身就是静态语言,所以var所声明的变量的类型已经确定任然是不能改变的,亦即,var并非是变体类型。

    Linq对谁适用

      linq的语法通过System.Linq下面的Enumerable类提供支持,通过观察他的签名,你就会发现他为IEnumerable<T>实现了一系列的扩展方法,也就是说,只要是实现了IEnumerable<T>的对象都可以使用Linq的语法来查询

      而对于只实现了IEnumerable接口而没有实现IEnumerable<T>的对象可以通过

    public static IEnumerable<TResult> Cast<TResult>(this IEnumerable source);

    来将IEnumerable接口转为IEnumerable<T>(例如ArrayList)。

    Linq中的关键字

      在C#3.0中,为Linq引入了一些新的关键字,他们是:

      from join where group into let orderby select

      熟悉Sql的同学看着是不是有些眼熟呢,其实在Linq中他们的涵义和在SQL中类似的,所以会很容易理解的。接下来的时间,简单介绍下这些关键字的使用。

    from

      from子句是一个Linq查询的开始,任何一个Linq语句都是以from开始,from子句指定查询的容器,和在此语句有效的局部变量(用来指定容器中的一项,from子句的效果很类似于foreach)。from子句的语法为

     from local in container

    local就是在此Linq语句中的局部变量,由于container必须为IEnumerable<T>,他的类型可以由container推导出来(即T)。上一段简单的例子:

    ar container = new List<string> { "张三", "李四", "王五" };
    var query = from name in container
                select name;
    
    foreach (string name in query)
    {
        Console.WriteLine(name);
    }

    输出:

    张三
    李四
    王五

    如果container仅仅实现IEnumerable而没有实现IEnumerable<T>,则需要显式指定局部变量的类型,或者是使用Cast转为IEnumerable<T>

    var container = new ArrayList { "张三", "李四", "王五" };
    var query = from name in container.Cast<string>()
                select name;
    //或者
    var query1 = from string name in container
                 select name;

    select

      对查询的结果进行投影,在子句中指定要选择的列,如上例。有的时候,我们只需要投影某一列,我们可以这样

    private static void TestSelectSingleProperty()
    {
        var persons = GetPersons();
    
        var query = from p in persons
                    select p.Name;
    
        foreach (var item in query)
        {
            Console.WriteLine(item);
        }
    }

    我们还可以指定要投影的列的集合,这个时候我们要用到匿名类型

    var query = from p in persons
                select new { p.ID, p.Name };
    
    foreach (var item in query)
    {
        Console.WriteLine("No:{0},Name:{1}",item.ID,item.Name);
    }

    query中的每一项都时候一个拥有ID属性和Name属性的对象,当然有的时候实体的属性名不是我们想要的,或者是通过对属性计算得来的,那么我们可以显式指定属性名,就像下面这样:

    var query = from p in persons
                select new
                {
                    UserID = p.ID,
                    FriendName = p.Gender == "" ? "Mr" : "Ms" + p.Name
                };
    
    foreach (var item in query)
    {
        Console.WriteLine("No:{0},Friendly Name:{1}", item.UserID, item.FriendName);
    }

    where

      对容器内的数据进行筛选。

    var query = from p in persons
                where p.DepartmentID == 1
                select p.Name;

    join

      类似SQL里的join,Linq中的join子句用于将两个容器的数据以某种关系进行关联。

    var departments = GetDepartments();
    var persons = GetPersons();
    
    var query = from d in departments
                join p in persons on d.ID equals p.DepartmentID
                select new { d, p };

    值得注意的是join子句只能使用equals或者是not equal而不能用其他运算符(==都不行)而equals运算符左边必须联接的左部,右边为右部,不能调换的,否则编译不能通过。

    into

      into子句用于将join或者是group子句的结果进一步持续化,包装成为一个

      System.Linq.IGrouping<TKey, TElement>对象,

      而且IGrouping继承自IEnumerable<TElement>,可以看出,IGrouping接口提供分组的键和,该键下所包含的集合。例子见group

    group

      对结果按照指定的条件进行分组

    var container = new List<string> { "ZhangSan", "LiSi", "Wangwu", "ZhaoLiu", "Deng" };
    var query = from name in container
                group name by name.Length into g
                select new { g.Key, Values = g };

    例子演示了通过姓名的长度对一个姓名列表进行分组,并将分组的结果保持到局部变量g中,可以通过下面的代码将query的结果输出

    foreach (var group in query)
    {
        Console.WriteLine("{0}:", group.Key);
        foreach (var item in group.Values)
        {
            Console.WriteLine(item);
        }
    } 

    let

      let子句用于在查询中添加一个新的局部变量,使其在后面的查询中可见

    var query = from p in persons
                let friendlyName = p.Gender == "" ? "Mr" : "Ms" + p.Name
                select new
                {
                    UserID = p.ID,
                    FriendName = friendlyName
                };
    
    foreach (var item in query)
    {
        Console.WriteLine("No:{0},Friendly Name:{1}", item.UserID, item.FriendName);
    }

    在IEnumerable<T>上的其他扩展

      Take Skip

      用于选取前XX个或者和跳过前XX个,如选择第11到20个则可以

    query.Skip(10).Take(10);

    OrderBy OrderByDescending

      排序而已

    query.OrderBy(c => c.Length);

    Distinct Union Intersect Except 这些单词都见过吧,分别就是取不重复,并集,交集,差集(这个貌似看看参数就明白了)

      其他扩展都在Enumerable类下面了。

      Linq的延迟加载特性

      Linq查询的执行结果是IEnumerable<T>类型,而对IEnumerable<T>,在内部,C#通过yield关键字实现迭代器达到延迟加载的目的。从而使Linq查询只是在需要的时候才会被执行。

      但是,某一些扩展方法在执行时会试图遍历整个容器,从而使延迟加载无效,如排序,聚合函数(Count,Sum,Average等。)

    static IEnumerable<int> InfinityInts()
    {
        int count = 0;
        while (true)
            yield return count++;
    }
    
    public static void LazyLoad()
    {
        var query = from i in InfinityInts()
                    select i;
        foreach (var i in query.Take(20))
        {
            Console.WriteLine(i);
        }
    }
    
    public static void CantDoLazyLoad()
    {
        var query = from i in InfinityInts()
                    select i;
        foreach (var i in query.OrderBy(i => i).Take(20))
        {
            Console.WriteLine(i);
        }
    }

    这里有个简单的例子来证明,当使用Take时候,Linq语句能正常的执行,而当我们再Linq上使用一个Order By之后,程序就卡死了,当然,这是理所应当的,在失去延迟加载的特性之后,试图对一个无穷序列排序的结果一定是outOfMemory。

  • 相关阅读:
    Atitit sumdoc everything index tech and index log 目录 1. 使用的tech 1 1.1. Atitit 日志记录的三个trace跟踪等级文件夹级
    Atitit nlp用到的技术与常见类库 目录 1. 常用的技术 1 1.1. 语言处理基础技术 分词 相似度等 1 1.2. 新闻摘要 2 1.3. 情感倾向分析 2 1.4. 文章标签 2 1.
    Atitit 资源类型的分类法规范MIME类型类型 目录 1.1. 一个MIME类型至少包括两个部分:一个类型(type)和一个子类型(subtype)。 1 1.2. 命名格式MIME类型包括一个
    Atitit 六种知识表示法 目录 1. 知识的静态描述和动态描述 1 1.状态空间表示 以状态和运算符(operator) 1 2.问题归约表示(函数式?? 1 (1)一个初始问题描述; 2 (2)
    微信小程序登录流程总结 目录 1.1. 前端调用wx.login 。。给后端传递一个code 1 1.2. 开发者需要在开发者服务器后台调用 auth.code2Session,使用 code 换取
    Atititi 计算机系 教材 目录 1. 硬件类 2 1.1. 《微机系统与接口技术》 2 1.2. 《计算机组成与系统结构(第2版)》 2 2. Atitit 操作系统原理 操作系统原理(cpu
    Atitit 声音和音乐检索 多媒体信息检索 信息检索 目录 1.1. 14.4.5 音频基础知识 1 1.2. 多媒体信息检索的方法主要有哪些?其原理是什么? 1 1.3. 基于文本的检索和基于
    Atitit 信息检索 v3 t55.docx Atitit 现代信息检索 目录 1.1. 信息检索(索引 索引 结构化文本 1 1.2. Atitit 重要章节 1 1.3. 息检索建模 1 1.
    Atiitt 程序语言vm与rt 虚拟机与运行时 目录 1. 运行时 虚拟机的一种,一般指进程级别的虚拟机。 1 1.1. 线程模型 1 1.2. 堆栈机vs 寄存器 1 1.3. 存储模型 2 1
    Atiitt 图像处理的常见功能业务用途与类库与功能实现 目录 1. 常见业务场景 3 1.1. 缩略图 蒙版遮罩挖空 3 1.2. 区域裁剪,水印,旋转 3 1.3. 判断图像大小分辨率要求
  • 原文地址:https://www.cnblogs.com/alsf/p/5993432.html
Copyright © 2020-2023  润新知