无法让运算符重载与 Linq 表达式树一起使用

发布于 2024-08-10 04:14:44 字数 1563 浏览 6 评论 0原文

我正在从 F# 创建 Linq 表达式树,该树对我拥有的自定义数据类型进行操作。该类型是一个非常简单的可区分联合,它重载了常用的算术运算符。但由于某种原因,我无法创建算术 linq 表达式节点,因为它找不到正确的重载。问题是,我发誓我不久前就已经开始工作了,但我不知道我做了什么改变才使它崩溃。

我将附上一个显示问题的小代码示例。下面的数据类型重载了加法运算符。使用重载运算符就像一个魅力,但是当我尝试使用 Expression.Add(lhs, rhs) 创建加法表达式树节点时,系统会抛出一个异常,抱怨它找不到 Add 操作的重载。

有人知道我做错了什么吗?

谢谢你, 里卡德

open System.Linq.Expressions

module DataType =
    exception NotImplementedYet of string

    type DataCarrier =
        | ScalarCarrier of float
        | VectorCarrier of float array

        member this.Add(other) =
            match (this, other) with
            | ScalarCarrier(x), ScalarCarrier(y) -> ScalarCarrier(x + y)
            | VectorCarrier(u), VectorCarrier(v) -> 
                VectorCarrier(Array.map2 (fun x y -> x + y) u v)
            | _,_ -> raise (NotImplementedYet("No go!"))

        static member (+) (lhs:DataCarrier, rhs) =
            lhs.Add(rhs)

module Main =
    let createAddOp (lhs:DataType.DataCarrier) (rhs:DataType.DataCarrier) =
        let clhs = Expression.Constant(lhs)
        let crhs = Expression.Constant(rhs)
        Expression.Add(clhs, crhs)

(* no problems with this one *)
printf "Testing operator overloading: %A" (DataType.ScalarCarrier(1.0) 
                                           + DataType.ScalarCarrier(2.0))
(* this throws an exception *)
printf "Testing expr construction %A" (Main.createAddOp 
                                        (DataType.ScalarCarrier(1.0))
                                        (DataType.ScalarCarrier(2.0)))

I am creating Linq expression trees from F# that operates on a custom datatype I have. The type is a very simple discriminated union that has the usual arithmetic operators overloaded. But for some reason I cannot create arithmetic linq expression nodes due to the fact that it can't find the correct overload. Thing is, I swear I had this working some time ago but I can't figure out what I changed to make it break.

I'll attach a small code sample showing the problem. The datatype below has the Addition operator overloaded. Using the overloaded operator works like a charm, but when I try to create an addition expression tree node using Expression.Add(lhs, rhs) the system throws an exception complaining that it can't find the overload for the Add operation.

Does anyone have an idea of what I am doing wrong?

Thank you,
Rickard

open System.Linq.Expressions

module DataType =
    exception NotImplementedYet of string

    type DataCarrier =
        | ScalarCarrier of float
        | VectorCarrier of float array

        member this.Add(other) =
            match (this, other) with
            | ScalarCarrier(x), ScalarCarrier(y) -> ScalarCarrier(x + y)
            | VectorCarrier(u), VectorCarrier(v) -> 
                VectorCarrier(Array.map2 (fun x y -> x + y) u v)
            | _,_ -> raise (NotImplementedYet("No go!"))

        static member (+) (lhs:DataCarrier, rhs) =
            lhs.Add(rhs)

module Main =
    let createAddOp (lhs:DataType.DataCarrier) (rhs:DataType.DataCarrier) =
        let clhs = Expression.Constant(lhs)
        let crhs = Expression.Constant(rhs)
        Expression.Add(clhs, crhs)

(* no problems with this one *)
printf "Testing operator overloading: %A" (DataType.ScalarCarrier(1.0) 
                                           + DataType.ScalarCarrier(2.0))
(* this throws an exception *)
printf "Testing expr construction %A" (Main.createAddOp 
                                        (DataType.ScalarCarrier(1.0))
                                        (DataType.ScalarCarrier(2.0)))

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

半枫 2024-08-17 04:14:44

一种解决方案是显式键入表达式操作数(为它们提供静态类型 DataType.DataCarrier 而不是其运行时类型 DataType.DataCarrier.ScalarCarrier):

module Main =
    let createAddOp (lhs:DataType.DataCarrier) (rhs:DataType.DataCarrier) =
        let clhs = Expression.Constant(lhs, typeof<DataType.DataCarrier>)
        let crhs = Expression.Constant(rhs, typeof<DataType.DataCarrier>)
        Expression.Add(clhs, crhs)

另一种选择是显式键入传递加法运算符来使用:

module Main =
    let createAddOp (lhs:DataType.DataCarrier) (rhs:DataType.DataCarrier) =
        let clhs = Expression.Constant(lhs)
        let crhs = Expression.Constant(rhs)
        Expression.Add(clhs, crhs, typeof<DataType.DataCarrier>.GetMethod("op_Addition"))

不过,我很惊讶您的原始代码不起作用。这似乎是表达式树如何查找相关添加运算符的限制(也就是说,Linq 似乎仅在操作数的运行时类型上查找添加运算符)。

One solution is to explicitly type the Expression operands (giving them the static type DataType.DataCarrier instead of their runtime type DataType.DataCarrier.ScalarCarrier):

module Main =
    let createAddOp (lhs:DataType.DataCarrier) (rhs:DataType.DataCarrier) =
        let clhs = Expression.Constant(lhs, typeof<DataType.DataCarrier>)
        let crhs = Expression.Constant(rhs, typeof<DataType.DataCarrier>)
        Expression.Add(clhs, crhs)

Another option would be to explicitly pass the addition operator to use:

module Main =
    let createAddOp (lhs:DataType.DataCarrier) (rhs:DataType.DataCarrier) =
        let clhs = Expression.Constant(lhs)
        let crhs = Expression.Constant(rhs)
        Expression.Add(clhs, crhs, typeof<DataType.DataCarrier>.GetMethod("op_Addition"))

I am surprised that your original code doesn't work, though. It appears to be a limitation in how expression trees find relevant add operators (that is, it appears that Linq only looks for add operators on the runtime types of operands).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文