f# - 如何为受歧视的联盟覆盖 .Equals() ?

标签 f# overriding equality discriminated-union

我有一个可区分的联合类型,我想覆盖 .Equals()

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

下面的代码是我最好的尝试:

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

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

"The struct, record or union type 'ModelArg' has an explicit implementation of 'ObjectEquals'. Consider implementing a matching override for 'Object.GetHashCode'."

我想避免这样做,因为我真的只关心字段 Name 并且出于性能原因。

当然我可以写一个equals 函数,但是我不能将它与List 函数一起使用,比如List.contains 并且我需要这样做。

有什么建议吗?

最佳答案

错误告诉您,由于您正在覆盖 Equals 方法,所以最好也覆盖 GetHashCode

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

此外,错误消息并未建议您将 int 包含在相等定义中。它只是说您需要实现 GetHashCode,并按照与您的 Equals 实现相同的意义来实现。这样做也不会降低性能,只要您从未实际调用 GetHashCode。如果你这样做 - 见上文。

由于您所有的 Equals 实现都是比较 Name 字段,因此将 GetHashCode 委托(delegate)给同一字段可能是有意义的:

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

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

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

关于f# - 如何为受歧视的联盟覆盖 .Equals() ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51699291/

相关文章:

f# - 如何使用 websockets

f# - 如何在普通任务(不是 Task<T>)上使用 Async.AwaitTask?

c# - 如何检查两个字典是否包含相同的值?

list - F#中列表的子列表

Java匿名子类和常规(非匿名)子类的区别

java - 如何覆盖java变量并使变量成为必填字段

java - Java @Override 注释是否曾经需要/用于接口(interface)实现?

java - 如何根据来自不同 Java 类的字段比较 "equivalence"的两个集合?

c# - 检查两个对象的字段中是否包含相同的数据

f# - FSharpPlus : the fsi blocks when I try to combine two transformers