考虑以下两个陈述...
((object)false) == ((object)false)
((object)false).Equals((object)false)
第一条语句返回false。 第二条语句返回true。
我理解为什么第一条语句返回false——当布尔值被装箱时,它变成了引用类型,而这两个引用不相等。但是,第二条语句如何得到true的结果呢?
基本上是因为它仍在调用多态的Equals
方法。
以下是使用不同类型演示的示例代码:
using System;
struct Foo
{
public override bool Equals(object other)
{
Console.WriteLine("Foo.Equals called!");
return true;
}
public override int GetHashCode()
{
return 1;
}
}
class Program
{
static void Main(string[] args)
{
object first = new Foo();
object second = new Foo();
first.Equals(second);
}
}
这仍然会打印出"Foo.Equals called!",因为在“box”上调用Equals方法仍会调用Foo.Equals。
现在,==没有被重写,而是被重载了......所以如果你写:
object first = ...;
object second = ...;
bool same = first == second;
这将始终进行引用标识的比较,而不会运行任何类型特定的代码。
Equals
方法是一个虚方法,被Boolean
类型重写。所以在第二行中将bool
转换为object
并不重要;它仍然使用类型的虚函数表来查找由对象的实际类型提供的Equals
实现(这就是多态!)。
==
运算符是一个静态运算符,因此适当的重载在编译时选择。编译器看到您使用该运算符比较两个object
类型的对象,因此选择(object, object)
重载。
下面是一个愚蠢的小程序,用于说明差异:
class Thing
{
public virtual void AnnounceSelf()
{
Console.WriteLine("I am a Thing.");
}
public static void AnnounceThing(Thing other)
{
Console.WriteLine("Here is a Thing.");
}
public static void AnnounceThing(OtherThing other)
{
Console.WriteLine("Here is ANOTHER type of Thing.");
}
}
class OtherThing : Thing
{
public override void AnnounceSelf()
{
Console.WriteLine("I am ANOTHER Thing.");
}
}
class Program
{
public static void Main()
{
Thing t = new Thing();
// Outputs "I am a Thing." as expected.
t.AnnounceSelf();
// Outputs "Here is a Thing." as expected.
Thing.AnnounceThing(t);
t = new OtherThing();
// This method is virtual, so even though t is typed as Thing,
// the implementation provided by OtherThing will be called;
// outputs "I am ANOTHER Thing."
t.AnnounceSelf();
// In contrast to above, this method will NOT call the more
// specific overload of AnnounceThing (accepting an OtherThing
// argument) because t is only typed as Thing, so the compiler
// will go with the first;
// outputs "Here is a Thing."
Thing.AnnounceThing(t);
// THIS will output "Here is ANOTHER type of Thing."
Thing.AnnounceThing((OtherThing)t);
}
}
正如你所说,第一个示例检查引用是否相等,而第二个示例检查每个对象的相等值。
来自MSDN:
Equals方法的所有实现都必须满足以下语句。在列表中,x、y和z表示不为null的对象引用。
x.Equals(x)返回true,除了涉及浮点类型的情况。请参阅IEC 60559:1989,微处理器系统的二进制浮点算术。
x.Equals(y)返回与y.Equals(x)相同的值。
如果x和y都是NaN,则x.Equals(y)返回true。
如果(x.Equals(y) && y.Equals(z))返回true,则x.Equals(z)返回true。
只要x和y引用的对象未被修改,连续调用x.Equals(y)将返回相同的值。
x.Equals(null)返回false。
运算符重载不是多态的,但Equals
是。即使bool
有一个重载的==,通过将其转换为object
,您正在使用object
的实现,它比较引用相等性。但您仍然在使用bool
版本的Equals
。
第一个是用于引用,第二个是用于值!