List包含始终为false C#

时间:2013-11-08 17:03:54

标签: c# .net list

我有一个带有2个fiels ID和Name的结构(struct)。然后我创建了一个这个结构的列表但是无论何时我做了一个包含它的工作是第一次将它添加到集合中但是它不再起作用了。为什么?它不是一个结构的引用。我想验证这是否不在列表中添加它。

public struct MyCar
{
    public int id { get; set; }
    public string name { get; set; }
}

List<MyCar> cars = new List<MyCar>();
MyCar myCar = new MyCar();
myCar.id = 1;
myCar.name = "a";
if(cars.Contains(myCar) == false)                
{
    cars.Add(myCar);
}
myCar = new MyCar();
myCar.id = 2;
myCar.name = "b";
if(cars.Contains(myCar) == false)                
{
    cars.Add(myCar);
}
myCar = new MyCar(); //Wrong. Duplicate and it's gonna be added again because Contains == false
myCar.id = 1;
myCar.name = "a";
if(cars.Contains(myCar) == false)                
{
    cars.Add(myCar);
}

也许我可以使用Find来匹配=&gt; X.ID和=&gt; X.NAME但我不想要这个,因为我的结构实际上比这两个字段更复杂。

3 个答案:

答案 0 :(得分:4)

要使用Contains类,必须覆盖bool Equals(object obj)(并且还需要GetHashCode()}。因为您使用的是struct而不是类,我会建议使用IEquateable;

public struct MyCar : IEquatable<MyCar>
{
    public int id { get; set; }
    public string name { get; set; }

    private static readonly StringComparer stringComparer = StringComparer.Ordinal;

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

    public bool Equals(MyCar car)
    {
        return this.id.Equals(car.id) && stringComparer.Equals(this.name,car.name);
    }

    public override int GetHashCode()
    {
        unchecked
        {
            int i = 17;
            i = i * 23 + id.GetHashCode();
            i = i * 23 + stringComparer.GetHashCode(name);
            return i;
        }
    }
}

答案 1 :(得分:1)

您可以使用Contains

,而不是使用Any
if (!cars.Any(m => m.id == myCar.id))

现在,如果您的心脏设置在Contains,则需要实施IEquatable<MyCar>,因为Contains使用默认值;每MSDN Documentation

  

此方法使用默认的相等比较器...

确定相等性
public struct MyCar : IEquatable<MyCar>
{
    public int id { get; set; }
    public string name { get; set; }

    public bool Equals(MyCar other)
    {
        return this.id == other.id;
    }

    public override bool Equals(object obj)
    {
        if (!(obj is MyCar)) { return false; }
        return o.id == this.id;
    }

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

通过实现该界面,您现在可以再次使用Contains。你需要考虑到这一点,因为这意味着你实际上正在改变这种类型的默认相等比较器。

答案 2 :(得分:1)

我原本期望Equals运算符可以作为答案,但是当我在.NET 4中的控制台应用程序中进行测试时,我甚至没有得到错误条件 - 可能是默认的ValueType.Equals比较所有字段无论如何。那么你在哪里运行它来得到这个错误?

        var a = new MyCar() { id = 1, name = "a" };
        var b = new MyCar() { id = 1, name = "a" };

        var x = new List<MyCar>();

        x.Add(a);

        Console.WriteLine(a.Equals(b));
        Console.WriteLine(x.Contains(a));
        Console.WriteLine(x.Contains(b)); //all 3 are true