我正在使用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)))
答案 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运算符)。