我在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 |
- 如果将相等比较器更改为a.Equals(b),会怎么样?
- 这是一个很好的教学问题。
- 因为你的vb.net代码不等于你的c代码。
- 当您分配给a时,您将得到装箱并创建一个包含true的框。当您分配给b时,会得到另一个包含true的框。当您比较a和b时,由于它们都是编译时类型object的,所以您调用由C语言规范定义的重载operator ==(object, object)。此重载检查引用是否指向同一对象。因为您有两个框,所以结果是false,并且"your if"下面的语句将不会运行。为了更好地理解这一点,请尝试将b的赋值改为:object b = a;,现在您只有一个框。
- 我以前曾说过"小心假设vb.net和c是用不同口音说的同一种语言-它们不是"
在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这样的东西会影响文本的比较方式。
从根本上讲,操作人员的工作方式不一样,也不打算以同样的方式工作。
- +我知道你会在身边,你喜欢这些神秘的问题:)
- @Abzy:我希望能够对=在VB中所做的工作提供更详细的解释,但是规范并不是非常清楚。
- 有趣的是,但是将对象更改为动态的行为与vb相同
- @VLADL:是的,因为它将按执行时间类型进行,并执行bool == bool比较。
- 谢谢你,乔恩。我已将您的答案标记为最终答案,但必须将其更改为Lobo答案,因为他也提供了解决方案。不过谢谢
- @MahdiLobo可能提供了代码,但他的回答也错了,不像Jon的。
- 我对你对我答案的评论感兴趣。它是否准确地反映了正在发生的事情?
- 你怎么能一直回答那些简单的/流行的问题?:)
- @佩里,当你回答24536个问题时,其中一些肯定会受到欢迎。
- @服务生:那他是怎么做到的?他回答了24536个问题!?)
- @阿布兹:你说的完全正确,埃多克斯1〔2〕肯定会在这附近……
除了乔恩的答案解释了事物的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 = b与Option 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提到了一个例外,字符串,因为向后兼容性的原因,相等比较可以做更多的事情。
- + 1。我认为这是一个例子,在这个例子中,vb.net的设计者成功地使来自vb6和vba的程序员使用"just work"语言,而oop则不那么突出,因此引用相等的概念就不那么重要了。一个VB程序员可以在不考虑对象等的情况下编写良好的工作代码。
- +1这并不像它真正应该的那样被否决。不使用Option Strict On必须被视为刑事犯罪…
- @约翰姆甘特:一个不了解引用标识重要性的编码人员可能能够编写出工作时发生的代码,但不太可能真正知道什么事情可以安全地更改,什么更改总是会破坏事情,什么更改可能看起来工作,但会造成不必要的不良副作用(例如导致什么应该是引用)对具有相同状态的不同可变对象的引用。如果对象很少发生变化,这种变化可能不会引起任何立即的问题,但可能会使以后很难发现错误。
对象实例不与运算符"=="进行比较。您应该使用方法"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 |
- 这仅仅是因为您没有覆盖operator ==。如果您超越了该操作符,而不等于,那么您的输出将被反转。比较operator ==中的参考值并不是固有的,比较Equals中的值也不是固有的。它们只是确定相等性的两种方法;它们都有引用比较的默认实现,并且都可以被重写以执行您希望它们执行的任何操作。唯一的区别是,Equals是虚拟的,而operator ==不是虚拟的。
- @Servy:请注意,您不能覆盖==—您只能超载它。
- @琼斯基特,你是对的,我的错。
- 抱歉,- 1。这个答案是错误的,不应该被接受。
- 在某处有一个Java问题等待这个答案。
问题是C中的==运算符是基于两个参数的编译时类型对静态方法的调用(好吧,从技术上讲可能不是,但也可以这样)。这些对象的实际运行时类型并不重要。
基于该编译时类型,编译器将确定要使用的operator ==的实现。它可以使用默认的object实现,也可以使用语言提供的数值重载之一,或者可以是用户定义的实现。
这与vb不同,因为vb在编译时不确定实现。它一直等到运行时,检查给定的两个参数,以确定它应该使用哪个==运算符的实现。
您的代码包含布尔值,但它们位于object类型的变量中。由于变量的类型为object,C编译器使用==的object实现,它比较引用,而不是对象实例。因为布尔值是框,所以它们没有相同的引用,即使它们的值相同。
VB代码不关心变量的类型。它一直等到运行时,然后检查这两个变量,发现它们实际上都是布尔型的,因此使用布尔型==运算符实现。该实现比较布尔值,而不是它们的引用(在调用该运算符之前,布尔值将被取消装箱,因此引用比较甚至不再有意义)。因为布尔值相同,所以返回true。
- 对于C来说,这看起来很好,我不太清楚=在vb中究竟做了什么。
- @乔斯基特很公平。
- 根据msdn.microsoft.com/en-us/library/cey92b0t(v=vs.110).aspx,在"使用关系比较运算符的无类型编程"部分:=以及所有其他关系比较运算符(如<和>=等)在运算符的两侧或任一侧都是Object时给予特殊处理。这种特殊处理的目的是使vb6程序员习惯于在pre-net vb中使用一种称为Variant的类型,他们可以以以前使用Variant的方式在vb.net中使用Object。
- 换言之,除了重载和Option Strict On的影响之外,vb =倾向于将Object拆箱,直到它可以得到字符串或数字。