七夕之Linq

今天七夕,可我只有一个人。

前天喜欢的女生生日,我准备了很久,可最后却什么也没做。我若去找她,她肯定不会快乐。

今天七夕,还是什么也没说。我知道,语言都是苍白的。

突然感觉深深的无力。

还是再写一篇吧,写啥好呢,想了半天,就Linq了,很配七夕。

其实我也不知道为啥配。

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时才会真正应用这些条件。

现在来考虑第二个例子:

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

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-11 08:31:35

七夕之Linq的相关文章

.NET深入解析LINQ框架(五:IQueryable、IQueryProvider接口详解)

阅读目录: 1.环路执行对象模型.碎片化执行模型(假递归式调用) 2.N层对象执行模型(纵横向对比链式扩展方法) 3.LINQ查询表达式和链式查询方法其实都是空壳子 4.详细的对象结构图(对象的执行原理) 5.IQueryable<T>与IQueryProvider一对一的关系能否改成一对多的关系 6.完整的自定义查询 1]. 环路执行对象模型.碎片化执行模型(假递归式调用) 这个主题扯的可能有点远,但是它关系着整个LINQ框架的设计结构,至少在我还没有搞懂LINQ的本意之前,在我脑海里一直频

.NET深入解析LINQ框架(一:LINQ优雅的前奏)

阅读目录: 1.LINQ简述 2.LINQ优雅前奏的音符 2.1.隐式类型 (由编辑器自动根据表达式推断出对象的最终类型) 2.2.对象初始化器 (简化了对象的创建及初始化的过程) 2.3.Lambda表达式 (对匿名方法的改进,加入了委托签名的类型推断并很好的与表达式树的结合) 2.4.扩展方法 (允许在不修改类型的内部代码的情况下为类型添加独立的行为) 2.5.匿名类型 (由对象初始化器推断得出的类型,该类型在编译后自动创建) 2.6.表达式目录树(用数据结构表示程序逻辑代码) 3.LINQ

.NET深入解析LINQ框架(二:LINQ优雅的前奏)

阅读目录: 1.LINQ框架的主要设计模型 1.1.链式设计模式 (以流水线般的链接方式设计系统逻辑) 1.2.链式查询方法(逐步加工查询表达式中的每一个工作点) 2.LINQ框架的核心设计原理 2.1.托管语言之上的语言(LINQ查询表达式) 2.2.托管语言构造的基础(LINQ依附通用接口与查询操作符对应的方法对接) 2.3.深入IEnumerable.IEnumerable<T>.Enumerable(LINQ to Object框架的入口) 2.4.深入IQueryable.IQuer

.NET深入解析LINQ框架(四:IQueryable、IQueryProvider接口详解)

阅读目录: 1.开篇介绍 2.扩展Linq to Object (应用框架具有查询功能) 2.1.通过添加IEnumerable<T>对象的扩展方法 2.2.通过继承IEnumerable<T>接口 2.3.详细的对象结构图 3.实现IQueryable<T> .IQueryProvider接口 3.1.延迟加载IEnumertor<T>对象(提高系统性能) 3.2.扩展方法的扩展对象之奥秘(this IQueryable<TSource> so

.NET深入解析LINQ框架(三:LINQ优雅的前奏)

阅读目录: 1.动态LINQ查询(动态构建Expression<T>表达式树) 2.DLR动态语言运行时(基于CLR之上的动态语言运行时) 1].动态LINQ查询(动态构建Expression<T>表达式树) 什么是动态LINQ查询?LINQ的编写是静态的,因为C#是基于静态类型系统原理设计的,在编写时已经确定类型,也就是在编译时就已经知道将要执行什么样的查询,条件是什么.排序方式是什么等等.那么很大一部分应用场合中我们需要根据用户的选择来查询数据源,以往我们都是通过判断的方式来拼

.NET深入解析LINQ框架(六:LINQ执行表达式)

阅读目录: 1.LINQ执行表达式 在看本篇文章之前我假设您已经具备我之前分析的一些原理知识,因为这章所要讲的内容是建立在之前的一系列知识点之上的,为了保证您的阅读顺利建议您先阅读本人的LINQ系列文章的前几篇或者您已经具备比较深入的LINQ原理知识体系,防止耽误您的宝贵时间. 到目前为止我们对LINQ的执行原理已经很清楚了,从它的前期构想到它真正为我们所用都有足够的证据,但是似乎问题并没有我们想的那么简单,问题总是在我们使用中频频出现尤其是新技术的使用,当然有问题才能有进步. 一:LINQ执行

应用开发之Linq和EF

上一章笔者对于WinForm开发过程用到的几个知识点做了讲解.笔者们可以以此为开端进行学习.而本章我们来讲一个跟ORM思想有关的知识点.在讲之前让我们想一下关于JAVA的hibernate知识点.hibernate也是ORM框架.记得hibernate里面有一个叫HQL.先不管HQL的好与坏.主要是明白HQL的目地是什么.ORM的思想就是为了让用户在操作数据的时候用上面向对象的思想来看,而不是二维数据了.所以HQL笔者认为就是一个面向对象思想的SQL语句.那么为什么笔者要讲到HQL呢?事实上笔者

Linq to List

var lstMater = lst.GroupBy(w => new { w.materialId, w.name, w.isPass, w.description }). Select(g => new View_El_MyCourse_MaterialInfo { description = g.Key.description, isPass = g.Key.isPass, materialId = g.Key.materialId, name = g.Key.name }).Order

几种查询方法(lambda Linq Enumerable静态类方式)

1.需要一个数据源类: using System; using System.Collections.Generic; namespace Linq { public class Student { public int Id { get; set; } public string Name { get; set; } public int Age { get; set; } } public class Data { public static List<Student> studentLi