12.4.1 自定义查询表达式

原则上,我们可以使用查询处理任何类型,只要它提供了绑定操作。这是函数式编程中这类函数的标准名称,像上一节类型签名所展示的。从技术角度来讲,我们需要实现一些方法,在把查询表达式转换为标准的函数调用,由 C# 编译器所使用。我们将为 12.6 节中的 Option<T> 的类型实现这些方法,该类型没有实现 IEnumerable<T>,所以,不能使用标准查询运算符。

我们首先考虑一下,查询应用到选项类型,是什么意思。清单 12.15 有两个查询,左边的处理列表,右边的处理选项类型。我们将使用两个简单的函数来提供输入:ReadIntList 函数读取整数列表(类型为 List<int>),TryReadInt 返回选项值(类型为 Option<int>)。

清单 12.15 对列表和选项值使用查询 (C#)


var list =

from n in ReadIntList()

from m in ReadIntList()

select n * m;


var option =

from n in TryReadInt()

from m in TryReadInt()

select n * m;

除了处理的数据类型不同之外,查询完全相同,因此,它们使用不同的查询运算符实现。两者都读不同的输入,并返回输入整数的积。表 12.1 给出了样本输入和结果。

表 12.1 对于可能的不同输入,由使用列表和选项值的查询所产生的结果


Type of values


Input #1


Input #2


Output


Lists

Options

Options

Options


[2; 3]

Some(2)

Some(3)

None


[10; 100]

Some(10)

None

Not required


[20; 200; 30; 300]

Some(20)

None

None

对于列表,查询执行交叉联接运算(可以想象成 F# 序列表达式中的两个嵌套for 循环),会产生一个序列,由输入值的每种组合条目所组成;对于选项值,有三种可能性。

■当第一个输入是值时,需要读第二个。然后,根据第二个输入的不同,有以下两种情况:

— 如果第二个输入也是值,则结果是 Some 值,包含的结果是积。

— 如果第二个输入是 None,由于没有值相乘,因此,查询返回 None。

■当第一个输入为 None 时,我们知道,结果无需考虑第二输入。整个查询延迟执行,所以,不必去读第二输入:TryReadInt 函数只调用一次。

可以发现,查询表达式提供了一种简便的方法,处理选项值。清单 12.15 无疑要比我们在第六章看到的等价代码,容易写(和读),那时,我们显式地使用了高阶函数。在本章的后面我们将会看到,实现所有必要的查询运算符;不过,现在,我们还是先看一下在 F# 中的类似语法。

时间: 2024-11-15 00:37:27

12.4.1 自定义查询表达式的相关文章

12.4.2 自定义 F# 语言

到目前为止,我们所讨论过的序列表达式,都是用 seq 标识符表示,后面的代码块括在大括号中.然而,F# 还允许我们创建自己的标识符,给代码块以特殊的意义.通常,这个功能称为计算表达式(computation expressions),而序列表达式是它的一个特例,是由 F#核心所实现,并经编译器优化. 我们已经知道,计算表达式可以包含标准的语言结构,比如 for 循环,还有别的结构,像 yield.在代码块之前的标识符,描述构造的意义,其方式与查询运算符(例如,Select 和 Where 扩展方

十五、C# 使用查询表达式的LINQ

使用查询表达式的LINQ 本章介绍了一种新的语法,查询表达式. 1.查询表达式概述 2.特点:投射  筛选  排序   Let  分组 3.作为方法调用 标准查询运算符所实现的查询在功能上与SQL中实现的查询非常相似 C#3.0中添加了一个新的语法:查询表达式. 本章将介绍新的查询表达式语法,并利用这个语法对上一章的许多查询进行表示. 一.查询表达式概述 除了遍历集合中的所有项之外,开发者经常要执行的另一个操作是对集合进行筛选,目的是 最终只需要遍历数量较少的项,或者对集合进行投射,使其中的项变

C# 标准查询表达式

一.标准查询运算符 1.C#提供了标准查询运算符,例如我想选择专利一系列(pantents)中以年份19开头的专利,可以用如下语句: IEnumerable<Patent> pantentWhere = pantents.Where(pantent => pantent.YearOfPublicaton.StartsWith("19")); 当然,此处的语句只是定义了查询,此时pantentWhere并没有内容,后面Lambda表达式指定的查询并没有执行,只有当遍历p

Linq学习之旅——LINQ查询表达式

1. 概述 2. from子句 3. where子句 4. select子句 5. group子句 6. into子句 7. 排序子句 8. let子句 9. join子句 10. 小结 1. 概述 LINQ的全称是Language Integrated Query,中文译成“语言集成查询”.LINQ作为一种查询技术,首先要解决数据源的封装,大致使用了三大组件来实现这个封装,分别是LINQ to Object.LINQ to ADO.NET.LINQ to XML.它们和.NET语言的关系如下:

LINQ查询表达式基础

LINQ,语言集成查询(Language Integrated Query)是一组用C#和Visual Basic语言的扩展. 对于编写查询的开发人员来说,LINQ 最明显的"语言集成"部分是查询表达式.查询表达式是使用 C# 3.0 中引入的声明性查询语法编写的.通过使用查询语法,你甚至可以使用最少的代码对数据源执行复杂的筛选.排序和分组操作.你使用相同的基本查询表达式模式来查询和转换 SQL 数据库.ADO.NET 数据集.XML 文档和流以及 .NET 集合中的数据. 下面我们通

Lambda表达式和查询表达式(1)基本概念

Lambda表达式也是一种匿名函数(anonymous function),比匿名方法具有更加简洁的表示形式.它可以包含表达式和语句,并且适用于创建委托和事件. 查询表达式: 是一种使用查询语法表示的表达式,它可以从一个或多个给定的数据源中检索数据,并制定检索结果的表现形式. Lambda表达式:  由输入参数.Lambda运算符和表达式(或语句块)构成. 它的语法形式如下: (input parameters) => empression; : input parameters : 表示输入参

LINQ查询表达式---------let子句

LINQ查询表达式---------let子句 let子句创建一个范围变量来存储结果,变量被创建后,不能修改或把其他表达式的结果重新赋值给它.此范围变量可以再后续的LINQ子句中使用. class Program { static void Main(string[] args) { int[] number = { 12, 15, 16, 17, 18, 19, 20 }; var query = from num in number let n = num % 2 where n == 0

LINQ查询表达式(1) - 查询表达式基础

什么是查询?它有什么用途? "查询"是指一组指令,这些指令描述要从一个或多个给定数据源检索的数据以及返回的数据应该使用的格式和组织形式. 查询不同于它所产生的结果.通常,源数据会在逻辑上组织为相同种类的元素序列. SQL 数据库表包含一个行序列. 与此类似,ADO.NET DataTable 包含一个 DataRow 对象序列. 在 XML 文件中,有一个 XML 元素"序列"(不过这些元素按分层形式组织为树结构). 内存中的集合包含一个对象序列.从应用程序的角度来

解读ASP.NET 5 &amp; MVC6系列(12):基于Lamda表达式的强类型Routing实现

原文:解读ASP.NET 5 & MVC6系列(12):基于Lamda表达式的强类型Routing实现 前面的深入理解Routing章节,我们讲到了在MVC中,除了使用默认的ASP.NET 5的路由注册方式,还可以使用基于Attribute的特性(Route和HttpXXX系列方法)来定义.本章,我们将讲述一种基于Lambda表达式的强类型类型. 这种方式的基本使用示例如下: services.Configure<MvcOptions>(opt => { opt.EnableTy