F# 扩展查询表达式
有没有关于如何向查询表达式扩展/添加新关键字的文档或示例?这可能吗 例如,我想添加一个超前/滞后运算符。除了@pad提到的,还有来自F#团队的Wonseok Chae关于包含查询表达式的计算表达式的演讲。我不确定会议是否被录制,但有一个关于生成.NET IL代码的查询语法的很酷的例子 对于找出支持哪些类型的操作以及如何使用属性对其进行注释,可能是最好的资源F# 扩展查询表达式,f#,F#,有没有关于如何向查询表达式扩展/添加新关键字的文档或示例?这可能吗 例如,我想添加一个超前/滞后运算符。除了@pad提到的,还有来自F#团队的Wonseok Chae关于包含查询表达式的计算表达式的演讲。我不确定会议是否被录制,但有一个关于生成.NET IL代码的查询语法的很酷的例子 对于找出支持哪些类型的操作以及如何使用属性对其进行注释,可能是最好的资源 where子句演示了您可能需要的关键属性: [<CustomOperation("where",MaintainsVariableSp
where
子句演示了您可能需要的关键属性:
[<CustomOperation("where",MaintainsVariableSpace=true,AllowIntoPattern=true)>]
member Where :
: source:QuerySource<'T,'Q> *
[<ProjectionParameter>] predicate:('T -> bool) -> QuerySource<'T,'Q>
在这里,变量p
和name
在where
之后仍然可以访问,因为where
仅过滤输入,而不转换列表中的值
最后,ProjectionParameter
允许您说p.UnitValue>100.0M
实际上应该转换为一个函数,该函数接受上下文(可用变量)并计算该表达式。如果未指定此属性,则该操作只获取参数的值,如中所示:
query { for p in .. do
take 10 }
这里,参数
10
只是一个简单的表达式,不能使用p
中的值 该语言的功能相当酷。刚刚实现了查询QuerySource的反向操作
简单的例子,但只是一个演示
module QueryExtensions
type ExtendedQueryBuilder() =
inherit Linq.QueryBuilder()
/// Defines an operation 'reverse' that reverses the sequence
[<CustomOperation("reverse", MaintainsVariableSpace = true)>]
member __.Reverse (source : Linq.QuerySource<'T,System.Collections.IEnumerable>) =
let reversed = source.Source |> List.ofSeq |> List.rev
new Linq.QuerySource<'T,System.Collections.IEnumerable>(reversed)
let query = ExtendedQueryBuilder()
看一看。我的答案中的最后一个链接可能会引起您的兴趣。也许值得一提的是,这些可以是标准查询生成器类型上的扩展方法。非常酷!谢谢你的链接。有趣的是,可以使用现有的linq扩展来实现他们在这里想要的功能。@kvb这太酷了!但是,您还需要补充的是,它们不会与LINQ to SQL和LINQ to Entities的标准提供程序一起工作:-((除非您编写一些预处理器,将它们转换为表达式树中支持的其他内容?)是的,它们只适用于IEnumerables,而不适用于IQueryables。这可以通过确保输入和输出类型更加具体来实现(参见我对davewolfs的其他答案的评论)。请注意,您可能希望在您拥有
'Q
的两个位置都使用System.Collections.IEnumerable
,因为标准IQueryable提供程序不知道如何处理您的操作,如果使用它,将抛出运行时异常。它似乎运行良好,但会添加。您能更详细地解释一下吗?他们知道如何处理吗处理?基本上,IQueryable提供程序针对带引号的查询版本工作,并且只识别内置运算符。因此,如果执行类似于query的操作{for x in myDatabaseTable do reverse}
其中myDatabaseTable
是LINQ表,则查询在运行时将失败。如果将'Q
类型参数限制为IEnumerable
,则查询将在运行时成功,但在客户端运行所有逻辑(而不是尝试生成服务器端查询)。
module QueryExtensions
type ExtendedQueryBuilder() =
inherit Linq.QueryBuilder()
/// Defines an operation 'reverse' that reverses the sequence
[<CustomOperation("reverse", MaintainsVariableSpace = true)>]
member __.Reverse (source : Linq.QuerySource<'T,System.Collections.IEnumerable>) =
let reversed = source.Source |> List.ofSeq |> List.rev
new Linq.QuerySource<'T,System.Collections.IEnumerable>(reversed)
let query = ExtendedQueryBuilder()
let a = [1 .. 100]
let specialReverse =
query {
for i in a do
select i
reverse
}