写在前面
其实在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
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子句的语法为
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学习笔记(自己总结的)linq学习笔记(自己总结的)
linq 学习笔记与详解,是初学者不可或缺的好东西,一定要珍惜。
linq学习笔记,仅供参考
Linq学习笔记(内含电子书) 摘抄的几位高人的学习笔记 仅供学习使用 内含几本Linq的电子书 压缩文件名: Linq.part1.rar 不能解压的请把名称改为上面的名字
文件名称:Linq.part2.rar
介绍Select,update,delete等种种操作
很实用的linq笔记 整理
完整的linq to sql 学习笔记。
linq to sql 语法 学习笔记
个人工作和学习中积累和总结的linq各种知识 主要包含linq中的各种方法使用 学习linq可以提高开发效率 也是学习EF的基础
学习LINQ的最好资料 本人学习LINQ的笔记 很好 很好 很好 很好 很好
适合初学者学习,详细的内容。让新手上手更容易
自学的LINQ,学习笔记,有需要的可以下下来看看
C# 2008 学习笔记 - LINQ to XML 86 一、命名空间 86 二、编程方式创建XML文档 87 三、使用 LINQ 查询创建XML文档 88 四、加载和解析XML内容 89 六、遍历内存中的XML文档 89 七、修改 XML文档 91 使用linq to xml ...
C# 2008 学习笔记 - LINQ to XML 87 一、命名空间 87 二、编程方式创建XML文档 88 三、使用 LINQ 查询创建XML文档 89 四、加载和解析XML内容 90 六、遍历内存中的XML文档 90 七、修改 XML文档 92 使用linq to xml ...
“李永京”的LinqToSql学习笔记,供大家学习使用,里面有丰富的资源,推荐入门的学习者下载,不要错过了。。
C# 2008 学习笔记 - LINQ to XML 87 一、命名空间 87 二、编程方式创建XML文档 88 三、使用 LINQ 查询创建XML文档 89 四、加载和解析XML内容 90 六、遍历内存中的XML文档 90 七、修改 XML文档 92 使用linq to xml ...
为你详细的讲解LINQ的相关知识,很好的进行入门,适合对vs.net的学习者
C# 2008 学习笔记 - LINQ to XML 87 一、命名空间 87 二、编程方式创建XML文档 88 三、使用 LINQ 查询创建XML文档 89 四、加载和解析XML内容 90 六、遍历内存中的XML文档 90 七、修改 XML文档 92 使用linq to xml ...