为什么 C # 不能比较两种对象类型,而 VB 却不能?

我在 C # 中有两个对象,不知道它是布尔型的还是其他类型的。 然而,当我试图比较这些 C # 时,却得不到正确的答案。 我用 VB.NET 尝试过同样的代码,它做到了!

有人能告诉我如果有解决办法的话该怎么办吗?

C # :

object a = true;
object b = true;
object c = false;
if (a == b) c = true;
MessageBox.Show(c.ToString()); //Outputs False !!

VB.NET:

Dim a As Object = True
Dim b As Object = True
Dim c As Object = False
If (a = b) Then c = True
MessageBox.Show(c.ToString()) '// Outputs True
6864 次浏览

在 C # 中,==运算符(当应用于引用类型表达式时)执行 参考文献相等性检查,除非它是 超载了。您正在比较两个引用,它们是装箱转换的结果,因此它们是不同的引用。

编辑: 使用重载 ==的类型,您可以获得不同的行为——但这是基于表达式的 编译时类型。例如,string提供 ==(string, string) :

string x = new string("foo".ToCharArray());
string y = new string("foo".ToCharArray());
Console.WriteLine(x == y); // True
Console.WriteLine((object) x == (object) y); // False

这里的第一个比较使用重载运算符,但是第二个比较使用“ default”引用比较。

在 VB 中,=操作符要做更多的工作——它甚至不仅仅等同于使用 object.Equals(x, y),因为像 Option Compare这样的操作可以影响文本的比较方式。

从根本上说,操作符的工作方式不一样,打算的工作方式也不一样。

对象实例不与操作符“ = =”进行比较。应该使用方法“ equals”。使用“ = =”运算符比较引用,而不是对象。

试试这个:

public class MyObject
{
public MyObject(String v)
{
Value = v;
}
public String Value { get; set; }
}


MyObject a = new MyObject("a");
MyObject b = new MyObject("a");
if(a==b){
Debug.WriteLine("a reference is equal to b reference");
}else{
Debug.WriteLine("a reference is not equal to b reference");
}
if (a.Equals(b)) {
Debug.WriteLine("a object is equal to b object");
} else {
Debug.WriteLine("a object is not equal to b object");
}

结果:

a reference is not equal to b reference
a object is not equal to b object

现在,试试这个:

public class MyObject
{
public MyObject(String v)
{
Value = v;
}
public String Value { get; set; }


public bool Equals(MyObject o)
{
return (Value.CompareTo(o.Value)==0);
}
}
MyObject a = new MyObject("a");
MyObject b = new MyObject("a");
if(a==b){
Debug.WriteLine("a reference is equal to b reference");
}else{
Debug.WriteLine("a reference is not equal to b reference");
}
if (a.Equals(b)) {
Debug.WriteLine("a object is equal to b object");
} else {
Debug.WriteLine("a object is not equal to b object");
}

结果:

a reference is not equal to b reference
a object is equal to b object

问题在于 C # 中的 = = 操作符是基于这两个参数的 编译时类型对静态方法的调用(好吧,也许不是技术上的,但是可以这样想)。这些对象的实际运行时类型并不重要。

基于该编译时类型,编译器将确定使用哪个 operator ==实现。它可能使用默认的 object实现,它可能使用语言提供的数值重载之一,或者它可能是用户定义的实现。

这与 VB 的不同之处在于 VB 不在编译时确定实现。它等待到运行时并检查给定的两个参数,以确定应该使用哪个 ==运算符实现。

您的代码包含布尔值,但它们位于 object类型的变量中。因为 变量object类型的,所以 C # 编译器使用 ==object实现,它比较 参考文献,而不是对象实例。因为布尔值是盒子,所以它们没有相同的引用,即使它们的值是相同的。

VB 代码不关心变量的类型。它一直等到运行时,然后检查这两个变量,发现它们都是布尔类型的 事实上,因此使用布尔 ==运算符实现。该实现比较布尔值,而不是它们的引用(在调用该操作符之前,布尔值将被取消装箱,因此引用比较甚至不再有意义)。因为布尔值是相同的,所以返回 true。

除了 Jon 的回答解释了 C # 的一面之外,下面是 VB 所做的:

在 VB 中与 Option Strict On进行比较,通过 = 一直都是测试值相等,从不进行参考相等。实际上,一旦切换到 Option Strict On,代码甚至不能编译,因为 System.Object没有定义 Operator=。你应该打开 一直都是的这个选项,它比捕蝇草更有效地捕捉虫子(尽管在你的特殊情况下,这种宽松的行为实际上做了正确的事情)。1

实际上,对于 Option Strict On,VB 的行为甚至比 C # 更严格: 在 C # 中,a == b 都不是触发对 SomeType.operator==(a, b)的调用,或者,如果不存在这种调用,则调用引用相等比较(这相当于调用 object.ReferenceEquals(a, b))。

另一方面,在 VB 中,比较 a = b 一直都是调用相等运算符。 2如果你想使用引用相等比较,你必须使用 a Is b(也就是 Object.ReferenceEquals(a, b))。


1) 这里有一个很好的迹象表明为什么使用 Option Strict Off是一个坏主意: 从之前开始,我已经使用 VB.NET 将近十年了。NET 的官方发布,直到几年前,和 我完全不知道什么 a = bOption Strict Off。它做了一些相等的比较,但到底发生了什么,为什么,不知道。但是它比 C # 的 dynamic特性更复杂(因为它依赖于一个文档良好的 API)。以下是 MSDN 的说明:

由于 Option Strict On提供 很强的打字能力,防止意外的类型转换和数据丢失,禁止后期绑定,并提高性能,因此强烈建议使用 Option Strict On

2) Jon 提到了一个例外,字符串,由于向后兼容的原因,相等比较会做更多的事情。