为什么两个空列表不相等?

5
我认为在两个空列表上调用Equals()应该会返回true,但实际情况并非如此。有人能解释一下为什么吗?
var lst = new List<Whatever>();
var lst2 = new List<Whatever>();
if(!lst.Equals(lst2))
    throw new Exception("seriously?"); // always thrown
11个回答

8
因为Equals检查引用,所以lstlst2是不同的对象。(请注意Equals是从Object继承而来,并没有在List<T>中实现)
你要寻找Linq的SequenceEquals
即使使用SequenceEquals,也不要期望它能在非空列表上使用Whatever类(除非它是一个结构体)。你可能需要实现一个比较器,并使用正确的重载

3

Equals 在这里比较的是两个列表的引用,因为它们是分开的列表,所以结果总是 false。


谢谢。我觉得集合类不重写Equals方法有点傻,就像这种情况,如果没有其他的话。实际上,我认为两个包含相同对象、顺序相同的List也应该是相等的。 - Viet Norm
@VietNorm - 这对于两个值类型的列表可能是有意义的,但如果它们是更复杂的引用类型呢?大多数 .Net 中的引用类型不会覆盖 Equals,因为它可能会产生非常混乱的行为。例如,如果您有一个 Dictionary<List<T>, MyClass>,那么 .Net 如何为该类构建基于哈希的查找,如果 List<T>.Equals 被覆盖了呢? - Keith
@Keith - 我不明白你的问题。如果List<T>重写Equals(),使其返回值取决于列表的内容,那么它显然也会以类似的方式重写GetHashCode()。 - Viet Norm
@VietNorm,除非您知道列表的类型是什么,否则要做到这一点将非常困难-List<T>.GetHashCode()需要知道T是什么。您不能只检查列表的长度,您需要为列表中的每个项目创建一个哈希,并以不会抵消的方式将它们组合起来。 - Keith

3

对象文档(MSDN文档):

Equals的默认实现支持引用类型的引用相等性,以及值类型的位相等性。引用相等性意味着被比较的对象引用指向同一个对象。位相等性意味着被比较的对象具有相同的二进制表示。

列表文档(MSDN文档):

确定指定的对象是否等于当前对象。(从对象继承。)

您有两个不同的对象(两次new...),因此它们不相同。


2
因为它比较对象的身份,而不是列表的内容。它们是两个独立的对象。
请参阅 C# FAQ 中的 answer

2

List<T>Equals 实现是从 Object 继承的:

换句话说,由于这是两个不同的列表,它们具有不同的引用,因此Equals 返回false

Equals 的默认实现对于引用类型支持引用相等性。


1

List<T>.Equals() 会比较两个列表的引用,如果它们相等,则返回 true。如果您想比较两个列表的元素,请使用 List<T>.SequenceEquals()


1

当您将两个列表进行比较时,equals方法不会比较列表中的项目。它只会将一个List对象与另一个List对象进行比较。它们有自己的身份


0
据我所知,从文档上看,List 上的 .Equals 是从 Object 继承而来的方法,这意味着它会检查列表是否为同一对象。由于您创建了两个不同的对象,它们不会相同。

能否解释一下为什么要给我点踩,这样我就知道该如何改进了。 - Roger Lindsjö
我也不理解为什么会被踩。List没有重写Equals()方法的事实是所有正确答案的精髓。谢谢。 - Viet Norm

0

它们是在内存中分配的两个不同列表(使用new关键字)。因此它们不能相等。如果您想要这样的功能,您应该构建自己的对象,继承自List并覆盖Equals函数


0
在C#和.Net中,你有引用类型和值类型。
值类型代表着数值。例如:整数、双精度浮点数、日期时间等等。
当你比较值类型时,你比较它们的实际值,所以:
int a = 10;
int b = 10;

if( a == b ) 
{
    // this will fire
}

请注意,每个变量都指向一个新的副本,所以:
int c = a;
c = c+5;

if( a == c ) 
{
    // this won't, because a==10 and c==15
}

引用类型是您可以传递并执行操作的对象。您可以有多个变量引用同一个对象,因此:

var a = new List<Whatever>();
var b = new List<Whatever>();
if( a == b ) 
{
    // this won't fire, a and be are separate objects
}

var c = a;
c.Add(new Whatever());
if( a == c ) 
{
    // this will, a and c are the same object.
    a[0]; // holds the value added to c
}

最后,一些特殊情况下的引用类型的行为类似于值类型,例如 string


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