简体   繁体   English

F# class 这两个同类型的对象为什么不相等呢?

[英]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 库中的许多标准容器(例如DictionaryHashtable )期望相等的对象也具有相同的 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM