开发者

What is the difference between using the == operator and the Equals method on a boxed boolean type?

Given these two statements...

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

The first statement returns false. The second statement returns true.

I understand why the first statement returns false - when the boolean is boxed, it becomes a reference type, and the two references are not equal. But, why开发者_如何学C / how does the second statement result in true?


Because it's still calling the polymorphic Equals method, basically.

Sample code to demonstrates with a different type:

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);
    }
}

That still prints "Foo.Equals called!" because calling the Equals method on the "box" still calls Foo.Equals.

Now == isn't overridden, it's overloaded... so if you write:

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

That will always compare for reference identity, without ever running any type-specific code.


This article may be able to answer your question:

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


Just as you said, the first example checks whether the references are equal, while the second checks for equal values for each object.

From MSDN:

The following statements must be true for all implementations of the Equals method. In the list, x, y, and z represent object references that are not null.

x.Equals(x) returns true, except in cases that involve floating-point types. See IEC 60559:1989, Binary Floating-point Arithmetic for Microprocessor Systems.

x.Equals(y) returns the same value as y.Equals(x).

x.Equals(y) returns true if both x and y are NaN.

If (x.Equals(y) && y.Equals(z)) returns true, then x.Equals(z) returns true.

Successive calls to x.Equals(y) return the same value as long as the objects referenced by x and y are not modified.

x.Equals(null) returns false.


Operator overloading is not polymorphic but Equals is. Even though bool has an overloaded ==, by casting it to object you're using object's implementation, which compares reference equality. But you're still using the bool version of Equals.


The Equals method is a virtual method which is overridden by the Boolean type. So it doesn't matter that you're casting the bool to an object in the second line; it's still using the type's vtable to look up the implementation of Equals provided by the object's actual type (that's polymorphism for you!).

The == operator is a static operator and so the appropriate overload is selected at compile time. The compiler sees you comparing two objects of type object with that operator and so it selects the (object, object) overload.

Here's a stupid little program to illustrate the difference:

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);
    }
}


1st one is for references, second one is for values!

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