F#使用自定义类创建集合

4

我正在尝试在我的一个类中使用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个回答

4
这里有一个应该能够工作的实现:
```html

以下是一个应该能够工作的实现:

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

太棒了,F# Power Pack中有实现活动记录模式的东西吗?如果可以直接继承它就太酷了。嗯,也许我会给这个类添加更多内容,并将其用作这样的模式。 - bhd739ge
你有没有考虑过使用字典而不是集合? - gradbot
@gradbot - 可能需要使用 HashSet 而不是 Dictionary。这些可变的 .Net 集合类型消除了对 IComparable 的需要,但仍需要 Equals() 和 GetHashCode()。 - Brian

1

我相信你需要实现IComparer<T>才能让集合推导(例如Set.of_list)正常工作。(不是IComparable<T>,后者往往使用较少 - 虽然我可能错了。)

这篇博客文章通俗地解释了如何在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中,所有这些比较接口真的很令人困惑!)


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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接