从列表中删除 class 的确切实例
Remove exact instance of class from list
我在某个时候将 class Foo
添加到 List<Foo>
我想从列表中删除 class 的这个确切实例 我这样做了这样 :
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;
}
}
我的方法有什么缺陷吗?从列表中删除对象的确切实例的最佳方法是什么?
编辑 忘了说:
在我的原始代码中,我没有跟踪实例。 class 是在没有哈希码的方法中实例化的,因此方法完成后将忘记第一个。我正在检查实例化 class 的方法之外的方法。
你可以打电话 list.Remove(test)
。它检查对象引用的相等性,因此将删除完全匹配。
Equal hash codes are not a guarantee for object equality. 因此,假设您将使用其哈希码取回同一个对象是错误的。如果您需要匹配其他属性上的项目而不是它们的引用,请在列表上创建自己的相等比较器。
是的,有几个。
首先,您已经有了要删除的实例。就做 list.Remove(test)
.
其次,哈希码不是唯一标识符。两个不同的对象可以具有相同的哈希码——唯一必须为真的是两个相同的对象必须具有相同的哈希码并且哈希码不会改变。 return 0;
是 GetHashCode
的一个完全有效的实现(虽然显然有点低效 :))。此外,GetHashCode
不是自动的 - 您的 Test
class 不会覆盖 GetHashCode
,因此您不知道它实际上 return.
第三,当你从列表中间移除一个项目时,它之后的所有项目都会移动。因此,您需要将循环回滚一项,例如:
for (var i = 0; i < list.Count; i++)
{
if (whatever) list.RemoveAt(i--);
}
编辑:
好的,既然您的编辑表明您不知道要删除哪个实例,那么 1) 将不起作用。无论如何,2) 仍然成立——散列码不是唯一标识符。如果您需要根据某个值查找实例,请查找该值,而不是哈希码。
您的循环需要按相反的顺序for (int i = list.Count - 1; i >= 0; i--)
,因为从列表中删除任何元素时,元素将向上移动 1 个位置。
如果您查看 GetHashCode 的 MSDN,您会看到
- 你不应该假设相等的哈希码意味着对象相等。
[https://msdn.microsoft.com/en-gb/library/system.object.gethashcode(v=vs.110).aspx][1]
我只建议使用
list.Remove(test)
如果 public int value { get; set; }
是唯一的,您可以使用 LINQ 删除
list.Remove(list.First(t => t.value == 1));
你说
I want to remove this exact instance of the class from the list
这意味着您要删除的是 class 的实例,而不是值类型。所以我们知道你要找的函数的签名是
void RemoveExactInstance<A>(List<A> as, A instance) where A : class
List
上的删除方法有备注:
If type T
implements the IEquatable<T>
generic interface, the equality comparer is the Equals
method of that interface; otherwise, the default equality comparer is 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
}
}
}
编辑:在您的编辑中,您说
In my original code I dont keep track of the instance.
如果您没有实例,那么大多数赌注都没有了。如果您只有散列码,则无法保证可以做到这一点。因此,最好保留实例而不仅仅是哈希码。
我在某个时候将 class Foo
添加到 List<Foo>
我想从列表中删除 class 的这个确切实例 我这样做了这样 :
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;
}
}
我的方法有什么缺陷吗?从列表中删除对象的确切实例的最佳方法是什么?
编辑 忘了说:
在我的原始代码中,我没有跟踪实例。 class 是在没有哈希码的方法中实例化的,因此方法完成后将忘记第一个。我正在检查实例化 class 的方法之外的方法。
你可以打电话 list.Remove(test)
。它检查对象引用的相等性,因此将删除完全匹配。
Equal hash codes are not a guarantee for object equality. 因此,假设您将使用其哈希码取回同一个对象是错误的。如果您需要匹配其他属性上的项目而不是它们的引用,请在列表上创建自己的相等比较器。
是的,有几个。
首先,您已经有了要删除的实例。就做 list.Remove(test)
.
其次,哈希码不是唯一标识符。两个不同的对象可以具有相同的哈希码——唯一必须为真的是两个相同的对象必须具有相同的哈希码并且哈希码不会改变。 return 0;
是 GetHashCode
的一个完全有效的实现(虽然显然有点低效 :))。此外,GetHashCode
不是自动的 - 您的 Test
class 不会覆盖 GetHashCode
,因此您不知道它实际上 return.
第三,当你从列表中间移除一个项目时,它之后的所有项目都会移动。因此,您需要将循环回滚一项,例如:
for (var i = 0; i < list.Count; i++)
{
if (whatever) list.RemoveAt(i--);
}
编辑:
好的,既然您的编辑表明您不知道要删除哪个实例,那么 1) 将不起作用。无论如何,2) 仍然成立——散列码不是唯一标识符。如果您需要根据某个值查找实例,请查找该值,而不是哈希码。
您的循环需要按相反的顺序for (int i = list.Count - 1; i >= 0; i--)
,因为从列表中删除任何元素时,元素将向上移动 1 个位置。
如果您查看 GetHashCode 的 MSDN,您会看到 - 你不应该假设相等的哈希码意味着对象相等。 [https://msdn.microsoft.com/en-gb/library/system.object.gethashcode(v=vs.110).aspx][1]
我只建议使用
list.Remove(test)
如果 public int value { get; set; }
是唯一的,您可以使用 LINQ 删除
list.Remove(list.First(t => t.value == 1));
你说
I want to remove this exact instance of the class from the list
这意味着您要删除的是 class 的实例,而不是值类型。所以我们知道你要找的函数的签名是
void RemoveExactInstance<A>(List<A> as, A instance) where A : class
List
上的删除方法有备注:
If type
T
implements theIEquatable<T>
generic interface, the equality comparer is theEquals
method of that interface; otherwise, the default equality comparer isObject.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
}
}
}
编辑:在您的编辑中,您说
In my original code I dont keep track of the instance.
如果您没有实例,那么大多数赌注都没有了。如果您只有散列码,则无法保证可以做到这一点。因此,最好保留实例而不仅仅是哈希码。