在装箱布尔类型上使用 == 运算符和 Equals 方法有什么区别?

发布于 2024-10-20 02:09:21 字数 234 浏览 4 评论 0原文

鉴于这两个语句...

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

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

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

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 / how does the second statement result in true?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

渔村楼浪 2024-10-27 02:09:21

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

现在 == 不是被覆盖,而是重载...所以如果你写:

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

那将总是比较用于参考身份,而无需运行任何特定于类型的代码。

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.

一笑百媚生 2024-10-27 02:09:21

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

来自 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。

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.

罪#恶を代价 2024-10-27 02:09:21

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

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.

留蓝 2024-10-27 02:09:21

Equals 方法是一个虚拟方法,被 Boolean 类型覆盖。因此,在第二行中将 bool 转换为 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);
    }
}

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);
    }
}
追风人 2024-10-27 02:09:21

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

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文