从HashSet获取不同的值

时间:2015-07-29 13:57:17

标签: c# 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

谢谢!

2 个答案:

答案 0 :(得分:3)

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

除此之外,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( 您无需在Distinct()上调用HashSet<T>,因为它本身可以保证其内部集合的唯一性,因为您提供了正确的IEquatable<T>覆盖或为其提供{{1} }}

From the docs of HashSet<T>.Add

  

返回值:

     

类型:System.Boolean如果元素已添加到,则为true   HashSet对象;如果元素已经存在,则返回false。

答案 1 :(得分:2)

首先,您应该将IEqualityComparer<T>实现为一个单独的类,并且需要在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>,这意味着它是无序的独特元素的集合,整个将使用您的等式比较器来检查给定元素是否存在于中(因此,所有元素在同一个元素中都是唯一的< EM>设置!)。