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

阅读目录:

  • 1.动态LINQ查询(动态构建Expression<T>表达式树)
  • 2.DLR动态语言运行时(基于CLR之上的动态语言运行时)

1】.动态LINQ查询(动态构建Expression<T>表达式树)

什么是动态LINQ查询?LINQ的编写是静态的,因为C#是基于静态类型系统原理设计的,在编写时已经确定类型,也就是在编译时就已经知道将要执行什么样的查询,条件是什么、排序方式是什么等等。那么很大一部分应用场合中我们需要根据用户的选择来查询数据源,以往我们都是通过判断的方式来拼接查询的SQL字符串,但是现在我们面对是强类型的LINQ查询,是否可以很方便的进行类似查询。其实也没有什么好神秘的,基本的实现原理是通过动态的构建表达式树来实现IQueryable<T>接口的查询。

其实动态LINQ查询所能执行的最关键的因素在于Expression<T>对象是可以被动态编译成可以执行的委托对象,委托对象是完全可以被直接使用的可执行代码段,这就为动态LINQ查询提供了基础。对于IEnumerable<T>类型的查询表达式方法都知道它的执行是不会直接接受Expression<T>类型对象的,那么动态LINQ是否能工作于IEnumerable<T>接口?其实可以的,有个很隐蔽的窍门隐藏在IQueryable<T>扩展方法对象Queryable中,也就是AsQueryable<T>方法,它返回的是一个实现了IQueryable<T>接口的EnumerableQuery对象,该对象的实现内容不是很复杂,将动态拼接的数据结构Expression<T>对象编译成可以执行的匿名函数,然后直接执行查询。

我们来看一下EnumerableQuery对象的重点,它肯定有一个地方是将Expression<T>对象Compiler的地方。

在上述代码中的“(1)重点”的地方,我们很清楚的看见表达式树被动态编译后然后紧接着又被执行,这里就能看出为什么IEnumerable<T>对象需要能够被转换成IQueryable<T>对象。这样就可以消除IEnumerable<T>、IQueryable<T>这两个接口之间的动态查询瓶颈。

为什么需要动态LINQ查询,上面说过问题出在我们没办法在运行时再去编写Lambda表达式了,都知道Lambda表达式到最后就是被编译成Expression表达式树对象,所以我们可以在运行时自己动态的构建Expression对象,这样就可以将动态构建出来的表达式树对象直接传入到需要的方法中。如果查询的数据对象是IEnumerable<T>则会被动态编译成可以执行的委托然后直接执行,如果查询的是IQueryable<T>则顺其自然的被提供程序解析执行。

下面我们来看一个简单的动态查询例子:

这是一组数据,为了简单测试就不搞那么麻烦的Linq to Sql数据源了。我们将要通过动态的构建表达式树来做为查询的逻辑,以往我们的Lambda在这个时候派不上用场了,在运行时我们无法再去构建委托类型。

现在的需求是从界面上接受一个Name值的输入,LINQ的查询只需要直接写就行了。

但是我们需要动态的构建表达式树来执行查询,表达式树的任何一个节点都有相对应的Expression派生类型,所以我们只要将相关类型组装起来就行了。由于我建的示例程序的类型是控制台程序,所以我们就用简短的方式演示一下如何构建表达式树。

图例:

该例子的重点是如何动态构建逻辑,根据不同的项目要求完全可以将类似的功能封装起来供以后重复使用。如果觉得手动编写表达式树很麻烦的话,建议可以找一个辅助类能将Lambda表达式的对象树都能打印出来的工具,然后对着这棵树在去写就简单多了。

关于动态LINQ的第三方的API不是很多,比较常用的就是Dynamic.cs的使用,具体我没有用过,看过相关文档应该还是比较方便的。它的内部原理其实还是动态的构建表达式树,只不过这部分工作被人家做了,而我们使用起来却简单的很多。

2】.DLR动态语言运行时(基于CLR之上的动态语言运行时)

