簡體   English   中英

從 C# 使用時 F# 記錄類型的相等性

[英]Equality of F# record Types when consumed from C#

我在 F# 庫中有以下記錄類型:

type Rating = {
        Id : string
        AverageRating : decimal
        ValueRange : int
        Label : string }

正如預期的那樣,以下測試在 F# 測試庫中通過:

[Fact]
let ``ShouldConsiderTwoInstancesOfAClassToBeTheSame`` () =

    let a = {Rating.Id = "id"
             AverageRating = 4.3m
             ValueRange = 10
             Label = "label"}

    let b = {Rating.Id = "id"
             AverageRating = 4.3m
             ValueRange = 10
             Label = "label"}

    a = b |> should equal true
    a.Equals b |> should equal true
    a <> b |> should equal false
    System.Object.ReferenceEquals(a, b) |> should equal false

但是,C# 中的以下測試失敗了......前兩個斷言都失敗了,盡管第三個斷言通過了:

    [Test]
    public void ShouldConsiderTwoInstancesOfAClassToBeTheSame()
    {
        var a = new Rating("id", 4.3m, 10, "label");
        var b = new Rating("id", 4.3m, 10, "label");

        Assert.True(a == b);
        Assert.False(a != b);
        Assert.True(a.Equals(b));
        Assert.False(ReferenceEquals(a, b));
    }

在僅使用運算符從 C# 消費時,有沒有辦法獲得記錄類型提供的開箱即用的結構相等性,或者您是否需要調用 Equals() ?

在慣用的 C# 中,引用類型預計不會對結構相等性進行正面測試。 IEquatable作為契約具有更多的語義意義。

默認情況下,相等意味着引用相等 F# 在這方面完全不同 - 它使用結構相等進行比較。 如果您查看 F# 為a = b所做的事情,它會調用

a.Equals(b, GenericEqualityComparer);

但是,對於實現了==運算符的類型,C# 編譯器知道選擇運算符的方法。

push.0 //ldloc, ldfld, etc.
push.1
call bool Rating::op_Equality(valuetype Rating, valuetype Rating)

a == b通常發生的情況是:

push.0
push.1
ceq

ceq比任何方法調用替代方案都快得多,並且是默認的相等比較,它為您提供引用相等。

其他核心 .NET 類型可能沒有顯式實現==!= ,但 JIT 具有特定的實現細節來對這些內部類型(有符號、fp 等)執行相等比較,因此它們仍然正確等同。

如果==比較在語義上對您很重要,您可以自己實現運算符:

type Rating = {
    Id : string
    AverageRating : decimal
    ValueRange : int
    Label : string 
} with
    static member op_Equality (a: Rating, b: Rating) =
      a.Equals b
    static member op_Inequality (a: Rating, b: Rating) =
          not (a.Equals b)

並且您的測試應該可以再次運行。

為了讓==在 C# 中工作,有問題的類需要實現 == 運算符

bool operator ==(Rating a, Rating b) => ...

如果查看生成的用於評級的 IL 代碼,您會看到它實現了IEquatable<T>, IComparable<T>, GetHashCode()等,但我沒有看到運算符實現。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM