Linq是c#设计者们在c#3.0中新添加的语法:查询表达式。使用查询表达式,很多标准查询操作符都能转化成更容易理解的代码,也就是和SQL风格非常接近的代码。

在介绍Linq之前,先介绍下泛型集合IEnumerable<T>,IEnumerable泛型接口可以在指定数据源进行迭代操作,它定义了一些扩展方法,可以对数据源进行操作。在Linq中,数据源实际是实现了对接口IEnumerable<T>的类,通过selsect返回的结果页实际是一个类。

Exposes the enumerator, which supports a simple iteration over a collection of a specified type.

这是msdn上给出的解释,一切foreach都是基于IEnumerable。在实际应用中,查询表达式输出哦几乎总是IEnumerable<T>或者它的派生类型。

下面看一段代码,简单的查询表达式:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace LinqBasic {
class Program {
private static string[] keyWords = { "it", "has", "been", "a", "long", "day", "to", "see", "you", "myfriend" }; public static void ShowWordContains() {
IEnumerable<string> selection = from word in keyWords where word.Contains("t") select word;
//此处将IEnumerable<string>换成var依旧可以,程序会根据选择的结果自动推断出查询的类型。
ShowWordContains(selection);
} public static void ShowWordContains(IEnumerable<string> selection){
foreach (string keyword in selection) Console.WriteLine(keyword);
}
static void Main(string[] args) { ShowWordContains();
Console.ReadLine(); }
}
}

输出:it
     to

在这个查询中,表达式总是以from子句开头,以select或者group by 结尾。from子句中的标识符word称为范围变量,代表集合中的每一项。这就很像是foreach循环变量代表集合中的没一项。

熟悉sql的开发者会发现,Linq和sql有非常相近的语法。最明显的区别是 c#查询的子句顺序首先是from子句,然后是where子句,最后才是select子句。而对应的sql查询首先是select,然后是from,最后是where。

#查询表达式的顺序其实更接近于各个操作在逻辑上的顺序,对查询进行求值时,首先指定集合from,再筛选出想要的项,(where),最后描述希望的结果(select)。

最后,c#查询表达式的顺序确保变量的作用域规则与局部变量的规则保持一致。例如,子句(通常是from)子句先声明变量,然后才能使用这个变量。

投射:

查询表达式的结果是IEnumerable<T>类型的集合。T的实际类型是从select或者group by子句推到出来的。例如 在上面的代码,编译器知到keywords是string[]类型,能穿花为IEnumerable<string>类型,所以推到出word是string类型,查询以select
word结尾,所以查询表达式是字符串集合,所以就算是匿名类型var,编译器也知道实际类型。

其实,输出类型还可以有别于输入类型,关键在于select子句的投射,如下面的代码。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
namespace LinqBasic {
class Program {
static void List1(string rootDirectory, string searchExtension) {
IEnumerable<string> files = Directory.GetFiles(rootDirectory, searchExtension);
IEnumerable<FileInfo> fileInfos = from file in files select new FileInfo(file);
foreach (FileInfo fileinfo in fileInfos) {
Console.WriteLine("filename:{0}, \tfileLaseWriteTime:{1}", fileinfo.Name, fileinfo.LastAccessTime);
}
} static void Main() {
List1(@"G:\c#\depositaryManagingSystem",@"*.cs");
Console.ReadLine();
}
}
}

输出:

filename:depositary.cs,         fileLaseWriteTime:2015/7/1 17:44:21
filename:depositary.Designer.cs,        fileLaseWriteTime:2015/6/25 19:32:42
filename:Form1.cs,      fileLaseWriteTime:2015/6/22 23:44:19
filename:Form1.Designer.cs,             fileLaseWriteTime:2015/6/22 23:44:19
filename:Program.cs,            fileLaseWriteTime:2015/6/17 10:17:38
filename:注册管理员.cs,         fileLaseWriteTime:2015/6/22 23:55:15
filename:注册管理员.Designer.cs,        fileLaseWriteTime:2015/6/25 19:34:32