从C#1一路走来,它变的越来越强大,.NET平台变得无所不能。很多人还一直咬着.NET不能跨平台,不能支持动态对象,不支持非托管等等理由来排斥它,然而他们所不知的是.NET已经悄无声息的做出来一大举动,那就是在静态语言运行时上嵌入动态语言运行时环境。我想不是微软不能支持所谓的缺点,而是它确实有它的本意。

动态语言运行时是在.NET4.0中引入的建立在CLR之上的运行时环境,目的是为了在静态语言中能够借鉴动态语言运行时的优点,比如强大的类型随意变换,这点在设计应用开发框架时尤其重要,任何一个好的特性都需要大面积的使用模式才能变的更完美。

说到动态运行时就不得不提JS中让人兴奋的var定义的对象特性了,如果没有留意在设计框架时而存在的烦恼其实很难发现动态运行和静态语言之间的好与不好。很明显的例子就是当我们定义一个数据类型的对象时,无法再在后期运行时对它进行其他类型的使用,看一个简单的例子:

在运行时我们可以随意的设计对象的类型,我大胆的假设完全可以用动态运行时特性设计类似人工智能系统,提供基本原型,然后根据用户自己的思维方式构建任意对象树。技术科研是很不错的方向,企业应用可能还有待商讨。

以往我们很难在运行时为对象动态的添加属性、行为、事件,通过动态语言运行时我们可以很自如的添加想要的东西。

下面我们来看一个简单的例子,在运行时动态的构建一个对象类型,在以前我们只有用动态编译、CodeDom技术来实现,这里将变的很简单。

一个很简单的例子告诉我们可以在C#中去编写如JS中的动态对象功能,不过目前还不是很成熟,动态对象的成员没有智能提示,应该是还没有被大面积使用起来,以后肯定也是一大美餐;

总结:LINQ框架的基本使用原理就全部结束了,后面我们就来学习如何能让LINQ查询我们自定义的数据源。很多朋友都喜欢自己写ORM框架,那么你肯定少不了对LINQ的支持吧?后面我们就来详细的讲解如何扩展IQueryable<T>、IQueryableProvider<T>两个重量级接口,只有他们两个才能让我们和LINQ对话,这两个接口还是很神秘的。

时间: 2024-08-05 15:00:10

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

.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框架1

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

atitit. groupby linq的实现(1)-----linq框架选型 java .net php

atitit.  groupby linq的实现(1)-----linq框架选型 java .net php 实现方式有如下 1. Dsl/ Java8 Streams AP ,对象化的查询api ,推荐 1 2. Linq::: like  sql 的dsl 1 1.1. linq4j (jdk6 ok,jdk7 编译错误,又马jar下载) 1 1.2. Quaere:Java上的LINQ(新不上sourcecode) 1 1.3. joSQL也是与Quaere类似的API 2 1.4. .n

LINQ:开始使用 LINQ(三)- 使用 LINQ 进行数据转换

开始使用 LINQ(三)- 使用 LINQ 进行数据转换 语言集成查询 (LINQ) 不仅可用于检索数据,  而且还是一个功能强大的数据转换工具.  通过使用 LINQ 查询,您可以将源序列用作输入,并采用多种方式修改它以创建新的输出序列.您可以通过排序和分组来修改该序列,而不必修改元素本身.但是,LINQ 查询的最强大的功能是能够创建新类型.这一功能在 select 子句中实现. 例如,可以执行下列任务: 一. 将多个输入联接到一个输出序列 1 class Student 2 { 3 publ

Linq技术三:Linq to Object 和生成数据表的扩展方法

这篇来谈论一下Linq第三个方面的应用:Linq to Object,只要是继承了IEnumerable或IQueryable接口的Object都能使用Linq特性进行操作.在操作过程当中可能很多人都觉得不好调试不能实时地观察结果数据集,想把IQuery的Linq查询语句转换成数据表DataTable,要怎么实现转换呢?来看一下. 先来说一场景解释一下为什么需要用Linq来解决一些问题,能解决一些什么样的问题,相对于SQL,DataTable等一些传统操作方式有哪些优势? 场景:目前主要数据源有

linq学习三个实例

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace LinqExer2 { class Program { static void Main(string[] args) { //1.LINQ实例一 //int[] number = { 2, 4, 3, 5, 7, 21, 34 }; //var