为什么c#不能比较两个对象类型,而VB不能?

时间:2023-01-12 19:40:40

I have two objects in C# and don't know if it's Boolean or any other type. However when I try to compare those C# fails to give the right answer. I have tried the same code with VB.NET and that did it !

我在c#中有两个对象,不知道它是布尔型还是其他类型。然而,当我试图比较这些c#时,却没有给出正确的答案。我用VB尝试过同样的代码。网就这么办了!

Can anyone tell me how to fix this if there is a solution ?

如果有办法的话,谁能告诉我怎么解决这个问题?

C#:

c#:

object a = true;
object b = true;
object c = false;
if (a == b) c = true;
MessageBox.Show(c.ToString()); //Outputs False !!

VB.NET:

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 个解决方案

#1


167  

In C#, the == operator (when applied to reference type expressions) performs a reference equality check unless it's overloaded. You're comparing two references which are the result of boxing conversions, so those are distinct references.

在c#中,==运算符(当应用于引用类型表达式时)执行一个引用等式检查,除非它重载。您正在比较两个引用,它们是装箱转换的结果,所以这些是不同的引用。

EDIT: With types which overload the ==, you can get different behaviour - but that's based on the compile-time type of the expressions. For example, string provides ==(string, string):

编辑:对于重载=的类型,您可以得到不同的行为—但是这是基于表达式的编译时类型的。例如,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

Here the first comparison is using the overloaded operator, but the second is using the "default" reference comparison.

这里,第一个比较使用重载操作符,第二个比较使用“默认”引用比较。

In VB, the = operator does a whole lot more work - it's not even just equivalent to using object.Equals(x, y), as things like Option Compare can affect how text is compared.

在VB中,=运算符要做更多的工作——它甚至不等同于使用对象。= (x, y),就像选项比较会影响文本的比较。

Fundamentally the operators don't work the same way and aren't intended to work the same way.

从根本上说,操作符不是以相同的方式工作的,也不打算以相同的方式工作。

#2


79  

In addition to Jon’s answer which explains the C# side of things, here’s what VB does:

除了Jon的答案解释了c#方面的内容之外,VB还做了以下工作:

In VB with Option Strict On, a comparison via = always tests for value equality and never for reference equality. In fact, your code doesn’t even compile once you switch Option Strict On because System.Object doesn’t define an Operator=. You should always have this option on, it catches bugs more effectively than a venus flytrap (although in your particular case this lax behaviour actually does the right thing).1

在VB中,选项严格为,通过=进行比较总是为了值相等而不是为了引用相等。事实上,您的代码甚至不会编译一旦您切换到严格的选择,因为系统。对象不定义运算符=。你应该总是有这个选项,它比捕蝇草更有效地捕捉虫子(尽管在你的特殊情况下,这种松懈的行为实际上是正确的)

In fact, with Option Strict On, VB behaves even stricter than C#: In C#, a == b either triggers a call to SomeType.operator==(a, b) or, if this doesn’t exist, invokes reference equality comparison (which is equivalent to calling object.ReferenceEquals(a, b)).

事实上,在选项严格的情况下,VB的行为甚至比c#:在c#中,a = b会触发对某一类型的调用。操作符==(a, b)或者,如果不存在,则调用引用相等比较(这等价于调用对象)。ReferenceEquals(a,b))。

In VB on the other hand, the comparison a = b always invokes the equality operator.2 If you want to use reference equality comparison, you have to use a Is b (which is, once again, the same as Object.ReferenceEquals(a, b)).

另一方面,在VB中,比较a = b总是调用等式运算符。2如果你想要使用引用等式比较,你必须使用a是b(同样的,和对象是一样的)。ReferenceEquals(a,b))。


1) Here’s a good indication why using Option Strict Off is a bad idea: I’ve used VB.NET for almost a decade, from before .NET’s official release until a few years ago, and I’ve absolutely no idea what a = b does with Option Strict Off. It does some kind of equality comparison, but what exactly happens and why, no idea. It’s more complex than C#’s dynamic feature, though (because that relies on a well-documented API). Here’s what the MSDN says:

