如何为受歧视的联盟覆盖 .Equals() ?
How does one override .Equals() for a 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# 中),散列码通常用作相等性的近似值。例如,如果您要将对象放入散列 table 中,散列 table 将根据 GetHashCode
在存储桶之间分配它们,并以这种方式在存储桶中查找它们.然后,如果 Equals
的实现方式与 GetHashCode
不同,散列 table 的行为将是不可预测的 table - 它可能无法查找刚刚插入的对象或类似的东西。
此外,错误消息并未建议您将 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()
最后,当使用 null
或其他类型的对象调用时,您的 Equals
实现会崩溃。如果您希望代码健壮,我建议您处理这种情况:
override this.Equals (o: obj) =
match o with
| :? ModelArg as ma -> this.Name = ma.Name
| _ -> false
我有一个受歧视的联合类型,想覆盖 .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# 中),散列码通常用作相等性的近似值。例如,如果您要将对象放入散列 table 中,散列 table 将根据 GetHashCode
在存储桶之间分配它们,并以这种方式在存储桶中查找它们.然后,如果 Equals
的实现方式与 GetHashCode
不同,散列 table 的行为将是不可预测的 table - 它可能无法查找刚刚插入的对象或类似的东西。
此外,错误消息并未建议您将 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()
最后,当使用 null
或其他类型的对象调用时,您的 Equals
实现会崩溃。如果您希望代码健壮,我建议您处理这种情况:
override this.Equals (o: obj) =
match o with
| :? ModelArg as ma -> this.Name = ma.Name
| _ -> false