F#使用自定义类设置

时间:2009-05-21 23:25:19

标签: f# set icomparable

我正在尝试将Set操作与我拥有的类一起使用。此类的每个实例都有一个唯一的ID。我是否需要实现System.IComparable接口?如果是,我将如何实现?

type SomeClass(id : int) =
    member this.ID = id

let someSet = Set.of_list [SomeClass(1); SomeClass(2)]
let test = someSet.Contains(SomeClass(2))    

3 个答案:

答案 0 :(得分:4)

这是一个应该有效的实现:

type SomeClass(id : int) =    
    member this.ID = id
    override this.Equals(o) =
        match o with
        | :? SomeClass as sc -> this.ID = sc.ID
        | _ -> false
    override this.GetHashCode() =
        id.GetHashCode()
    interface System.IComparable with
        member this.CompareTo(o) =
            match o with
            | :? SomeClass as sc -> compare this.ID sc.ID
            | _ -> -1

答案 1 :(得分:1)

我相信你需要实现IComparer<T>来设置理解(例如Set.of_list)才能工作。 ( IComparable<T>,虽然我可能错了,但往往使用不太广泛。)

这个blog post解释了如何在F#中实现接口。它还包含一个实现IComparer<T>的类型的特定示例,实际上并不像您希望的那样简单。

type Comp() =  
    interface IComparer with  
        member x.Compare(a, b) = 0  
    member x.Compare(a, b) = (x :> IComparer).Compare(a,b)  

如果有效,请告诉我。我怀疑你实际上可能需要实现IEqualityComparer<T>,因为据我所知,这就是LINQ集扩展方法的基础。 (在BCL中进行比较时,所有这些界面真的让人感到困惑!)

答案 2 :(得分:1)

关于我对其他答案的评论,您可以将其纳入可重用的基类,但我不确定这是一个好主意:

type EqCompBase<'EqKey, 
        'DerivedType when 'DerivedType :> EqCompBase<'EqKey,'DerivedType> >
        (id : 'EqKey) =    
    member this.ID = id
    override this.Equals(o) =
        match o with
        | :? EqCompBase<'EqKey, 'DerivedType> as sc -> this.ID = sc.ID
        | _ -> false
    override this.GetHashCode() =
        id.GetHashCode()
    interface System.IComparable with
        member this.CompareTo(o) =
            match o with
            | :? EqCompBase<'EqKey, 'DerivedType> as sc -> compare this.ID sc.ID
            | _ -> -1

type SomeClass(id : int, otherFieldThatDoesNotMatterForEquality : string) =
    inherit EqCompBase<int, SomeClass>(id)

let someSet = Set.of_list [SomeClass(1,"yadda"); SomeClass(2,"blah")]
let test = someSet.Contains(SomeClass(2,"foo"))
printfn "%A" test  // true