1)这里有一个很好的说明为什么使用选项Strict Off不是一个好主意:我使用了VB。NET近十年来,直到几年前才正式发布,我完全不知道a = b有什么限制,它做了一些平等的比较,但是到底发生了什么,为什么,不知道。它比c#的动态特性要复杂得多(因为它依赖于一个有良好文档记录的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.

由于选项Strict提供了强类型,防止出现数据丢失的非预期类型转换,不允许延迟绑定,并提高了性能,因此强烈建议使用它。

2) Jon has mentioned one exception, strings, where equality comparison does some more things for reasons of backwards compatibility.

Jon提到了一个例外,字符串,在这里,由于向后兼容的原因,相等比较会做更多的事情。

#3


4  

Object instances are not compared with the operator "==". You should to use method "equals". With "==" operator are comparing references, not objects.

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

Try this:

试试这个:

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");
}

Results:

结果:

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

Now, try this:

现在,试试这个:

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");
}

Results:

结果:

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

#4


3  

The issue is that the == operator in C# is a call to a static method (well, maybe not technically, but it can be though of as such) based on the compile time type of the two parameters. What the actual runtime types of those objects are doesn't matter.

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

Based on that compile time type the compiler will determine what implementation of operator == to use. It might use the default object implementation, it might use one of the numeric overloads provided by the language, or it could be a user defined implementation.

基于编译时类型,编译器将确定要使用的操作符==的实现。它可能使用默认的对象实现,可能使用语言提供的数字重载之一,也可能是用户定义的实现。

This is different from VB in that VB doesn't determine the implementation at compile time. It waits until runtime and inspects the two parameters that it is given to determine which implementation of the == operator it should use.

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

Your code contains boolean values, but they are in variables that are of type object. Because the variable is of type object, the C# compiler use the object implementation of ==, which compares the references, not the object instances. Since the boolean values are boxes, they don't have the same reference, even though their values are the same.

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

The VB code doesn't care what type the variable is. It waits until runtime and then checks the two variables, sees that they are actually of both of type boolean, and so uses the boolean == operator implementation. That implementation compares the values of the booleans, not their references (and the booleans will be unboxed before calling calling that operator, so a reference comparison doesn't even make sense any more). Because the values of the booleans are the same, it returns true.

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

#1


167  

In C#, the == operator (when applied to reference type expressions) performs a reference equality check unless it's overloaded. You're comparing two references which are the result of boxing conversions, so those are distinct references.

在c#中,==运算符(当应用于引用类型表达式时)执行一个引用等式检查,除非它重载。您正在比较两个引用,它们是装箱转换的结果,所以这些是不同的引用。

EDIT: With types which overload the ==, you can get different behaviour - but that's based on the compile-time type of the expressions. For example, string provides ==(string, string):

编辑:对于重载=的类型,您可以得到不同的行为—但是这是基于表达式的编译时类型的。例如,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

Here the first comparison is using the overloaded operator, but the second is using the "default" reference comparison.

这里,第一个比较使用重载操作符,第二个比较使用“默认”引用比较。

In VB, the = operator does a whole lot more work - it's not even just equivalent to using object.Equals(x, y), as things like Option Compare can affect how text is compared.

在VB中,=运算符要做更多的工作——它甚至不等同于使用对象。= (x, y),就像选项比较会影响文本的比较。

Fundamentally the operators don't work the same way and aren't intended to work the same way.

从根本上说,操作符不是以相同的方式工作的,也不打算以相同的方式工作。

#2


79  

In addition to Jon’s answer which explains the C# side of things, here’s what VB does:

除了Jon的答案解释了c#方面的内容之外,VB还做了以下工作:

In VB with Option Strict On, a comparison via = always tests for value equality and never for reference equality. In fact, your code doesn’t even compile once you switch Option Strict On because System.Object doesn’t define an Operator=. You should always have this option on, it catches bugs more effectively than a venus flytrap (although in your particular case this lax behaviour actually does the right thing).1

