从 HashSet 中获取不同的值

Get distinct values from HashSet

我只想从 HashSet 中获取不同的值,我已经实现了 IEquatableIEqualityComparer,但仍然无法获取不同的值。

class Program
{
    static void Main(string[] args)
    {

        HashSet<Item> items = new HashSet<Item>()
        {
            {new Item("item1")},
            {new Item("item2")},
            {new Item("item3")},
            {new Item("item1")}
        };

        foreach (var item in items.Distinct())
        {
            Console.WriteLine(item.Name);
        }

        Console.ReadKey();

    }
}


class Item : IEquatable<Item>, IEqualityComparer<Item>
{
    public string Name { get; set; }
    public Item(string name)
    {
        this.Name = name;
    }

    public bool Equals(Item other)
    {
        return this.Name.Equals(other.Name);
    }

    public bool Equals(Item x, Item y)
    {
        return x.Equals(y);
    }

    public int GetHashCode(Item obj)
    {
        return this.Name.GetHashCode();
    }
}

控制台输出:

item1
item2
item3
item1

谢谢!

如果您只有一个实现来定义 class 的相等性,那么(正确地)实现 IEquatable<T> 就足够了。您也不应该实施 IEqualityComparer<T> 。后者的意思是,通常在一个单独的 class 中,当你想提供多种方法来定义一个类型的两个元素之间的唯一性时。

除此之外,您 GetHashCode 的方法签名是错误的。目前,它遵循 object.Equals 而不是您的自定义实现。

您需要将 override 关键字添加到 GetHashCode 实现中,并从签名中删除 Item obj

public override int GetHashCode()
{
    return this.Name.GetHashCode();
}

并覆盖 object.Equals 以及使用您的 Equals(item other):

public override bool Equals(object obj)
{
    if (ReferenceEquals(null, obj)) return false;
    if (ReferenceEquals(this, obj)) return true;
    if (obj.GetType() != this.GetType()) return false;
    return Equals((Item) obj);
}

public override bool Equals( 您不需要在 HashSet<T> 上调用 Distinct() 因为它本身保证了其内部集合的唯一性,前提是您提供了适当的 IEquatable<T> 覆盖或为其提供了 IEqualityComparer<T>.

From the docs of HashSet<T>.Add:

Return Value:

Type: System.Boolean true if the element is added to the HashSet object; false if the element is already present.

首先,您应该将 IEqualityComparer<T> 作为一个单独的 class 实现,并且您需要在 HashSet<T> 构造期间提供整个相等比较器:

var set = new HashSet<CustomClass>(new CustomClassEqualityComparer());

如果您采用相等比较器方式,则不会被迫实施 IEquatable<T>:

public class ItemEqualityComparer : IEqualityComparer<Item>
{
    public bool Equals(Item x, Item y)
    {
        return x.Name == y.Name;
    }

    public int GetHashCode(Item obj)
    {
        return obj.Name.GetHashCode();
    }
}

此外,您可以设计许多 IEqualityComparer<T> 实现来涵盖许多可以为同一对象定义不同唯一性含义的用例(即 Item)。

如果您提供 IEqualityComparer<T> 的良好实现,您将不需要 Distinct,因为 HashSet<T>set 而这意味着它是唯一元素的无序集合,整个 set 将使用您的相等比较器来检查 set 中是否存在给定元素(因此,所有元素在同一个集合中都是唯一的!)。