关于泛型:等效于F#ICastableTo <‘T>吗?

F# ICastableTo<'T> equivalent?

您不能在F#中实现通用接口的多个实例。在我的情况下,这真是令人b目结舌,因为我计划实现一个称为ICastableTo <'T>的接口,该接口可用于模式匹配:

1
2
3
4
5
6
7
8
9
10
11
type ICastableTo<'T> =
    /// <summary>
    /// Returns a casted version of the object
    /// </summary>
    member this.Value : 'T

...
(*x:obj*)
match x with
| :? ICastableTo<SomeType> as x -> doSomethingWith(x.Value)
| _ -> invalidOp("can't cast like that")

但是,当我尝试实际使用它时,由于无法实现ICastableTo接口的多种版本(请参阅在不同的泛型实例上实现相同的接口),我遇到了一个问题,但是我的某些类实际上可以转换为不止一种类型。

在这里,我最好的选择是什么?我当然可以定义一个ICastable接口并使用一个" PossibleCasts"属性,该属性将公开所有可用的强制转换委托,但它不是非常漂亮,并且不能很好地继承。

这是我的代码:

1
2
3
4
5
type BindableFunction<'T,'V>(func : 'T -> 'V) =
    member val Parent : 'T = nothing with get, set
    interface Specializable with
        member SpecializeFor(x: obj) =
            match x with | :? ICastable<'T> as x -> Parent <- x.Value | _ -> invalidOp("")

然后是我的可转换班。例如,我有一个TCell类,该类具有对Cell(组合)的引用,因此可以将其强制转换为Cell以实现功能绑定,即使这两种类型之间没有继承链接。

我认为我最终要做的是生成非匹配的" match x with | ICastable <'T>"(aka,我将使用ICastableOf_Cell并使用Reflection找到良好的接口(按名称获取类型) ),然后使用Reflection.Emit。

生成代码

另一种选择是为BindableFunction提供两种泛型类型,一种为值类型,另一种为ICastableOf_Cell,这也许是一个更好的主意,但会使我的代码在各个地方更加冗长。


最后,我采用了以下方法:

1
2
3
4
5
6
7
type BindableFunction<'T,'V>(convert: obj -> 'T, func : 'T -> 'V) =
    member val Parent : 'T = nothing with get, set
    interface Specializable with
        member SpecializeFor(x: obj) =
            match x with
            | :? 'T as x -> (Parent <- x)
            | _          -> (Parent <- convert(x))

这允许我为每种类型使用唯一的接口,因此不使用通用的接口。

1
let CastToCell = ref(fun(o:obj) -> match o with | :? ICellScope as o -> o.ICell.Cell | _ -> invalidOp("invalid scope conversion"))

最后:

1
new BindableFunction<Cell,_>(!CastToCell,...)