一起谈.NET技术,Linq学习笔记
写在前面
其实在09年就已经学习过Linq了,并被她那优美的语法所吸引,只是现在所在的公司还在使用VS2005在.Net2.0的框架下面的开发,所以Linq也很久没有用过了,最近看部门的同事对这个有些兴趣,所以打算整理点东西出来跟大家一起做个分享。
什么是Linq
LINQ是Language Integrated Query的简称,它是集成在.NET编程语言中的一种特性。已成为编程语言的一个组成部分,在编写程序时可以得到很好的编译时语法检查,丰富的元数据,智能感知、静态类型等强类型语言的好处。并且它同时还使得查询可以方便地对内存中的信息进行查询而不仅仅只是外部数据源。
Linq包括Linq to Objects, Linq to SQL,Linq to XML, Linq to DataSet等,本篇从Linq to Objects开始了解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 containerselect 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>的对象可以通过
来将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)。上一段简单的例子:
var container = new List<string> { "张三", "李四", "王五" }; var query = from name in containerselect 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 containerselect name;
select
对查询的结果进行投影,在子句中指定要选择的列,如上例。
有的时候,我们只需要投影某一列,我们可以这样
private static void TestSelectSingleProperty() {var persons = GetPersons();var query = from p in personsselect p.Name;foreach (var item in query){Console.WriteLine(item);} }
我们还可以指定要投影的列的集合,这个时候我们要用到匿名类型
var query = from p in personsselect 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 personsselect 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 personswhere p.DepartmentID == 1select p.Name;
join
类似SQL里的join,Linq中的join子句用于将两个容器的数据以某种关系进行关联。
var departments = GetDepartments(); var persons = GetPersons(); var query = from d in departmentsjoin p in persons on d.ID equals p.DepartmentIDselect 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 containergroup name by name.Length into gselect 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 personslet friendlyName = p.Gender == "男" ? "Mr" : "Ms" + p.Nameselect 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。
最后
这都只是皮毛,感兴趣的同学可以自己去MSDN查看更详细的资料,最后,推荐一个工具和一个网站:
LINQPAd(http://www.linqpad.net/) 一个非常有用的Linq学习工具
Linq 101 微软官方的Linq样例代码
转载于:https://www.cnblogs.com/waw/archive/2011/09/01/2162863.html
一起谈.NET技术,Linq学习笔记相关推荐
- Linq 学习笔记(二)
Linq 学习笔记(二) 下面就来介绍一些查询的示例: 1.Linq查询 var racers = from r in Formula1.GetChampions() where r.Wins > ...
- 《软件调试分析技术》学习笔记
<软件调试分析技术>学习笔记(一) 今天开始写写一些心得体验. <软件调试分析技术>是好友Monster的处女作品.作为一直以的好伙伴,他是我看着长大的,(*^__^*) 嘻嘻 ...
- 从研发角度谈存储技术的学习
从研发角度谈存储技术的学习 收藏 对于研发人员,存储技术的学习内容非常之多.我根据自己的理解,把它们大致分为以下8项内容: http://blog.csdn.net/liuben/archive/20 ...
- Spring Security技术栈学习笔记(十三)Spring Social集成第三方登录验证开发流程介绍
开发第三方登录,我们必须首先要了解OAuth协议(本文所讲述的OAuth协议指的是OAuth2协议),本文首先简单介绍OAuth协议,然后基于Spring Social来阐述开发第三方登录需要做哪些准 ...
- Spring Security技术栈学习笔记(十四)使用Spring Social集成QQ登录验证方式
上一篇文章<Spring Security技术栈开发企业级认证与授权(十三)Spring Social集成第三方登录验证开发流程介绍>主要是介绍了OAuth2协议的基本内容以及Spring ...
- 区块链技术指南学习笔记2
区块链技术指南学习笔记2 密码学 Hash 算法与数字摘要 常见hash算法 数字摘要 加解密算法 加解密系统基本组成 对称加密算法 非对称加密算法 消息认证码与数字签名 消息认证码 数字签名 数字证 ...
- Spring Security技术栈学习笔记(八)Spring Security的基本运行原理与个性化登录实现
正如你可能知道的两个应用程序的两个主要区域是"认证"和"授权"(或者访问控制).这两个主要区域是Spring Security的两个目标."认证&qu ...
- MAC OS X 技术内幕 学习笔记之四 MAC OS系统的启动引导
MAC OS X 技术内幕 学习笔记之四 MAC OS系统的启动引导 MAC OS的启动非常快,同样的运行硬件环境,运行MAC系统感觉比运行windows系统要快不少.在使用笔记本时,同样的电池容量, ...
- 《区块链原理与技术》学习笔记(六) — 区块链安全
<区块链原理与技术>学习笔记 第六部分 四.区块链网络层 1. 网络层安全 1.1 分布式拒绝服务攻击(DDos) 1.2 延展性攻击 1.3 日蚀攻击 1.4 分割攻击 1.5 延迟攻击 ...
最新文章
- django forms 错误处理
- linux qemu 源码编译
- python语法基础知识总结-Python基础知识梳理 - 第01部分
- Twitter-Snowflake,64位自增ID算法详解
- 单片机裸机实用组件--软件定时器、时间戳
- Shell程序设计 | 基本语法 :变量、I/O、算术运算、条件判断、流程控制、函数
- 解决sublime3不能编辑插件default settings的问题
- 数据结构之查找算法:B+树
- 数理统计的统计量分布t分布_t分布:啤酒厂发现的关键统计概念
- wordpress使用 ftp使用问题总结
- 修改hostname有几种方式?(转)
- python面试题之多线程好吗?列举一些让Python代码以并行方式运行的方法
- Elasticsearch--进阶-aggregations聚合分析_ES的强大的数据分析能力厉害啊---全文检索引擎ElasticSearch工作笔记016
- 3 矩阵运算_FlyAI小课堂:小白学PyTorch(11) 常见运算详解
- 【转】【翻】Android Design Support Library 的 代码实验——几行代码,让你的 APP 变得花俏...
- 个人博客系统的设计与实现_一个标星近 10k 的现代化的个人独立博客系统,程序员值得拥有...
- 中国移动5G智慧港口典型业务场景分析
- 制作PPT和画报的免费素材:pixabay免费照片插图矢量图
- python flask 微信_使用Flask创建微信公众号
- 四个收敛的关系:一致收敛,点态收敛,绝对收敛,条件收敛
热门文章
- html5中点击后不发生变化_魔道祖师中资深粉一看就明白的梗,路人见到后都反应不过来...
- jquery给div赋值
- layui引入jQuery
- mipi 屏 通过寄存器调背光
- [VB]在状态栏中显示帮助信息
- 英语总结系列(二十七):重复就是力量
- 30多门免费课程上线,亚马逊“机器学习大学”开学了
- C++中menset用法
- Java Web中相对路径与绝对路径的分析
- Chrome V8引擎系列随笔 (1):Math.Random()函数概览