这个查询表达式的结果是一个IEnumerable<fileinfo>,而不是Directoy.Getfiles()返回的Ienumerable<string>类型,查询表达式的select子句可以将from子句的表达式所收集到的东西完全投射到完全不同的数据类型中。

注意: 将上面的查询结果强数据类型转化成var匿名类型是完全可以的。

如下面的代码段:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
namespace LinqBasic {
class Program {
static void List1(string rootDirectory, string searchExtension) {
var files = Directory.GetFiles(rootDirectory, searchExtension);
var fileresults = from file in files
select new {
Name = file,
LastWriteName = File.GetLastWriteTime(file)
};
foreach (var fileresult in fileresults) {
Console.WriteLine("filename:{0}, \tfileLaseWriteTime:{1}\n", fileresult.Name, fileresult.LastWriteName);
}
} static void Main() {
List1(@"G:\c#\depositaryManagingSystem",@"*.cs");
Console.ReadLine();
}
}
}

在这个例子中,我们只投射出了文件名和他最后一次的写入时间。

程序运行结果

可以看出,Directory.Getfiles()这个静态方法可以得到文件的全名。而FileInfos.Name这个属性只能得到文件名。

关于文件的知识,将在不久后讲解。

初学者主题:查询表达式的推迟执行

我们现在来考虑我的第一个代码段,对selection赋值的时候,创建查询和向变量赋值不会执行查询,而只是生成代表查询的对象。换言之,查询对象创建时不会调用word.contains()方法。查询表达式只是存储了一个条件(查询标准)。以后再遍历有selection变量所标识的集合时会用到这个条件。

下面我们在来看一段代码来检测这个发生。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
namespace LinqBasic {
class Program {
private static string[] keyWords = { "it", "has", "been", "a", "long", "day", "to", "see", "you", "myfriend" };
public static void ShowKeywords() {
IEnumerable<string> selections = from word in keyWords where IsKeyWord(word) select word; Console.WriteLine("Query created");
foreach (string str in selections) Console.WriteLine(str);
}
private static bool IsKeyWord(string word) {
Console.WriteLine("~~~");
if (word.Contains("t")) return true;
return false;
}
static void Main() {
ShowKeywords();
Console.ReadLine();
}
}
}

程序输出:

可以看到,在query created 之前并没有任何输出,在foreach对集合的输出是,才调用方法IsKeyWord();

总之 虽然selection是集合(毕竟他的类型是IEnumerable<T>),但在赋值时,from子句之后的一切都构成了选择条件。遍历selection时才会真正应用这些条件。

现在来考虑第二个例子:

今天七夕要早睡,剩下的明天继续吧。

