从列表中删除确切的类实例

时间:2016-07-11 12:33:44

标签: c# list hashcode

我在某个时刻向Foo添加了一个类List<Foo>我想从列表中删除这个类的确切实例:我这样做:

    static void Main()
    {
        List<Test> list = new List<Test>();
        Test test = new Test(1);
        int hashCode = test.GetHashCode();
        list.Add(test);
        for (int i = 0; i < list.Count; i++)
        {
            if(list[i].GetHashCode() == hashCode)
            {
                list.Remove(list[i]);
            }
        }
        Console.ReadKey();
    }

public class Test
{
    public int value { get; set; }

    public Test(int value)
    {
        this.value = value;
    }
}

我的方法有什么缺陷吗?从列表中删除确切对象实例的最佳方法是什么?

修改忘了提及:

在我的原始代码中,我没有跟踪实例。该类在哈希代码不是的方法中实例化,因此在方法完成后将忘记第一个类。我正在检查实例化类的方法。

5 个答案:

答案 0 :(得分:2)

是的,有几个。

首先,您已经拥有要删除的实例。只需list.Remove(test)

其次,hashcode不是唯一标识符。两个不同的对象可以具有相同的哈希码 - 唯一必须是真的是两个相同的对象必须具有相同的哈希码并且哈希码不会改变。 return 0;GetHashCode的完全有效的实现(虽然显然效率有点低:))。另外,GetHashCode不是自动的 - 您的Test类不会覆盖GetHashCode,因此您不知道实际返回的是什么。

第三,当您从列表中间删除项目时,移动后的所有项目。因此,您需要将一个项目回滚,例如:

for (var i = 0; i < list.Count; i++)
{
  if (whatever) list.RemoveAt(i--);
}

修改

好的,因为你的编辑很明显你不知道要删除哪个实例,1)不会起作用。在任何情况下,2)仍然保持 - 哈希码不是唯一标识符。如果需要根据某个值查找实例,请查找值,而不是哈希码。

答案 1 :(得分:0)

您只需致电list.Remove(test)即可。它会检查对象引用的相等性,因此将删除完全匹配。

here因此,假设您将使用其哈希代码返回相同的对象是错误的。如果您需要匹配除引用之外的其他属性上的项目,请在列表上创建自己的相等比较器。

答案 2 :(得分:0)

你的循环需要按相反的顺序for (int i = list.Count - 1; i >= 0; i--),因为从列表中删除任何元素时,元素将向上移动1个位置。

答案 3 :(得分:0)

如果您查看MSDN for GetHashCode,您会看到 - 你不应该假设相等的哈希码意味着对象相等。 [https://msdn.microsoft.com/en-gb/library/system.object.gethashcode(v=vs.110).aspx][1]

我建议使用

public int value { get; set; }

如果list.Remove(list.First(t => t.value == 1)); 是唯一的,您可以使用LINQ删除

inner.f.y <- function(y)
{
    cat("length(y)   ", length(y), "\n")

    t<-2*y*exp((exp(-1*1i)-1)*y)

    cat("length(t)   ", length(t), "\n")
    t
}
integrate(inner.f.y, lower = 0.01, upper = 8)

答案 4 :(得分:0)

你说

  

我想从列表中删除该类的确切实例

这意味着您要删除的内容是类的实例,而不是值类型。因此,我们知道您正在寻找的功能的签名是

void RemoveExactInstance<A>(List<A> as, A instance) where A : class 

List上的删除方法有以下注释:

  

如果类型T实现IEquatable<T>通用接口,则相等比较器是该接口的Equals方法;否则,默认的相等比较器为Object.Equals

这意味着我们无法使用Remove方法。

IndexOf方法也是如此。因此,迭代并删除相同对象的索引是一种有效的策略。

您的实现在实例上使用GetHashCode,但不能保证为您提供唯一的哈希码;多个实例可以共享相同的哈希码。

我们可以做的是用哈希码检查代替引用相等性检查。为此,我们有Object.ReferenceEquals

我们可以在您的代码中替换它:

void RemoveExactInstance<A>(List<A> as, A instance) where A : class {
    for (int i = as.Count - 1 ; i >= 0; i--)
    {
        if(Object.ReferenceEquals(as[i], instance))
        {
            list.Remove(list[i]);
            //if you only want to remove the first instance
            //you want to break; out of the loop here,
            //otherwise, continue on
        }
    }
}

编辑:在你的编辑中,你说

  

在我的原始代码中,我没有跟踪实例。

如果您没有该实例,大多数投注都会被取消。如果您只有哈希码,则无法保证使其正常工作。因此,最好保留实例,而不仅仅是哈希代码。