为什么C#不能比较两个对象types,但VB不对?
我在C#中有两个对象,不知道它是布尔型还是其他types。 但是,当我尝试比较那些C#没有给出正确的答案。 我已经尝试了与VB.NET相同的代码,并做到了!
任何人都可以告诉我如何解决这个问题,如果有解决scheme?
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
在C#中, ==
运算符(应用于引用typesexpression式时)会执行引用相等性检查,除非它被重载 。 你正在比较两个引用,这是拳击转换的结果,所以这些是不同的引用。
编辑:与重载==
types,你可以得到不同的行为 – 但这是基于expression式的编译时间types。 例如, 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
这里第一个比较是使用重载操作符,但第二个是使用“默认”参考比较。
在VB中, =
运算符做了很多工作,甚至不等同于使用object.Equals(x, y)
,因为像Option Compare
这样的东西可以影响文本的比较方式。
从根本上说,运营商的工作方式并不一样,也不打算以相同的方式工作。
除了Jon的答案,它解释了C#方面的事情,下面是VB做的事情:
在带有Option Strict On
VB中,比较通过=
总是testing值是否相等,永远不会参考相等。 实际上,一旦你切换Option Strict On
,你的代码甚至不会编译,因为System.Object
没有定义一个Operator=
。 你应该总是有这个选项,它比金星捕蝇器更有效地捕捉错误(尽pipe在你的特定情况下,这种松散的行为实际上是正确的)。 1
事实上,使用Option Strict On
,VB的行为甚至比C#更严格:在C#中, a == b
触发对SomeType.operator==(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
是一个坏主意:从.NET正式发布到几年前,我已经使用了VB.NET近十年了, 我完全不知道 a = b
使用Option Strict Off
。 它做了一些平等的比较,但究竟发生了什么,为什么,不知道。 虽然它比C#的dynamic
特性更复杂(因为它依赖于良好logging的API)。 以下是MSDN所说的内容:
由于
Option Strict On
提供了强大的键入function ,可防止数据丢失导致的意外types转换,禁止后期绑定并提高性能,因此强烈build议使用它。
2) Jon提到了一个例外,string,在这种情况下,为了向后兼容,平等比较会做更多的事情。
对象实例不与运算符“==”进行比较。 你应该使用方法“等于”。 用“==”运算符比较引用,而不是对象。
尝试这个:
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#中的==运算符是基于两个参数的编译时间types的静态方法的调用(也许不是技术上,但它可以是这样)。 这些对象的实际运行时types是什么并不重要。
基于编译时间types,编译器将确定要使用的operator ==
实现。 它可能使用默认的object
实现,它可能使用语言提供的数字重载之一,也可能是用户定义的实现。
这不同于VB,因为VB不会在编译时确定实现。 它等到运行时间,并检查它给出的两个参数,以确定它应该使用哪个==
运算符的实现。
你的代码包含布尔值,但它们是在object
types的variables中。 因为variables是object
types的,所以C#编译器使用==
的object
实现,它比较引用而不是对象实例。 由于布尔值是框,所以它们不具有相同的引用,即使它们的值相同。
VB代码不关心variables是什么types。 它等到运行时,然后检查这两个variables,看到它们实际上都是布尔types,所以使用布尔==
运算符实现。 该实现比较了布尔值的值,而不是它们的引用(在调用这个操作符之前,布尔值将被拆箱,所以参考比较甚至没有意义)。 因为布尔值的值相同,所以返回true。