【问题标题】:Object.Equals is virtual, but Object.operator== does not use it in C#?Object.Equals 是虚拟的,但是 Object.operator== 在 C# 中不使用它?
【发布时间】:2011-04-13 03:28:40
【问题描述】:

我在 C# 中遇到了一个我不太了解的奇怪“不对称”。见以下代码:

using System;
using System.Diagnostics;
namespace EqualsExperiment
{
    class Program
    {
        static void Main(string[] args)
        {
            object apple = "apple";
            object orange = string.Format("{0}{1}", "ap", "ple");
            Console.WriteLine("1");
            Debug.Assert(apple.Equals(orange));
            Console.WriteLine("2");
            Debug.Assert(apple == orange);
            Console.WriteLine("3");
        }
    }
}

对于所有 .NET 专家来说,这可能是显而易见的,但第二个断言失败了。

在 Java 中,我了解到 == 是这里称为 Object.ReferenceEquals 的同义词。在 C# 中,我认为 Object.operator== 使用 Object.Equals,它是虚拟的,因此在 System.String 类中被覆盖。

有人可以解释一下,为什么第二个断言在 C# 中失败?我的哪些假设是错误的?

【问题讨论】:

  • 我也在另一个线程中找到了我的问题的answer。似乎object.operator== 使用object.ReferenceEquals,但string.operator== 使用object.Equals。这对我来说是违反直觉的,因为object.Equals 是虚拟的,所以它可以在object.operator== 中使用。

标签: c# equals equals-operator referenceequals


【解决方案1】:

== 运算符不是同义词,它是为不同类型定义的运算符。

== 运算符是为字符串定义的,然后它确实使用了Equals 方法:

public static bool operator ==(string a, string b) {
  return Equals(a, b);
}

但是,在您的代码中,您不是在字符串上使用运算符,而是在对象上使用它,因此您得到的是为对象定义的 == 运算符,它使用 ReferenceEquals 进行比较。

使用哪种运算符重载是在编译时决定的,因此决定重载的是变量的类型,而不是变量指向的对象的实际类型。

【讨论】:

  • 嗯。所以你说 Object.operator== 是用 ReferenceEquals 定义的,而 String.operator== 是用 Equals 定义的。这不是很好和直观吗?
  • @wigy:大多数时候它工作得很好,但当然有像你的例子这样的情况,你可能希望在运行时确定比较。它肯定比在 C++ 和 Java 中更直观,因为在 C++ 和 Java 中,您根本无法可靠地在字符串上使用 == 运算符。在 VB 中,= 运算符决定了运行时的比较,这更符合 VB 的工作方式,但它提供了其他几种可能会让您感到惊讶的情况。在 C# 中,可以从代码中准确确定将使用什么比较,这更符合 C# 的一般工作方式。
  • 谢谢古法。我知道它比 C、Java 或 VB 更好。 C++ 运算符可能是虚拟的,因此您会遇到不同的问题。这就是为什么大多数 C++ 编码标准都使用像 if (5 == something) {...} 这样的 Yoda-conditions 从你的回答我理解,框架设计者认为 ReferenceEquals 对一些编码人员来说更直观,但另一方面固定 string.operator==。跨度>
  • 字符串实习不会使 == 也返回 true 成为可能吗?有什么想法吗?
  • @Ani:是的,如果你比较两个具有相同值的实习字符串,它们将指向同一个字符串对象。在 OP 的示例中,orange 字符串是在运行时故意创建的,因此它不会被实习。
【解决方案2】:

操作符被定义为静态方法,因此它们不能参与多态性。所以你的第二个断言使用== 的定义object(因为你的变量被声明为object),它只测试引用相等。如果变量声明为string,则将使用string== 重载,并且第二个断言将成功。

【讨论】:

  • 另外值得注意的是,为了完整起见,在这种情况下,静态 object.Equals(apple,orange) 将返回 trueobject.Equals 首先使用== 来检查引用是否相等,如果失败,它将使用重载的apple.Equals(orange)(假设appleorange 不是null)。
  • 我知道我使用static bool Object.operator==(Object, Object)。但我还是不明白,为什么不叫Object.Equals(Object)。因为那是虚拟的,所以最后会调用正确的String.Equals(Object)
猜你喜欢
  • 2012-01-28
  • 1970-01-01
  • 1970-01-01
  • 2010-11-10
  • 2011-05-07
  • 1970-01-01
  • 1970-01-01
  • 2020-08-19
  • 2011-08-20
相关资源
最近更新 更多