在VB中,选项严格为,通过=进行比较总是为了值相等而不是为了引用相等。事实上,您的代码甚至不会编译一旦您切换到严格的选择,因为系统。对象不定义运算符=。你应该总是有这个选项,它比捕蝇草更有效地捕捉虫子(尽管在你的特殊情况下,这种松懈的行为实际上是正确的)

In fact, with Option Strict On, VB behaves even stricter than C#: In C#, a == b either triggers a call to SomeType.operator==(a, b) or, if this doesn’t exist, invokes reference equality comparison (which is equivalent to calling object.ReferenceEquals(a, b)).

事实上,在选项严格的情况下,VB的行为甚至比c#:在c#中,a = b会触发对某一类型的调用。操作符==(a, b)或者,如果不存在,则调用引用相等比较(这等价于调用对象)。ReferenceEquals(a,b))。

In VB on the other hand, the comparison a = b always invokes the equality operator.2 If you want to use reference equality comparison, you have to use a Is b (which is, once again, the same as Object.ReferenceEquals(a, b)).

另一方面,在VB中,比较a = b总是调用等式运算符。2如果你想要使用引用等式比较,你必须使用a是b(同样的,和对象是一样的)。ReferenceEquals(a,b))。


1) Here’s a good indication why using Option Strict Off is a bad idea: I’ve used VB.NET for almost a decade, from before .NET’s official release until a few years ago, and I’ve absolutely no idea what a = b does with Option Strict Off. It does some kind of equality comparison, but what exactly happens and why, no idea. It’s more complex than C#’s dynamic feature, though (because that relies on a well-documented API). Here’s what the MSDN says:

1)这里有一个很好的说明为什么使用选项Strict Off不是一个好主意:我使用了VB。NET近十年来,直到几年前才正式发布,我完全不知道a = b有什么限制,它做了一些平等的比较,但是到底发生了什么,为什么,不知道。它比c#的动态特性要复杂得多(因为它依赖于一个有良好文档记录的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.

由于选项Strict提供了强类型,防止出现数据丢失的非预期类型转换,不允许延迟绑定,并提高了性能,因此强烈建议使用它。

2) Jon has mentioned one exception, strings, where equality comparison does some more things for reasons of backwards compatibility.

Jon提到了一个例外,字符串,在这里,由于向后兼容的原因,相等比较会做更多的事情。

#3


4  

Object instances are not compared with the operator "==". You should to use method "equals". With "==" operator are comparing references, not objects.

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

Try this:

试试这个:

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");
}

Results:

结果:

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

Now, try this:

现在,试试这个:

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");
}

Results:

结果:

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

#4


3  

The issue is that the == operator in C# is a call to a static method (well, maybe not technically, but it can be though of as such) based on the compile time type of the two parameters. What the actual runtime types of those objects are doesn't matter.

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

Based on that compile time type the compiler will determine what implementation of operator == to use. It might use the default object implementation, it might use one of the numeric overloads provided by the language, or it could be a user defined implementation.

基于编译时类型,编译器将确定要使用的操作符==的实现。它可能使用默认的对象实现,可能使用语言提供的数字重载之一,也可能是用户定义的实现。

This is different from VB in that VB doesn't determine the implementation at compile time. It waits until runtime and inspects the two parameters that it is given to determine which implementation of the == operator it should use.

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

Your code contains boolean values, but they are in variables that are of type object. Because the variable is of type object, the C# compiler use the object implementation of ==, which compares the references, not the object instances. Since the boolean values are boxes, they don't have the same reference, even though their values are the same.

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

The VB code doesn't care what type the variable is. It waits until runtime and then checks the two variables, sees that they are actually of both of type boolean, and so uses the boolean == operator implementation. That implementation compares the values of the booleans, not their references (and the booleans will be unboxed before calling calling that operator, so a reference comparison doesn't even make sense any more). Because the values of the booleans are the same, it returns true.

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