在类型定义之外实现相等

时间:2011-03-10 22:31:18

标签: interface f# operator-overloading equality

我有几种实现接口的类型。这些类型的平等仅取决于接口成员。是否可以为这些类型定义一次,而不是为每种类型覆盖Equalsop_Equality

修改

我尝试了以下操作,但无论出于何种原因,它都会覆盖=的每次使用,即使对于未实现IEntity的类型也是如此。

[<AutoOpen>]
module Equality =
    let inline op_Equality (left:IEntity) (right:IEntity) = true

我也尝试使用灵活类型(#IEntity)。结果相同。

2 个答案:

答案 0 :(得分:2)

您尝试做的是mixins或类型类可能在其他语言中启用的内容;遗憾的是,F#中没有相同的功能。您最好的选择可能是以下选项之一:

  1. 使用抽象基类而不是接口。
  2. 在您的类型之外编写您的相等方法,然后让所有实现都遵循它。例如,

    let entityEquals (i1:IEntity) (i2:IEntity) =
      i1.Member1 = i2.Member1 &&
      i1.Member2 = i2.Member2 &&
      ...
    
    type MyEntity() =
      interface IEntity with
        member x.Member1 = ...
        ...
        override x.Equals(y) = 
          match y with
          | :? IEntity as y -> entityEquals x y
          | _ -> false
        override x.GetHashCode() =
          ...
    

    除了一些样板文件之外,这里的缺点是如果其他人实现了你的IEntity接口,他们就不会被迫使用你的相等方法 - 它是选择加入的。

  3. 创建另一个用于IEntity s:

    的等式测试的运算符
    let (==) (i1:IEntity) (i2:IEntity) =
      i1.Member1 = i2.Member1 &&
      ...
    

    这个(巨大的)缺点是包含IEntity的类型(如元组,记录等)的结构相等不会使用此运算符来比较这些组件,这很可能导致令人惊讶的破碎代码。

答案 1 :(得分:1)

我认为没有办法以静态的方式做到这一点。问题是扩展成员(例如,如果您添加op_Equality作为扩展名)被静态成员约束忽略(例如,如果您还重新定义了{{1}使用=inlin要求)。

F#编译器只有在编译FSharp.Core.dll时才有一些特殊功能可以提供帮助(搜索声明op_Equality的来源)。它使用类似静态类型切换的东西 - 但是凡人都无法访问它。

所以,我没有比使用动态类型测试更好的想法,这不是一个好方法,而且定义一个自定义运算符来比较你的接口可能更好。

作为参考,丑陋的动态方法是:

let inline GenericOne