Linq(一)的更多相关文章

  1. Linq表达式、Lambda表达式你更喜欢哪个?

    什么是Linq表达式?什么是Lambda表达式? 如图: 由此可见Linq表达式和Lambda表达式并没有什么可比性. 那与Lambda表达式相关的整条语句称作什么呢?在微软并没有给出官方的命名,在& ...

  2. Linq之旅:Linq入门详解(Linq to Objects)

    示例代码下载:Linq之旅:Linq入门详解(Linq to Objects) 本博文详细介绍 .NET 3.5 中引入的重要功能:Language Integrated Query(LINQ,语言集 ...

  3. [C#] 走进 LINQ 的世界

    走进 LINQ 的世界 序 在此之前曾发表过三篇关于 LINQ 的随笔: 进阶:<LINQ 标准查询操作概述>(强烈推荐) 技巧:<Linq To Objects - 如何操作字符串 ...

  4. [C#] 进阶 - LINQ 标准查询操作概述

    LINQ 标准查询操作概述 序 “标准查询运算符”是组成语言集成查询 (LINQ) 模式的方法.大多数这些方法都在序列上运行,其中的序列是一个对象,其类型实现了IEnumerable<T> ...

  5. LINQ to SQL语句(7)之Exists/In/Any/All/Contains

    适用场景:用于判断集合中元素,进一步缩小范围. Any 说明:用于判断集合中是否有元素满足某一条件:不延迟.(若条件为空,则集合只要不为空就返回True,否则为False).有2种形式,分别为简单形式 ...

  6. .NET深入实战系列—Linq to Sql进阶

    最近在写代码的过程中用到了Linq查询,在查找资料的过程中发现网上的资料千奇百怪,于是自己整理了一些关于Linq中容易让人困惑的地方. 本文全部代码基于:UserInfo与Class两个表,其中Cla ...

  7. LINQ Group By操作

    在上篇文章 .NET应用程序与数据库交互的若干问题 这篇文章中,讨论了一个计算热门商圈的问题,现在在这里扩展一下,假设我们需要从两张表中统计出热门商圈,这两张表内容如下: 上表是所有政区,商圈中的餐饮 ...

  8. Entity Framework 6 Recipes 2nd Edition(11-9)译 -> 在LINQ中使用规范函数

    11-9. 在LINQ中使用规范函数 问题 想在一个LINQ查询中使用规范函数 解决方案 假设我们已经有一个影片租赁(MovieRental )实体,它保存某个影片什么时候租出及还回来,以及滞纳金等, ...

  9. Entity Framework 6 Recipes 2nd Edition(11-11)译 -> 在LINQ中调用数据库函数

    11-11. 在LINQ中调用数据库函数 问题 相要在一个LINQ 查询中调用数据库函数. 解决方案 假设有一个任命(Appointment )实体模型,如Figure 11-11.所示, 我们想要查 ...

  10. Entity Framework 6 Recipes 2nd Edition(13-6)译 -> 自动编译的LINQ查询

    问题 你想为多次用到的查询提高性能,而且你不想添加额外的编码或配置. 解决方案 假设你有如Figure 13-8 所示的模型 Figure 13-8. A model with an Associat ...

随机推荐

  1. ipv6例子

    一个IPv6通讯的例子 /* sudochen@163.com * * */ #include <stdio.h> #include <string.h> #include & ...

  2. ubuntu共享文件配置

    目标:实现windows和linux混合组成的操作 系统中可以共享文件,并可以通过机器名互相访问 安装文件共享服务 0.更改本机主机名,修改 /etc/hostname文件和/etc/hosts文件中 ...

  3. [后端人员耍前端系列]KnockoutJs篇:快速掌握KnockoutJs

    一.引言 之前这个系列文章已经介绍Bootstrap.由于最近项目中,前端是Asp.net MVC + KnockoutJs + Bootstrap来做的.所以我又重新开始写这个系列.今天就让我们来看 ...

  4. 细心很重要---猜猜这个SQL执行的什么意思

    今天在帮客户做语句优化的时候,突然遇到这样一个语句,类似下面的例子(原语句是个update) 例子中使用AdventureWorks数据中的两个表. productID 是[Production].[ ...

  5. dojo/aspect源码解析

    dojo/aspect模块是dojo框架中对于AOP的实现.关于AOP的详细解释请读者另行查看其它资料,这里简单复习一下AOP中的基本概念: 切面(Aspect):其实就是共有功能的实现.如日志切面. ...

  6. 打通移动App开发的任督二脉、实现移动互联创业的中国梦

    年初的两会上,第一次听到克强总理讲到“互联网+”的计划,当时就让我为之感到无比振奋.我个人的理解是:“互联网+”的本质就是要对传统行业供需双方的重构,通过移动互联技术来推动各个行业上的全民创新,促使中 ...

  7. java输出任意两个日期之间有多少天

    package JingDian; import java.text.ParseException; import java.text.SimpleDateFormat; import java.ut ...

  8. 一个简单的通用Makefile实现

    一个简单的通用Makefile实现   Makefile是Linux下程序开发的自动化编译工具,一个好的Makefile应该准确的识别编译目标与源文件的依赖关系,并且有着高效的编译效率,即每次重新ma ...

  9. 渣渣小本求职复习之路每天一博客系列——Java基础(9)

    ———————————————————————今天不闲聊————————————————————————————— 第十一章:线程 第四节:synchronized与同步 首先,我们来看一段代码: p ...

  10. [Unity3D]再次点击以退出程序

    [Unity3D]再次点击以退出程序 本文介绍为Android应用编写点击返回按键时的"再次点击以退出程序"的方法. +BIT祝威+悄悄在此留下版了个权的信息说: 下面是一个测试用 ...