简体   繁体   English

F#ICastableTo <'T等效?

[英]F# ICastableTo<'T> equivalent?

You can't implement multiple instances of a generic interface in F#. 您无法在F#中实现通用接口的多个实例。 This is a bummer in my case, because I had a plan to implement an interface called ICastableTo<'T> that could be used for pattern matching: 在我的情况下,这是一个无赖,因为我计划实现一个名为ICastableTo <'T的接口,可用于模式匹配:

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")

However, when I tried to actually use this, I face an issue because I can't implement mulitple version of the ICastableTo interface (see Implementing the same interface at different generic instantiations ), yet some of my classes are actually castable to more than one type. 但是,当我尝试实际使用它时,我遇到了一个问题,因为我无法实现ICastableTo接口的多个版本(请参阅在不同的通用实例中实现相同的接口 ),但我的一些类实际上可以转换为多个类型。

What would be my best option here? 这里最好的选择是什么? I could of course define an ICastable interface and use a "PossibleCasts" property that would expose all available casting delegates but that's not super beautiful and does not play that well with inheritance. 我当然可以定义一个ICastable接口,并使用一个“PossibleCasts”属性来公开所有可用的转换委托,但这并不是非常漂亮,并且在继承方面表现不佳。


Here's what my code looks like: 这是我的代码的样子:

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("")

and then I've my castable classes. 然后我有我的可投手课程。 For example, I've a TCell class that has a reference to a Cell (composition) and can therefore be casted into a Cell for the purpose of function binding, even if there's no inheritance link between the two types. 例如,我有一个TCell类,它具有对Cell(组合)的引用,因此可以将其转换为Cell以进行函数绑定,即使这两种类型之间没有继承链接。

I think what I will end up doing is generating the "match x with | ICastable<'T>" to be non-generic (aka, I'll use ICastableOf_Cell and find the good interface using Reflection (get type by name) and then generate the code using Reflection.Emit. 我认为我最终要做的是生成“匹配x与| ICastable <'T>”是非泛型的(也就是说,我将使用ICastableOf_Cell并使用Reflection找到好的界面(按名称获取类型)然后使用Reflection.Emit生成代码。

The other option would be to give the BindableFunction two generic types, one being the value type, and the other one ICastableOf_Cell, which is maybe a better idea but would make my code more verbose at various places. 另一个选择是给BindableFunction两个泛型类型,一个是值类型,另一个是ICastableOf_Cell,这可能是一个更好的主意,但会使我的代码在各个地方更加冗长。

Finally, I went for the following approach: 最后,我采用了以下方法:

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))

This allows me to use unique interfaces per type, and therefore not use a generic interface. 这允许我使用每种类型的唯一接口,因此不使用通用接口。

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

with finally: 最后:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM