Object.Equals是虚拟的,但Object.operator==在C#中不使用它?

Object.Equals是虚拟的,但Object.operator==在C#中不使用它?,c#,equals,equals-operator,referenceequals,C#,Equals,Equals Operator,Referenceequals,我被C#中一个奇怪的“不对称”击中了,我真的不明白。请参阅以下代码: using System; using System.Diagnostics; namespace EqualsExperiment { class Program { static void Main(string[] args) { object apple = "apple"; object orange = string.F

我被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#中失败了?我的哪些假设是错误的?

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

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


==
操作符是为字符串定义的,然后它实际使用了
Equals
方法:

public static bool operator ==(string a, string b) {
  return Equals(a, b);
}
但是,在代码中,您没有在字符串上使用运算符,而是在对象上使用运算符,因此您得到的是为对象定义的
=
运算符,它使用
ReferenceEquals
进行比较


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

为了完整性,还值得注意的是,在这种情况下,static
object.Equals(apple,orange)
将返回
true
object.Equals
首先使用
=
检查ref相等,如果失败,它将使用重载的
apple.Equals(橙色)
(假设
apple
orange
不是
null
)。我知道我使用的是
静态bool对象。操作符==(对象,对象)
。但我仍然不明白,为什么不调用
Object.Equals(Object)
。由于这是虚拟的,因此将在end.Hmmm中调用正确的
String.Equals(Object)
。所以说Object.operator==是用ReferenceEquals定义的,而String.operator==是用Equals定义的。这不是很好,很直观吗?@wigy:大多数情况下,它工作得很好,但当然也有类似于您的示例的情况,您可能希望在运行时确定比较结果。它当然比C++和java中更直观,在这里你不能完全使用字符串上的==运算符。在VB中,=运算符在运行时确定比较,这与VB的工作方式更为一致,但这会导致其他一些情况,让您感到惊讶。在C#中,可以从代码中确定将使用什么样的比较,这更符合C#的一般工作方式。谢谢Guffa。我知道它比C、Java或VB更好。C++操作符可能是虚拟的,因此在那里存在不同的问题。这就是为什么大多数C++编码标准使用YODA条件,比如“代码> >(5=某事物){…} /代码>,从我的答案中,我理解,框架设计者认为引用等价对于一些编码器来说是更直观的,但另一方面,修复了string.operator==的问题。字符串内部处理是否会使==也返回
true
?有什么想法吗?@Ani:是的,如果你比较两个具有相同值的插入字符串,它们将指向同一个字符串对象。在OP的例子中,
orange
字符串是在运行时故意创建的,这样它就不会被占用。我在另一个线程中发现了一个问题的答案。似乎是
对象。运算符=
使用
对象。引用等于
,但
字符串。运算符==
使用
对象。等于
。这与我的直觉相反,因为
object.Equals
是虚拟的,所以它可以在
object.operator==
中使用。