为什么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不会在编译时确定实现。 它等到运行时间,并检查它给出的两个参数,以确定它应该使用哪个==运算符的实现。

你的代码包含布尔值,但它们是在objecttypes的variables中。 因为variablesobjecttypes的,所以C#编译器使用==object实现,它比较引用而不是对象实例。 由于布尔值是框,所以它们不具有相同的引用,即使它们的值相同。

VB代码不关心variables是什么types。 它等到运行时,然后检查这两个variables,看到它们实际上都是布尔types,所以使用布尔==运算符实现。 该实现比较了布尔值的值,而不是它们的引用(在调用这个操作符之前,布尔值将被拆箱,所以参考比较甚至没有意义)。 因为布尔值的值相同,所以返回true。