C# - List<T>.Remove()总是删除列表中的第一个对象

5
在Visual Studio 2008(C#)中工作时,我使用List集合来存储我的自定义类(Shift)的实例。我想通过使用Remove方法从列表中删除某个班次。但是,List.Remove()总是删除它找到的第一项。为此,我已经实现了Shift的IComparable接口,我认为这应该足够了,然后我添加了IEqualityComparer的实现,但仍然没有效果。以下是我的实现摘录:

region IComparable Members

    public int CompareTo(object obj)
    {
        Shift s1 = this;
        Shift s2 = (Shift)obj;
        if (s1.start.time != s2.start.time)
            return s1.start.CompareTo(s2.start);
        else
            return s1.end.CompareTo(s2.end);
    }

endregion

region IEqualityComparer Members

    public bool Equals(Shift x, Shift y)
    {
        
        if ((x.opening) != (y.opening)) return false;
        if ((x.closing) != (y.closing)) return false;
        if (!x.opening) if (x._start != y._start) return false;
        if (!x.closing) if (x._end != y._end) return false;
        if (x.when != y.when) return false;
        if (x.day != y.day) return false;
        if (x.EmployeeID != y.EmployeeID) return false;
        return true;
    }

    public int GetHashCode(Shift obj)
    {
        return obj.ToString().ToLower().GetHashCode();
    }

endregion

然而,当列表包含两个班次时,比如“8:00-15:00”和“12:00-16:00”,调用Remove("12:00-16:00")会导致“8:00-15:00”被删除,而后面的班次仍留在集合中!

这里出了什么问题?谢谢。

4个回答

10

你可以覆写 object.GetHashCodeobject.Equals

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

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

Equals(x, y)中,你也应该进行空值检查。


如果 obj.GetType() != GetType(),你也应该返回 false,否则你可能会针对具有更精细算法的子类进行相等性检查。 - Bryan Watts
-1,他没有重载object.GetHashCode(),而是实现了IEqualityComparer<T>.GetHashCode(T)。 - csharptest.net
顺便说一句,我觉得他只是误解了List.Remove()的行为,以为它会执行List.RemoveAll()(请看下面我的回答)。 - csharptest.net
OIC,谢谢提醒。听起来好像是要删除他想要删除的几个中的“第一个”。困惑如果他使用默认的引用相等性,我不确定它是如何删除任何东西的。无论如何,听起来他现在正在工作。 - csharptest.net

4

IComparable通常不用于比较相等性(它用于排序),因此List<T>.Remove()会忽略它。

IEqualityComparer并不是用于相等性目的的IComparable的等价物。它应该由一个比较器对象实现 - 也就是说,一个比较其他对象相等的对象。如果你想让相等比较固有于你的类中,那么你需要实现IEquatable<T>。或者只需在你的类上覆盖Object.Equals()Object.GetHashCode(),而不实现任何接口。


其实 Object.Equals() 很好用!这似乎是最简单的选项。谢谢。 - Konrad Morawski

1

使用EqualityComparer<T>.Default来确定相等性并选择要删除的对象,如果您的对象实现了IEquatable<T>,则会使用它,否则将使用引用相等性。

你有两个选项可以获得想要的行为:

1) 使Shift实现IEquatable<T>(不仅覆盖Object.Equals或制作该方法,而是使Shift-Shift:IEquatable <Shift>

2) 使用List<T>.RemoveAt


0

根据您提供的示例,您正在调用:

List<Shift>.Remove("12:00 - 16:00");

在这种情况下,"12:00 - 16:00" 是一个String值,而不是一个实际的Shift对象。请确保在您的CompareTo方法中,您的代码正确将String值转换为Shift对象。否则,当比较开始时间时...事情可能会出错。

事实上,Justin,我并没有真正传递一个字符串参数,这只是我自己的“伪代码”,只是为了展示这个概念。如果有歧义,对不起。 - Konrad Morawski

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接