6

鉴于这两个陈述...

((object)false) == ((object)false)
((object)false).Equals((object)false)

第一条语句返回 false。第二个语句返回 true。

我明白为什么第一个语句返回 false - 当布尔值被装箱时,它变成了引用类型,并且两个引用不相等。但是,为什么/如何第二个陈述结果为真?

4

6 回答 6

8

因为它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 call!” 因为在“盒子”上调用 Equals 方法仍然调用Foo.Equals.

现在==没有被覆盖,它被重载......所以如果你写:

object first = ...;
object second = ...;
bool same = first == second;

这将始终比较参考身份,而无需运行任何特定于类型的代码。

于 2011-03-01T18:00:00.760 回答
5

这篇文章或许能回答你的问题:

http://blogs.msdn.com/b/csharpfaq/archive/2004/03/29/when-should-i-use-and-when-should-i-use-equals.aspx

于 2011-03-01T18:01:25.657 回答
1

正如您所说,第一个示例检查引用是否相等,而第二个示例检查每个对象的相等值。

来自MSDN

对于 Equals 方法的所有实现,以下语句必须为真。在列表中,x、y 和 z 表示不为空的对象引用。

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。

于 2011-03-01T17:59:54.177 回答
1

运算符重载不是多态的,而是多态Equals的。即使bool有一个重载的 ==,通过将其转换为object您正在使用object的实现,它比较引用相等性。但是您仍在bool使用Equals.

于 2011-03-01T18:00:14.110 回答
1

Equals方法是一个被Boolean类型覆盖的虚方法。因此,在第二行中将其转换bool为 an并不重要;object它仍然使用类型的 vtable 来查找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);
    }
}
于 2011-03-01T18:01:04.877 回答
-1

第一个是参考,第二个是价值!

于 2011-03-01T18:01:10.157 回答