代码之家  ›  专栏  ›  技术社区  ›  PreqlSusSpermaOhranitel

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

  •  0
  • PreqlSusSpermaOhranitel  · 技术社区  · 8 年前

    我正在添加一个类 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 回复  |  直到 8 年前
        1
  •  2
  •   Luaan    8 年前

    是的,有一些。

    首先,您已经有了要删除的实例。就这么做 list.Remove(test) .

    其次,哈希码不是唯一的标识符。两个不同的对象可以具有相同的哈希代码-唯一必须为真的是,两个相同的对象必须具有相同的hash代码,并且哈希代码不会更改。 return 0; 是完全有效的 GetHashCode (尽管显然有点低效:)。而且 不是自动的-你的 Test 类不重写 方法 ,所以您不知道它实际上会返回什么。

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

    编辑:

    好吧,既然您的编辑很明显地表明您不知道要删除哪个实例,那么1)将无法工作。无论如何,2)仍然保持-哈希代码不是唯一标识符。如果需要根据某个值查找实例,请查找该值,而不是哈希代码。

        2
  •  0
  •   Patrick Hofman Wahid Bitar    8 年前

    list.Remove(test) 。它检查对象引用的相等性,因此将删除精确匹配。

    Equal hash codes are not a guarantee for object equality. 因此,假设您将使用同一对象的哈希代码返回该对象是错误的。如果需要匹配其他属性(而不是其引用)上的项,请在列表上创建自己的相等比较器。

        3
  •  0
  •   par    8 年前

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

        4
  •  0
  •   Hasan Emrah Süngü    8 年前

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

    我只是建议使用

    list.Remove(test)
    

    如果 public int value { get; set; }

    list.Remove(list.First(t => t.value == 1));
    
        5
  •  0
  •   Martijn    8 年前

    你是说

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

    这意味着要删除的对象是类的实例,而不是值类型。所以我们知道你要找的函数的签名是

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

    上的remove方法 List 备注如下:

    If类型 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
            }
        }
    }
    

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

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

    如果你没有实例,大多数赌注都会落空。如果你只有哈希代码,就没有保证能实现这一点的方法。因此,最好保留实例,而不仅仅是散列代码。