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
而我需要这样做。
有什么建议么?
该错误告诉您,由于您要覆盖该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)