写在前面

最近在看Linq,在博客园看到这篇文章,写的通俗易懂,转来和大家一起做个分享。原文地址http://www.cnblogs.com/goscan/archive/2011/05/05/Linq_study_log.html

什么是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 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)。上一段简单的例子:

var 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。

最后

这都只是皮毛,感兴趣的同学可以自己去MSDN查看更详细的资料,最后,推荐一个工具和一个网站

LINQPAd(http://www.linqpad.net/)  一个非常有用的Linq学习工

(转)Linq学习笔记的更多相关文章

  1. linq学习笔记

    最近在学习linq的一些基础知识,看了c#高级编程及阅读了园子内部几篇优秀的博文,有所体会,感觉应该记录下来,作为以后复习使用.都是一些最基础的知识,大致分为三个部分:linq预备知识:linq查询: ...

  2. C#之Linq学习笔记【转】

    写在前面 其实在09年就已经学习过Linq了,并被她那优美的语法所吸引,只是现在所在的公司还在使用VS2005在.Net2.0的框架下面的开发,所以Linq也很久没有用过了,最近看部门的同事对这个有些 ...

  3. C# Linq 学习笔记

    刚刚学习了 Siki老师 的C#教程Linq部分,以下是笔记 需要引用命名空间 using System.Linq; 然后我们需要准备数据 武林高手类 /// <summary> /// ...

  4. C# LINQ学习笔记一:走进LINQ的世界

    本笔记摘抄自:https://www.cnblogs.com/liqingwen/p/5832322.html,记录一下学习过程以备后续查用. LINQ 简介:     语言集成查询(LINQ)是Vi ...

  5. LINQ 学习笔记(1)

    学习资源参考 : http://www.cnblogs.com/lifepoem/archive/2011/12/16/2288017.html 常用方法是 Where, OrderBy, Selec ...

  6. C# LINQ学习笔记五:LINQ to XML

    本笔记摘抄自:https://www.cnblogs.com/yaozhenfa/p/CSharp_Linq_For_Xml.html,记录一下学习过程以备后续查用. 一.生成xml 1.1创建简单的 ...

  7. C# LINQ学习笔记四:LINQ to OBJECT之操作文件目录

    本笔记摘抄自:https://www.cnblogs.com/liqingwen/p/5816051.html,记录一下学习过程以备后续查用. 许多文件系统操作实质上是查询,因此非常适合使用LINQ方 ...

  8. C# LINQ学习笔记三:LINQ to OBJECT之操作字符串

    本笔记摘抄自:https://www.cnblogs.com/liqingwen/p/5814204.html,记录一下学习过程以备后续查用. 一.统计单词在字符串中出现的次数 请注意,若要执行计数, ...

  9. C# LINQ学习笔记二:LINQ标准查询操作概述

    本笔记摘抄自:https://www.cnblogs.com/liqingwen/p/5801249.html,记录一下学习过程以备后续查用. “标准查询运算符”是组成语言集成查询 (LINQ) 模式 ...

随机推荐

  1. MySQL之扩展(触发器,存储过程等)

    视图 视图是一个虚拟表(非真实存在),其本质是[根据SQL语句获取动态的数据集,并为其命名],用户使用时只需使用[名称]即可获取结果集,并可以将其当作表来使用. SELECT * FROM ( SEL ...

  2. css 中的度量单位

    px 相对长度单位.像素(Pixel). 像素是相对于显示器屏幕分辨率而言的.譬如,WONDOWS的用户所使用的分辨率一般是96像素/英寸.而MAC的用户所使用的分辨率一般是72像素/英寸. em 相 ...

  3. 【转】 JSONObject使用方法

    随笔- 46  文章- 0  评论- 132 JSONObject简介 本节摘要:之前对JSON做了一次简单的介 绍,并把JSON和XML做了一个简单的比较:那么,我就在想,如果是一个json格式的字 ...

  4. python动态获取对象的属性和方法

    http://blog.csdn.net/kenkywu/article/details/6822220首先通过一个例子来看一下本文中可能用到的对象和相关概念.01     #coding: UTF- ...

  5. iOS 使用UIWebView把oc代码和javascript相关联

    首先请参看一篇文章,作者写的很明白,请参看原地址 http://blog.163.com/m_note/blog/static/208197045201293015844274/. 其实,oc和js的 ...

  6. July 21st, Week 30th Thursday, 2016

    What youth deemed crystal, age finds out was dew. 年少时的水晶,在岁月看来不过是露珠. As time goes by, we are gradual ...

  7. 补丁vs错误(codevs 2218 错误答案)

    题目描述 Description 错误就是人们所说的Bug.用户在使用软件时总是希望其错误越少越好,最好是没有错误的.但是推出一个没有错误的软件几乎不可能,所以很多软件公司都在疯狂地发放补丁(有时这种 ...

  8. 多源最短路(codevs 1077)

    题目描述 Description 已知n个点(n<=100),给你n*n的方阵,a[i,j]表示从第i个点到第j个点的直接距离. 现在有Q个询问,每个询问两个正整数,a和b,让你求a到b之间的最 ...

  9. HttpHandler动态生成图片

    1.向服务器请求返回图片,浏览器是不知道服务上有这个图片的存在的,只是发出请求,接收请求,显示图片 string path = context.Server.MapPath("~/1.jpg ...

  10. Mysql 5.6.17-win64.zip配置

    第一大步:下载. a.俗话说:“巧妇难为无米之炊”嘛!我这里用的是 ZIP Archive 版的,win7 64位的机器支持这个,所以我建议都用这个.因为这个简单嘛,而且还干净. 地址见图 拉倒最下面 ...