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

Why C# fails to compare two object types with each other but VB doesn't?

我在C中有两个对象,不知道它是布尔型还是其他类型。然而,当我试图比较这些C时,却没有给出正确的答案。我在vb.net上也尝试过同样的代码,就是这样!

如果有解决方案,有人能告诉我如何解决这个问题吗?

C:

1
2
3
4
5
object a = true;
object b = true;
object c = false;
if (a == b) c = true;
MessageBox.Show(c.ToString()); //Outputs False !!

VB.NET:

1
2
3
4
5
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_中,==运算符(当应用于引用类型表达式时)执行引用相等性检查,除非它被重载。您正在比较两个引用,它们是装箱转换的结果,因此它们是不同的引用。

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

1
2
3
4
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这样的东西会影响文本的比较方式。

从根本上讲,操作人员的工作方式不一样,也不打算以同样的方式工作。


除了乔恩的答案解释了事物的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所说的:

Because Option Strict On provides strong typing, prevents unintended type conversions with data loss, disallows late binding, and improves performance, its use is strongly recommended.

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


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

试试这个:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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");
}

结果:

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

现在,试试这个:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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");
}

结果:

1
2
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。