2

我有一个具有 2 个字段 ID 和名称的结构(结构)。然后我创建了这个结构的列表,但是每当我做一个包含它第一次将它添加到集合中时它就可以工作了,但是它不再工作了。为什么?它不是一个引用是一个结构。我想验证这是否不在列表中添加它。

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 来匹配 => X.ID 和 => X.NAME 但我不想要这个,因为我的结构实际上比这两个字段更复杂。

4

3 回答 3

4

使用Contains类必须覆盖bool Equals(object obj)(并且最好GetHashCode()也是)。因为您使用的是 astruct而不是类,所以我也建议实施 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;
        }
    }
}
于 2013-11-08T17:08:38.360 回答
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
于 2013-11-08T17:19:21.900 回答
1

而不是使用Contains你可以使用Any

if (!cars.Any(m => m.id == myCar.id))

现在,如果你的心是 on Contains,你需要实现IEquatable<MyCar>,因为Contains使用默认的;每个MSDN 文档

此方法通过使用默认的相等比较器来确定相等...

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再次使用。您需要仔细考虑,因为这意味着您实际上是在更改此类型的默认相等比较器。

于 2013-11-08T17:06:15.857 回答