一个受歧视的联盟如何覆盖.Equals()?

Sol*_*lma 3 f# overriding equality discriminated-union

我有一个已区别的联合体类型,并且想要覆盖.Equals()

在这个简单的示例中,我可以使用.Equals函数int解决问题,但是在我的代码中otherStuff不支持结构比较。

以下代码是我的最佳尝试:

[<CustomEquality>]
type ModelArg = { Name: string; OtherStuff: int}
    with override this.Equals (o: obj) = this.Name = (o :?> ModelArg).Name
Run Code Online (Sandbox Code Playgroud)

然后,我得到一条红色的波浪线和以下消息:

"The struct, record or union type 'ModelArg' has an explicit implementation of 'ObjectEquals'. Consider implementing a matching override for 'Object.GetHashCode'."
Run Code Online (Sandbox Code Playgroud)

我想避免这样做,因为我确实只关心该领域Name,而且出于性能原因。

当然,我可以编写一个equals函数,但无法将其与List类似的函数一起使用,List.contains而我需要这样做。

有什么建议么?

Fyo*_*kin 5

该错误告诉您,由于您要覆盖该Equals方法,因此也应该重写该方法GetHashCode

这样做的原因是,通常在.NET中(不仅仅是在F#中),哈希码通常用作等式的近似值。例如,如果您要将对象放在哈希表中,则哈希表将根据来在存储桶之间分配对象GetHashCode,并且也会以这种方式在存储桶中查找它们。然后,如果Equals实现方式不同于GetHashCode,则哈希表的行为将不可预测-可能无法查找刚刚插入的对象或类似对象。

此外,错误消息并不建议您在相等的定义中包括int。它只说明您需要实现GetHashCode,并且必须以与实现相同的意义来Equals实现。只要您从不实际致电,这样做也不会影响性能GetHashCode。如果您愿意-见上文。

由于您的所有Equals实现都是对Name字段进行比较,因此委派GetHashCode到同一字段可能也很有意义:

[<CustomEquality>]
type ModelArg = { Name: string; OtherStuff: int}
    with 
       override this.Equals (o: obj) = this.Name = (o :?> ModelArg).Name
       override this.GetHashCode() = this.Name.GetHashCode()
Run Code Online (Sandbox Code Playgroud)

最后,Equals当用null或另一个类型的对象调用时,您的实现会崩溃。如果您希望代码健壮,我建议您处理这种情况:

       override this.Equals (o: obj) = 
           match o with 
           | :? ModelArg as ma -> this.Name = ma.Name
           | _ -> false
Run Code Online (Sandbox Code Playgroud)