首页 > 解决方案 > 为什么这两个同类型的F#类对象不相等?

问题描述

有人可以向我解释为什么这两个对象不相等,处理这些问题的解决方案是什么?

[<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

标签: .net.net-coref#

解决方案


这就是 .NET 中相等的工作原理:默认情况下,除非您自己实现比较方法,否则相等是“通过引用”的——也就是说,每个对象都只与自身相等,不与其他对象相等。

对于许多标准库类型,例如字符串,实际上已经实现了比较方法。这就是为什么相等的字符串是相等的,即使它们不是同一个对象。但是对于您自己滚动的类型,您必须实现您认为合适的比较方法。

对于您在这里尝试做的事情,您想要的方法是Equals. 这是该System.Object类型的一个虚方法,默认情况下它按照上述方式工作:每个对象都只与它自己相等。但是您可以为您的类型覆盖它:

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

现在,比较将按照您期望的方式进行。但是您也会收到一条警告,要求您也实施GetHashCode。这是因为 .NET 库中的许多标准容器(例如DictionaryHashtable)期望相等的对象也具有相同的哈希值,如果您的对象不这样做,则可能无法正常工作。我将把执行GetHashCode留作练习。有关更多信息,请参阅文档


但由于您使用的是 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# 记录默认具有“结构相等”(即当所有字段相等时,两条记录相等),由编译器为您实现,但它们还提供其他好处,例如更短的语法、默认不变性、功能更新语法、模式匹配、类型推断等。强烈推荐。


推荐阅读