写在前面

最近在看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. 手把手教你用Python爬虫煎蛋妹纸海量图片

    我们的目标是用爬虫来干一件略污事情 最近听说煎蛋上有好多可爱的妹子,而且爬虫从妹子图抓起练手最好,毕竟动力大嘛.而且现在网络上的妹子很黄很暴力,一下接受太多容易营养不量,但是本着有人身体就比较好的套路 ...

  2. Linux运维相关目录

  3. jQuery mobile 开发问题记录

    一.动态加载页面问题 1.存在这样一个页面布局: main.html 为主界面A,B为该页面中的三个page,其中A为splitview左部分页面,B为右半部页面 a1.html 为一个独立的页面 a ...

  4. 【GoLang】GoLang GOPATH 工程管理 最佳实践

    参考资料: MAC下 Intellij IDEA GO语言插件安装及简单案例:http://blog.csdn.net/fenglailea/article/details/53054502 关于wi ...

  5. 【转】mysql 触发器实现两个表的数据同步

    mysql通过触发器实现两个表的同步 目前,在本地测试成功. 假设本地的两个数据库a和b,a下有表table1(id, val) b下有表table2(id, val) 假设希望当table1中数据更 ...

  6. Java for LeetCode 164 Maximum Gap

    Given an unsorted array, find the maximum difference between the successive elements in its sorted f ...

  7. codeforces B. New Year Present 解题报告

    题目链接:http://codeforces.com/contest/379/problem/B 题目意思:给定一个有n个钱包的序列,其中第i个钱包需要投入ai个钱币,需要编写一个程序,使得在对第i个 ...

  8. jQuery工具函数

    要点:1.字符串操作2.数组和对象操作3.测试操作4.URL 操作5.浏览器检测6.其他操作 工具函数是指直接依附于 jQuery 对象,针对 jQuery 对象本身定义的方法,即全局性的函数.它的作 ...

  9. 【读书笔记】读《JavaScript高级程序设计-第2版》 - 函数部分

    1. 定义 函数实际上是对象,每个函数都是Function类型的实例,而且都与其他引用类型一样具有属性和方法.由于函数是对象,因此函数名实际上也是一个指向函数对象的指针,不会与某个函数绑定. 对于函数 ...

  10. show processlist

    mysql> show processlist; #mysql服务器查看有那些主机连进来,并列出它们查什么库 +-----+------+-----------+------+--------- ...