关于LINQ的文章,网上有很多,所以这篇文章我主要是总结下我自己的学习心得。

首先需要先了解的相关技术

1.隐式类型、匿名类型、对象初始化器

1)隐式类型,使用var关键字创建,C#编译器会根据用于初始化局部变量的初始值推断出变量的数据类型。(不过我个人认为,能用具体类型的地方尽量不要用var关键字,因为这样会让你遗忘“被封装类库”方法的返回值类型--有损可读性)

隐式类型使用限制:

a) 隐式类型只能应用于方法或者属性内局部变量的声明,不能使用var来定义返回值、参数的类型或类型的数据成员。

b)使用var进行声明的局部变量必须赋初始值,并且不能以null作为初始值。

2) 匿名类型,只是一个继承了Object的、没有名称的类。C#编译器会在编译时自动生成名称唯一的类。

3) 对象初始化器,提供一种非常简洁的方式来创建对象和为对象的属性赋值。(相关还有“集合初始化器”)

由于C#强类型语言,即我们在声明变量时必须指定变量的具体类型。所以在创建匿名对象时,需要结合隐式类型、匿名类型、对象初始化器一起创建匿名对象。(避免类型转换)

示例:

var person = new { name = “heyuquan” , age = 24 }

由于C#强类型语言,即我们在声明变量时必须指定变量的具体类型。所以在创建匿名对象时,需要结合隐式类型、匿名类型、对象初始化器一起创建匿名对象。(避免类型转换)

2.Lambda表达式,Func委托

1)Lambda表达式只是用更简单的方式来书写匿名方法,从而彻底简化.NET委托类型的使用。

Lambda表达式在C#中的写法是“arg-list => expr-body”,“=>”符号左边为表达式的参数列表,右边则是表达式体(body)。参数列表可以包含0到多个参数,参数之间使用逗号分割。

2)Func委托

Func委托,是微软为我们预定义的常用委托,封装一个具有:零个或多个指定类型的输入参数并返回一个指定类型的结果值的方法。

示例:

static void Main(string[] args)
{
// 委托函数
Func<string, string, string> func1 = Hello;
// 匿名方法
Func<string, string, string> func2 =
delegate(string a, string b)
{
return "欢迎光临我的博客" + Environment.NewLine + a + " " + b;
};
// Lambda表达式
Func<string, string, string> func3 =
(a, b) => { return "欢迎光临我的博客" + Environment.NewLine + a + " " + b; };
// 调用Func委托
string helloStr = func2("滴答的雨", @"http://www.cnblogs.com/heyuquan/");
Console.WriteLine(helloStr);
} static string Hello(string a, string b)
{
return "欢迎光临我的博客" + Environment.NewLine + a + " " + b;
}

3.扩展方法

1)扩展方法声明在静态类中,定义为一个静态方法,其第一个参数需要使用this关键字标识,指示它所扩展的类型。

2)扩展方法可以将方法写入最初没有提供该方法的类中。还可以把方法添加到实现某个接口的任何类中,这样多个类就可以使用相同的实现代码。(LINQ中,System.Linq.Queryable.cs和System.Linq.Enumerable.cs 正是对接口添加扩展方法)

3)扩展方法虽定义为一个静态方法,但其调用时不必提供定义静态方法的类名,只需引入对应的命名空间,访问方式同实例方法。

4)扩展方法不能访问它所扩展的类型的私有成员。

示例:

public static IEnumerable<TSource> MyWhere<TSource>(
this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
foreach (TSource item in source)
{
if (predicate(item))
yield return item;
}
}

4.Yield迭代器,延迟计算

1)Yield迭代器

在上面定义的MyWhere扩展方法中,我们使用了yield迭代器。使我们不必“显示”实现IEnumerable或IEnumerator接口。只需要简单的使用yield 关键字,由 JIT 编译器帮我们编译成实现 IEnumerable或IEnumerator接口的对象(即:本质还是传统遍历,只是写法上非常简洁),就能使用foreach进行遍历。

2)延迟计算(Lazy evaluation)

