簡體   English   中英

在用戶定義的對象列表上,Distinct() 沒有按預期工作,也沒有調用 Equals 方法

[英]Distinct() not working as expected, and not calling Equals method, on a List of user defined objects

我已經創建了自己的 Tuple 定義,以便我可以對 Equals 方法有自己的定義,其中 (1, 3) 等於 (3, 1)。 代碼如下。

public struct Tuple : IEquatable<object>
{
    public int Item1 { get; set; }
    public int Item2 { get; set; }


    public Tuple(int item1, int item2)
    {
        this.Item1 = item1;
        this.Item2 = item2;
    }

    public override bool Equals(object obj)
    {
        if (obj == null)
        {
            return false;
        }

        if (Object.ReferenceEquals(this, obj))
            return true;

        Tuple other;
        if (obj is Tuple)
        {
            other = (Tuple)obj;
        }
        else
        {
            return false;
        }

        if (this.Item1 == other.Item1 && this.Item2 == other.Item2
          || this.Item1 == other.Item2 && this.Item2 == other.Item1)
        {
            return true;
        }

        return false;
    }

    public override int GetHashCode()
    {
        int hash = 13;
        hash = (hash * 7) + Item1.GetHashCode();
        hash = (hash * 7) + Item2.GetHashCode();
        return hash;
    }

    public static bool operator ==(Tuple left, Tuple right)
    {
        return left.Equals(right);
    }

    public static bool operator !=(Tuple left, Tuple right)
    {
        return !(left == right);
    }
}

但是當我在元組列表上運行 distinct 時,它不使用我對 Equals 的定義。 例如,在頂點變量上,如下所示:

List<Tuple> vertices

我願意:

var distinctVertices = vertices.Distinct();

它確實檢查不同的值,但它沒有通過我的 Equals 定義,因此在我上面描述的情況下不起作用。 知道我可能做錯了什么嗎?

首先,您可能想要實現IEquatable<Tuple> ,而不是IEquatable<object> - Tuple : IEquatable<Tuple>


其次,可變struct上的相等是一個糟糕的想法; 我強烈建議您使用:

public readonly struct Tuple : IEquatable<Tuple>
{
    public int Item1 { get; }
    public int Item2 { get; }
    public Tuple(int item1, int item2)
    {
        Item1 = item1;
        Item2 = item2;
    }
    ...
}

第三,您的EqualsGetHashCode必須一致。 如果順序對Equals不重要,則對GetHashCode不重要。 只考慮:

public override int GetHashCode() => Item1 ^ Item2;

或其他與訂單無關的東西。


最后,您的Equals可能可以簡化:

public override bool Equals(object obj) => obj is Tuple other && Equals(other);
public bool Equals(Tuple other)
    => (Item1 == other.Item1 && Item2 == other.Item2)
    || (Item1 == other.Item2 && Item2 == other.Item1);

看看Distinct 文檔中的這個注釋:

該方法是通過使用延遲執行來實現的。 立即返回值是一個存儲執行操作所需的所有信息的對象。 在通過直接調用其 GetEnumerator 方法或在 Visual C# 中使用 foreach 或在 Visual Basic 中使用 For Each 來枚舉對象之前,不會執行此方法表示的查詢。

這意味着,在您枚舉結果之前,在過濾序列方面不會發生任何事情。

如果您對結果執行foreach或添加ToList ,即:

var distinctVertices = vertices.Distinct().ToList();

或者

foreach(var vertice in distinctVertices)
{
    // optionally do something here
}

然后你會看到你的Equals方法被執行。

暫無
暫無

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

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