将 F# 函数转换为表达式<Func<..,..>>
Convert F# func to Expression<Func<..,..>>
我有一个带有以下签名的函数的模块:
module Something =
let someFunc func = // ('TType -> 'TField) -> 'TValue
...
在该函数内部,我从某个外部库调用一个函数,该函数具有以下签名 (C#) 的方法:
class SomeClass
{
public ReturnType<TType> SomeMethod<TField>(func: Expression<Func<TType, TField>>) { ... }
}
当我尝试在那里传递一个 'TType -> 'TField
函数时,我得到一个错误,它不能转换为 Expression<Func<'TType, 'TField>>
。我在 Whosebug 上发现了以下问题:question
但这并没有解决我的问题(第一个答案无效,第二个答案有效,但我必须更改函数的签名)。
对于第二个答案,我必须将函数的签名更改为以下内容:
module Something =
let someFunc func = // Expression<Func<'TType, 'TField>>) -> 'TValue
...
为我的模块的 "client" 添加额外的 class 可见,如下所示:
type ExpressionHelper() =
static member AsExpression<'TType, 'TField>(e: Expression<Func<'TType, 'TField>>) = e
所以最后的调用看起来像这样:
let _ = Something.someFunc (fun (o: SomeType) -> o.someField)
看起来像这样:
let _ = Something.someFunc (ExpressionHelper.AsExpression (fun (o: SomeType) -> o.SomeField))
我不想强制模块的 user
将 F# 函数显式转换为 Expression<Func<'TType, 'TField>>
。我想在我的模块中这样做,有什么方法可以实现吗?
如果您有一个 'T1 -> 'T2
类型的值,则无法将其转换为 Expression<Func<'T1, 'T2>>
类型的值。这是不可能的,因为前者是编译后的函数(引用某个对象及其方法的委托),而后者是原始源代码的表示。
因此,您将需要使用 Expression<...>
作为参数类型(或 Expr
,如果您要使用引号,这是 F# 的等价物)。
但是,在 F# 中,有时编译器会自动将使用 lambda 函数语法 fun x -> ..
创建的值转换为 Expression<...>
类型的值。它不会为 let-bound 函数的参数执行此操作,但会为静态方法的参数执行此操作。这意味着您可以使用:
open System
open System.Linq.Expressions
type A =
static member foo (f:Expression<Func<int, int>>) =
f.ToString()
A.foo (fun n -> n + 1)
我有一个带有以下签名的函数的模块:
module Something =
let someFunc func = // ('TType -> 'TField) -> 'TValue
...
在该函数内部,我从某个外部库调用一个函数,该函数具有以下签名 (C#) 的方法:
class SomeClass
{
public ReturnType<TType> SomeMethod<TField>(func: Expression<Func<TType, TField>>) { ... }
}
当我尝试在那里传递一个 'TType -> 'TField
函数时,我得到一个错误,它不能转换为 Expression<Func<'TType, 'TField>>
。我在 Whosebug 上发现了以下问题:question
但这并没有解决我的问题(第一个答案无效,第二个答案有效,但我必须更改函数的签名)。
对于第二个答案,我必须将函数的签名更改为以下内容:
module Something =
let someFunc func = // Expression<Func<'TType, 'TField>>) -> 'TValue
...
为我的模块的 "client" 添加额外的 class 可见,如下所示:
type ExpressionHelper() =
static member AsExpression<'TType, 'TField>(e: Expression<Func<'TType, 'TField>>) = e
所以最后的调用看起来像这样:
let _ = Something.someFunc (fun (o: SomeType) -> o.someField)
看起来像这样:
let _ = Something.someFunc (ExpressionHelper.AsExpression (fun (o: SomeType) -> o.SomeField))
我不想强制模块的 user
将 F# 函数显式转换为 Expression<Func<'TType, 'TField>>
。我想在我的模块中这样做,有什么方法可以实现吗?
如果您有一个 'T1 -> 'T2
类型的值,则无法将其转换为 Expression<Func<'T1, 'T2>>
类型的值。这是不可能的,因为前者是编译后的函数(引用某个对象及其方法的委托),而后者是原始源代码的表示。
因此,您将需要使用 Expression<...>
作为参数类型(或 Expr
,如果您要使用引号,这是 F# 的等价物)。
但是,在 F# 中,有时编译器会自动将使用 lambda 函数语法 fun x -> ..
创建的值转换为 Expression<...>
类型的值。它不会为 let-bound 函数的参数执行此操作,但会为静态方法的参数执行此操作。这意味着您可以使用:
open System
open System.Linq.Expressions
type A =
static member foo (f:Expression<Func<int, int>>) =
f.ToString()
A.foo (fun n -> n + 1)