a)定义:来源自函数式编程,在函数式编程里,将函数作为参数来传递,传递过程中不会执行函数内部耗时的计算,直到需要这个计算结果的时候才调用,这样就可以因为避免一些不必要的计算而改进性能。

b)Yield迭代器的延迟计算原理:JIT 编译器会帮助我们将迭代主体编译到IEnumerator.MoveNext()方法中。从上图foreach的执行流程来看,迭代主体是在每次遍历执行到 in 的时候才会调用MoveNext(),所以其迭代器耗时的指令是延迟计算的。

c)LINQ查询的延迟计算原理:通过给LINQ扩展方法传递方法委托,作为yield迭代器的主体,让遍历执行到MoveNext()时才执行耗时的指令。

5.表达式树

表达式树:表达式树允许在运行期间建立对数据源的查询,因为表达式树存储在程序集中。(后续会有详细介绍)

Language Integrated Query(LINQ,语言集成查询)

从这幅图中,我们可以知道LINQ包括五个部分:LINQ to Objects、LINQ to XML、LINQ to SQL、LINQ to DataSet、LINQ to Entities。

目前,还可以下载其他第三方提供程序,例如LINQ to JSON、LINQ to MySQL、LINQ to Amazon、LINQ to Flickr和LINQ to SharePoint。无论使用什么数据源,都可以通过LINQ使用相同的API进行操作。

1.怎样区分LINQ操作时,使用的是哪个LINQ提供程序?

LINQ提供程序的实现方案是:根据命名空间和第一个参数的类型来选择的。实现扩展方法的类的命名空间必须是打开的,否则扩展类就不在作用域内。Eg:在LINQ to Objects中定义的 Where() 方法参数和在 LINQ to Entities中定义的 Where() 方法实现是不同。

// LINQ to Objects:
public static class Enumerable
{
public static IEnumerable<TSource> Where<TSource>(
this IEnumerable<TSource> source, Func<TSource, bool> predicate);
} // LINQ to Entities
public static class Queryable
{
public static IQueryable<TSource> Where<TSource>(
this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate); }

2.LINQ查询提供几种操作语法?

LINQ查询时有两种语法可供选择:查询表达式(Query Expression)和方法语法(Fluent Syntax)。

.NET公共语言运行库(CLR)并不具有查询表达式的概念。所以,编译器会在程序编译时把查询表达式转换为方法语法,即对扩展方法的调用。所以使用方法语法会让我们更加接近和了解LINQ的实现和本质,并且一些查询只能表示为方法调用。但另一方面,查询表达式通常会比较简单和易读。不管怎样,这两种语法是互相补充和兼容的,我们可以在一个查询中混合使用查询表达式和方法语法。

以下扩展方法存在对应的查询表达式关键字:Where、Select、SelectMany、OrderBy、ThenBy、OrderByDescending、ThenByDescending、GroupBy、Join、GroupJoin。

LINQ查询表达式

书写模版如下:

