[英]Why are these two F# class objects of the same type not equal?
Can someone explain to me why these two objects are not equal, and what is the solution for handling such concerns?有人可以向我解释为什么这两个对象不相等,处理此类问题的解决方案是什么?
[<AllowNullLiteralAttribute>]
type Duration (id, startDate, endDate) =
member val DbId : string = id with get,set
member val StartDate : Nullable<DateTime> = startDate with get,set
member val EndDate : Nullable<DateTime> = endDate with get,set
new () =
Duration(null, System.Nullable(), System.Nullable())
[<AllowNullLiteralAttribute>]
type ProductMedium (mediumType, fileLink, duration) =
member val MediumType : string = mediumType with get,set
member val FileLink : string = fileLink with get,set
member val Duration : Duration = duration with get,set
new () =
ProductMedium (null, null, null)
let medium1 = new ProductMedium("Type1", null, null)
let medium2 = new ProductMedium("Type1", null, null)
medium1 = medium2 // returns false
That's just how equality in .NET works: by default, unless you implement comparison methods yourself, equality is "by reference" - that is, every object is equal only to itself and to nothing else.这就是 .NET 中相等性的工作原理:默认情况下,除非您自己实现比较方法,否则相等性是“通过引用”——也就是说,每个 object 只等于它自己,而不等于其他任何东西。
For many standard library types, such as strings, comparison methods are, in fact, implemented.对于许多标准库类型,例如字符串,实际上已经实现了比较方法。 That's why equal strings are equal, even if they're not the same object. But for types that you roll yourself you have to implement the comparison methods as you see fit.
这就是为什么相等的字符串是相等的,即使它们不相同 object。但是对于您自己滚动的类型,您必须实现您认为合适的比较方法。
For what you're trying to do here, the method you want is Equals
.对于您要在此处执行的操作,您需要的方法是
Equals
。 This is a virtual method on the System.Object
type, and by default it works the way described above: every object is equal only to itself.这是
System.Object
类型的虚方法,默认情况下它按上述方式工作:每个 object 只等于它自己。 But you can override it for your type:但是您可以为您的类型覆盖它:
type ProductMedium (mediumType, fileLink, duration) =
member val MediumType : string = mediumType with get,set
member val FileLink : string = fileLink with get,set
member val Duration : string = duration with get,set
override this.Equals(other) =
match other with
| :? ProductMedium as p ->
this.MediumType = p.MediumType && this.FileLink = p.FileLink && this.Duration = p.Duration
| _ ->
false
Now the comparison will work the way you expect it to.现在比较将按照您期望的方式进行。 But you will also get a warning asking you to implement
GetHashCode
as well.但是您也会收到一条警告,要求您也实施
GetHashCode
。 This is because many standard containers in the .NET library (such as Dictionary
or Hashtable
) expect equal objects to also have the same hash and may not work correctly if your objects don't do this.这是因为 .NET 库中的许多标准容器(例如
Dictionary
或Hashtable
)期望相等的对象也具有相同的 hash 并且如果您的对象不这样做则可能无法正常工作。 I will leave the implementation of GetHashCode
as an exercise.我将把
GetHashCode
的实现留作练习。 See documentation for more info.有关详细信息,请参阅文档。
But since you're using F#, you actually have a better option available to you: don't use regular .NET classes, use F# records instead:但是由于您使用的是 F#,您实际上有一个更好的选择:不要使用常规的 .NET 类,而是使用 F# 记录:
type ProductMedium = { MediumType : string; FileLink : string; Duration : string }
let medium1 = { MediumType = "Type1"; FileLink = null; Duration = null }
let medium2 = { MediumType = "Type2"; FileLink = null; Duration = null }
F# records have "structural equality" (ie two records are equal when all their fields are equal) by default, implemented for you by the compiler, but they also provide other benefits, such as much shorter syntax, immutability by default, functional update syntax, pattern-matching, type inference, and more. F# 记录在默认情况下具有“结构相等”(即两条记录在所有字段都相等时相等),由编译器为您实现,但它们还提供其他好处,例如更短的语法、默认不变性、功能更新语法、模式匹配、类型推断等。 Highly recommend.
极力推荐。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.