簡體   English   中英

列出自定義類的相等性

[英]List equality of a custom class

我有一個類A ,它擁有一個字符串屬性並覆蓋Equals以進行相等性測試。

public class A
{
    public string Prop { get; }

    public A(string val)
    {
        Prop = val;
    }

    public override bool Equals(object obj)
    {
        return obj is A arg && (Prop == arg.Prop);
    }

    public override int GetHashCode()
    {
        return base.GetHashCode();
    }
}

我也有一個B類,它具有List<A>作為屬性:

public class B
{
    public IReadOnlyList<A> Prop { get; }

    public B(IReadOnlyList<A> val)
    {
        Prop = val;
    }

    public override bool Equals(object obj)
    {
        // ...
    }

    public override int GetHashCode()
    {
        return base.GetHashCode();
    }
}

我希望能夠與B實例進行比較,以了解其平等性和秩序。 如何通過不重寫在A中編寫的相同代碼來在B中編寫Equals方法? 有沒有辦法重用“等於”?

更新:我的第一個版本假設B是從A派生A

  1. A.EqualsA.Equals

如果未密封A ,則obj is A ...如果比較不同的類型,則可以返回假陽性。 因此,更正的版本:

public override bool Equals(object obj)
{
    return obj is A other
        && this.Prop == other.Prop
        && this.GetType() == other.GetType(); // not needed if A is sealed
}
  1. A.GetHashCode

base.GetHashCode將為不同但相等的實例返回不同的哈希碼,這是錯誤的。 而是從自身屬性派生哈希碼。 如果Prop行為類似於某些ID,則只需返回Prop.GetHashCode()

  1. B.Equals
    public override bool Equals(object obj)
    {
        return obj is B other
            && this.Prop.SequenceEqual(other.Prop) // will re-use A.Equals
            && this.Prop.GetType() == other.Prop.GetType() // not needed if different IReadOnlyList types are ok
            && this.GetType() == other.GetType(); // not needed if B is sealed
    }
  1. B.GetHashCode

您可以匯總A實例的哈希碼。 在這里,我使用一個簡單的XOR,但是如果相同的項目通常可以以不同的順序出現,那么您可以想出一些更奇特的東西。

return Prop.Aggregate(0, (h, i) => h ^ i.GetHashCode());

Linq包含一個比較集合的有用方法: SequenceEqual

public override bool Equals(object obj)
{
    if (!(obj is B other))
    {
        return false;
    }

    if (this.Prop == null || other.Prop == null)
    {
        return false;
    }

    return this.Prop.SequenceEqual(other.Prop);
}

另外,重寫Equals時,請實現IEquatable<T>

實施Equals為列表可以通過使用來完成SequenceEquals方法(從System.Linq命名空間),這保證了在一個列表中的每個項目中的其他列表中的同一索引處等於的項目。

您可能會考慮更改的一件事是GetHashCode的實現。 如果兩個項目相等,則此方法應返回相同的數字(盡管不能保證具有相同哈希碼的兩個項目相等)。 使用base.GetHashCode()不滿足此要求,因為在這種情況下, baseobject 根據文檔“用於引用類型的哈希碼是通過調用基類的Object.GetHashCode方法來計算的,該方法基於對象的引用來計算哈希碼” ,因此,如果對象引用的是完全相同的哈希值,則它們僅返回相同的HashCode同一對象。

HashCode應該基於用於確定相等性的相同屬性,因此在這種情況下,我們要為類A使用Prop.GetHashCode() ,並且要為類B Prop所有項目聚合哈希碼。

這是可以重構類的一種方法:

public class A : IEquatable<A>
{
    public string Prop { get; }

    public A(string val)
    {
        Prop = val;
    }

    public bool Equals(A other)
    {
        if (other == null) return false;
        return Prop == other.Prop;
    }

    public override bool Equals(object obj)
    {
        return Equals(obj as A);
    }

    public override int GetHashCode()
    {
        return Prop.GetHashCode();
    }
}

public class B : IEquatable<B>
{
    public IReadOnlyList<A> Prop { get; }

    public B(IReadOnlyList<A> val)
    {
        Prop = val;
    }

    public bool Equals(B other)
    {
        if (other == null) return false;
        if (ReferenceEquals(this, other)) return true;
        if (Prop == null) return other.Prop == null;
        return other.Prop != null && Prop.SequenceEqual(other.Prop);
    }

    public override bool Equals(object obj)
    {
        return Equals(obj as B);
    }

    public override int GetHashCode()
    {
        return Prop?.Aggregate(17,
            (current, item) => current * 17 + item?.GetHashCode() ?? 0)
                ?? 0;
    }
}

這樣的事情怎么樣:

public override bool Equals(object obj)
{
    if(!(obj is B))
    {
        return false;
    }

    var b = obj as B;

    if(b.Prop.Count != this.Prop.Count)
    {
        return false;
    }

    for(var i =0; i < Prop.Count; i++)
    {
        if (!Prop.ElementAt(i).Equals(b.Prop.ElementAt(i)))
        {
            return false;
        }
    }

    return true;
}

暫無
暫無

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

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