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

时间:2009-11-07 14:45:07

标签: f# operator-overloading expression-trees

我正在使用F#创建Linq表达式树,它运行在我自己的自定义数据类型上。该类型是一个非常简单的区分联合,具有通常的算术运算符重载。但由于某些原因,我无法创建算术linq表达式节点,因为它无法找到正确的重载。事情是,我发誓我前段时间有这个工作,但我无法弄清楚我改变了什么让它休息。

我会附上一个显示问题的小代码示例。下面的数据类型使Addition运算符重载。使用重载运算符就像魅力一样,但是当我尝试使用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)))

1 个答案:

答案 0 :(得分:3)

一种解决方案是显式键入Expression操作数(为它们提供静态类型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"))

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