C#进阶之路(五):Linq初识的更多相关文章

  1. 【SSH进阶之路】Hibernate映射——一对一单向关联映射(五)

    [SSH进阶之路]Hibernate基本原理(一) ,小编介绍了Hibernate的基本原理以及它的核心,採用对象化的思维操作关系型数据库. [SSH进阶之路]Hibernate搭建开发环境+简单实例 ...

  2. C#进阶之路(六):表达式进行类的赋值

    好久没更新这个系列了,最近看.NET CORE源码的时候,发现他的依赖注入模块的很多地方用了表达式拼接实现的.比如如下代码 private Expression<Func<ServiceP ...

  3. python之路:模块初识

    python王者开发之路:模块初识 模块初识我现在讲的确有点早.不过没关系,后面我会详细说模块. 模块,也就是库,是python三剑客之一.这三剑客,函数.库和类,都是由程序编写而成的.之所以我先说模 ...

  4. GO语言的进阶之路-初探GO语言

    GO语言的进阶之路-初探GO语言 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.为什么我们需要一门新语言 Go语言官方自称,之所以开发Go 语言,是因为“近10年来开发程序之难 ...

  5. Scala进阶之路-Scala中的高级类型

    Scala进阶之路-Scala中的高级类型 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.类型(Type)与类(Class)的区别 在Java里,一直到jdk1.5之前,我们说 ...

  6. GO语言的进阶之路-网络安全之proxy

    GO语言的进阶之路-网络安全之proxy 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 在党的带领下,我们大陆的孩子身心健康还是杠杠的,尤其是像我这种农村孩纸,从来不会像<人 ...

  7. GO语言的进阶之路-协程和Channel

    GO语言的进阶之路-协程和Channel 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 看过我之前几篇博客小伙伴可能对Golang语言的语法上了解的差不多了,但是,如果想要你的代码 ...

  8. GO语言的进阶之路-面向对象编程

    GO语言的进阶之路-面向对象编程 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 当你看完这篇文章之时,我可以说你的Golang算是入门了,何为入门?就是你去看Docker 源码能看 ...

  9. GO语言的进阶之路-面向过程式编程

    GO语言的进阶之路-面向过程式编程 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 我们在用Golang写一个小程序的时候,未免会在多个地方调用同一块代码,这个时候如何优化你的代码呢 ...

  10. GO语言的进阶之路-Golang高级数据结构定义

    GO语言的进阶之路-Golang高级数据结构定义 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 我们之前学习过Golang的基本数据类型,字符串和byte,以及rune也有所了解, ...

随机推荐

  1. Linux:文件系统

    Linux:文件系统 分区与文件系统 对分区进行格式化是为了在分区上建立文件系统.一个分区通常只能格式化为一个文件系统,但是磁盘阵列等技术可以将一个分区格式化为多个文件系统. 组成 最主要的组成部分如 ...

  2. PHP 实现Session入库/存入redis

    对于大访问量的站点使用默认的Session 并不合适,我们可以将其存入数据库.或者使用Redis KEY-VALUE数据存储方案 首先新建一个session表 CREATE TABLE `sessio ...

  3. Loadrunder脚本篇——关联数组(参数数组)

    导言 前面说过可以用关联取出服务器相关的一些动态变化的信息,前面也提过web_reg_save_param中可以设置ord=all,代表从服务器中取出的是一个数组,它试用的场景是当我访问一个发帖网站, ...

  4. api token

    具体实现如下: 1. api请求客户端想服务器端一次发送用用户认证信息(用户名和密码),服务器端请求到改请求后,验证用户信息是否正确. 如果正确:则返回一个唯一不重复的字符串(一般为UUID),然后在 ...

  5. PHP 获取真实IP地址

    function getClientIp($type = 0) { $type = $type ? 1 : 0; static $ip = NULL; if ($ip !== NULL) return ...

  6. HBase-存储-HFile格式

    HBase-存储-HFile格式 实际的存储文件功能是由HFile类实现的,它被专门创建以达到一个目的:有效地存储HBase的数据.它们基于Hadoop的TFile类,并模仿Google的BigTab ...

  7. POJ 3167 Cow Patterns (KMP+前缀和)

    题意:给你两串数字,长度分别为n和m,数字大小在[1,25].当后一串数字每个数字的排名位置与前一串数字(任一长度为m的子串)每个数字的排名位置一致时就完全匹配,最后求哪些位置是完全匹配的. 例如:1 ...

  8. CSU 1786 莫队+KDTree

    题意 给出n个二维点(2e5) 和 q个询问(1e4) 每个询问给lr 问点l到r间有多少对点的曼哈顿距离<=d 点的坐标<=108 想出了莫队算法 复杂度n^1.5 看起来很科学 但是每 ...

  9. PrepareStatement

    import java.sql.DriverManager; import java.sql.Connection; import java.sql.PreparedStatement; import ...

  10. Codeforces Beta Round #61 (Div. 2) D. Petya and His Friends 想法

    D. Petya and His Friends time limit per test 2 seconds memory limit per test 256 megabytes input sta ...