gpt4 book ai didi

f# - 将一级函数参数传递给 LINQ 表达式

转载 作者:行者123 更新时间:2023-12-01 11:16:34 26 4
gpt4 key购买 nike

此代码片段重现了我在使用某些生产代码时遇到的问题。函数 containsProperty 代表一个真实世界的函数,它实际上在一个库中,所以我对签名是什么没有发言权。

问题是我不知道如何创建一个可以将普通函数作为参数的包装函数,然后将其传递给 containsProperty。我可以使用作为 lambda 表达式的函数直接调用 containsProperty,但我不能使用来自其他来源的函数调用它。

函数 addToGroup 是迄今为止我想出的最好的函数,它使用引号。这种方法有两个问题,我正试图弄清楚。首先,如何去掉引号中的 Func ?也许以某种方式将它移到 addToGroup 中?其次,我可以以此为基础只传递一个函数吗?我还没有成功找到既不产生编译时错误也不产生运行时错误的东西。

函数 addToGroup2 是我想要执行的操作,但它无法编译。错误消息是“'Quotations.Expr<'a>' 类型没有可用的构造函数”。

为什么我要费心去解决这个问题?因为只要我不能将传入的函数视为一流值,我就无法创建我想要的设计。我希望这些函数来自记录集合。

如果将此代码段粘贴到 LINQPad 或其他软件中,请注释掉 addToGroup2 及其调用,以便编译和运行代码段。

open System
open System.ComponentModel
open System.ComponentModel.DataAnnotations // Reference to this assembly required.

type CfgSettings = {
mutable ConnectionString: string
mutable Port: int
}

and CfgSettingsMetadata() =
static member containsProperty<'TProperty>(propertyExpression: Linq.Expressions.Expression<Func<CfgSettings,'TProperty>>) =
Console.WriteLine "good!"
static member addToGroup f =
CfgSettingsMetadata.containsProperty(FSharp.Linq.RuntimeHelpers.LeafExpressionConverter.QuotationToLambdaExpression f) |> ignore
static member addToGroup2 (f: CfgSettings -> 'TProperty) =
CfgSettingsMetadata.containsProperty(FSharp.Linq.RuntimeHelpers.LeafExpressionConverter.QuotationToLambdaExpression (Quotations.Expr<Func<CfgSettings,'TProperty>>f)) |> ignore
static member BuildMetadata () =
CfgSettingsMetadata.containsProperty(fun x -> x.ConnectionString)
CfgSettingsMetadata.containsProperty(fun x -> x.Port)
CfgSettingsMetadata.addToGroup <@ Func<_,_>(fun x -> x.ConnectionString) @>
CfgSettingsMetadata.addToGroup <@ Func<_,_>(fun x -> x.Port) @>
CfgSettingsMetadata.addToGroup2 (fun x -> x.ConnectionString)
CfgSettingsMetadata.addToGroup2 (fun x -> x.Port)

CfgSettingsMetadata.BuildMetadata()

问题的两个答案Expression<Func<T, bool>> from a F# func对我有所帮助,但我还没有找到解决方案。

最佳答案

那么,这里有两个问题。

如何传递函数而不必将其包装在 <@ ... @> 中?

为此,您只需添加 [<ReflectedDefinition>]属性到你的方法的参数。它隐式地将传递给它的参数包装在引号中。

type CfgSettingsMetadata() =
static member addToGroup([<ReflectedDefinition>] f: Expr<CfgSettings -> 'TProperty>) =
CfgSettingsMetadata.containsProperty(LeafExpressionConverter.QuotationToLambdaExpression f) |> ignore

// Example use:
CfgSettingsMetadata.addToGroup(Func<_, _>(fun x -> x.ConnectionString))

如何从 Expr<a -> b> 转换至 Expression<Func<a, b>>

这确实在您链接的问题中得到了解释,尽管此后 API 发生了一些变化。

type CfgSettingsMetadata() =
static member addToGroup ([<ReflectedDefinition>] (f: Expr<CfgSettings -> 'TProperty>)) =
let call = LeafExpressionConverter.QuotationToExpression f :?> MethodCallExpression
let lambda = call.Arguments.[0] :?> LambdaExpression
let e = Expression.Lambda<Func<CfgSettings, 'TProperty>>(lambda.Body, lambda.Parameters)
CfgSettingsMetadata.containsProperty(e) |> ignore

// Example use:
CfgSettingsMetadata.addToGroup(fun x -> x.ConnectionString)

关于f# - 将一级函数参数传递给 LINQ 表达式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50196797/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com