为什么C#无法将两种对象类型相互比较,但VB却没有?

时间:2013-02-12 16:31:43

标签: c# .net vb.net comparison

我在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

4 个答案:

答案 0 :(得分:166)

在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

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

在VB中,=运算符可以完成更多工作 - 它甚至不等同于使用object.Equals(x, y),因为Option Compare之类的内容会影响文本的比较。

从根本上说,运营商的工作方式不同,并且意图以相同的方式工作。

答案 1 :(得分:79)

除了Jon的解释C#方面的答案之外,这是VB的作用:

在带有Option Strict On的VB中,通过= 进行的比较总是测试值的相等性,从不测试引用相等性。实际上,由于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)。 Here’s what the MSDN says:

  

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

2) Jon提到了一个例外,字符串,其中为了向后兼容性,相等比较做了更多的事情。

答案 2 :(得分:4)

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

试试这个:

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

答案 3 :(得分:3)

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

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

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

您的代码包含布尔值,但它们位于object类型的变量中。由于变量的类型为object,因此C#编译器使用object的{​​{1}}实现,它会比较引用,而不是对象实例。由于布尔值是方框,因此它们不具有相同的引用,即使它们的值相同。

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