【问题标题】:Can't get operator overloading to work with Linq Expression Trees无法让运算符重载以使用 Linq 表达式树
【发布时间】:2009-11-07 14:45:07
【问题描述】:

我正在从 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)))

【问题讨论】:

    标签: f# operator-overloading expression-trees


    【解决方案1】:

    一种解决方案是显式键入表达式操作数(给它们静态类型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 似乎只在操作数的运行时类型上查找加法运算符)。

    【讨论】:

    • 太棒了,我真的认为没有解决方法。你刚刚为我减轻了很多压力! +1 我认为这曾经在 F# 的 Oct CTP 之前工作过。我会做一些测试。
    猜你喜欢
    • 1970-01-01
    • 2019-05-29
    • 2017-02-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-28
    • 2011-09-16
    相关资源
    最近更新 更多