区分联合成员方法

时间:2014-11-25 20:27:16

标签: inheritance f# discriminated-union

我想定义一个受歧视联盟的所有成员共享的方法。目前我已经像这样实现了它,但它似乎真的不太优雅 - 当然还有更好的方法。建议?

type A = 
   {AData:string}
   member this.SharedMethod (x:float) : int= ...
type B =
   {BData:float}
   member this.SharedMethod (x:float) : int= ...
type AB =
| A of A
| B of B

let CallSharedMethod (ab:AB) x =
   match ab with
   | AB.A(a') -> a'.SharedMethod x
   | AB.B(b') -> b'.SharedMethod x

2 个答案:

答案 0 :(得分:18)

这样的事情怎么样?

type AB =
    | A of string
    | B of float

    member self.SharedMethod (x : float) =
        match self with
        | A s -> x
        | B f -> f + x

这假设您希望sum类型的每个变体(也称为区别联合)使用float参数执行不同的操作。

对于A的情况,我只返回原始值,因为我无法做其他事情(因为stringfloat之间没有普遍有用的关系产生了float)。

答案 1 :(得分:8)

在您的示例中,您使用实例成员扩充 记录类型AB。但是,您不仅可以扩充记录类型,还可以扩充 union 类型(如@Rodrick的答案中所示)。如果你这样做,联盟的扩充将由每个DU案例“共享”,这就是你所要求的。为了使其更加明确,我已经重命名了您示例的某些部分:

type A = { AData:string }
type B = { BData:float }

type AB =
    | ACase of A
    | BCase of B
    member __.SharedMethod x = 0

let callSharedMethod (ab:AB) x = ab.SharedMethod x

如果查看对象浏览器(或ILSpy之类的反编译器)中的编译代码,您将看到AB被编译为两个子类AB.ACase和{{1}的基类},AB.BCase属于基类SharedMethod

另见F# 3.0 specification:联盟类型成员的第8.5.1节。