152

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

4 回答 4

168

在 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 中,=操作符做了更多的工作——它甚至不仅仅等同于 using object.Equals(x, y),因为诸如此类的事情Option Compare会影响文本的比较方式。

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

于 2013-02-12T16:38:57.070 回答
79

除了解释 C# 方面的 Jon 的回答之外,这是 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)这里很好地说明了为什么 usingOption Strict Off是一个坏主意:我使用 VB.NET 已经将近十年了,从 .NET 正式发布之前到几年前,我完全不知道.NET 有什么a = bOption Strict Off。它进行了某种平等比较,但究竟发生了什么以及为什么,不知道。不过,它比 C# 的dynamic功能更复杂(因为它依赖于有据可查的 API)。这是 MSDN 所说的:

因为Option Strict On提供强类型,防止意外类型转换导致数据丢失,不允许后期绑定,提高性能,所以强烈推荐使用它。

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

于 2013-02-12T20:01:48.790 回答
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
于 2013-02-12T16:40:16.443 回答
3

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

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

这与 VB 不同,因为 VB 不会在编译时确定实现。它等到运行时并检查给定的两个参数以确定==它应该使用哪个操作符实现。

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

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

于 2013-02-12T17:28:07.850 回答