2009-10-18 46 views
2

我应该从下面的结果中对Equals(),ReferenceEquals()和==做出什么决定?他们生产什么?Value vs Reference

#region 
int integer = 1; 
int integer2 = integer; 

bool referenceEquality = (integer == integer2);//true 
bool valueEquality = integer.Equals(integer2);//true 
bool valueEqualityMore = object.Equals(integer, integer2);//true 
bool valueEqualityMoreMore = object.ReferenceEquals(integer, integer2);//false 
#endregion 

#region 
int integer = 1; 
int integer2 = 1; 

bool referenceEquality = (integer == integer2);//true 
bool valueEquality = integer.Equals(integer2);//true 
bool valueEqualityMore = object.Equals(integer, integer2);//true 
bool valueEqualityMoreMore = object.ReferenceEquals(integer, integer2);//false 
#endregion 

#region 
MyClass obj = new MyClass(1, "Hello"); 
MyClass obj2 = obj; 

bool referenceEquality = (obj == obj2);//true 
bool valueEquality = obj.Equals(obj2);//true 
bool valueEqualityMore = object.Equals(obj, obj2);//true 
bool valueEqualityMoreMore = object.ReferenceEquals(obj, obj2);//true    
#endregion 

#region 
MyClass obj = new MyClass(1, "Hello"); 
MyClass obj2 = new MyClass(1, "Hello"); 

bool referenceEquality = (obj == obj2);//false 
bool valueEquality = obj.Equals(obj2);//false 
bool valueEqualityMore = object.Equals(obj, obj2);//false 
bool valueEqualityMoreMore = object.ReferenceEquals(obj, obj2);//false 
#endregion 

地狱!我一点都没懂。

对我来说,第一个block的referenceEquals()应该返回true。 ==在第二个块中应该返回false(因为引用是不同的)。 而且,第四块中的两个Equals()应该返回true(因为它们的值相同)。

+1

您可以缩小你的问题,具体如下: 1)这些结果你发现令人惊讶的 2)你在说什么决定 – Mathias 2009-10-18 16:09:58

+0

好评。查看更新。 – anonymous 2009-10-18 16:13:37

+1

referenceEquals比较对象实例引用,因为int值是对两个不同对象的框,它们具有不同的引用。 ==默认情况下比较引用,所以即使具有相同状态的MyClass的两个实例也具有不同的引用,因为它们是两个不同的对象。 – Elisha 2009-10-18 16:19:31

回答

8

您似乎遇到的第一个混淆之处在于,对于值类型,即int,float,DateTime==运算符是值相等。对于引用类型,==是(默认情况下,请参见下文)引用相等。这可以解释前两个整数情况下答案的不一致性。

其次,默认实现Equals()测试引用相等,而不是值相等。因此,MyClass似乎不会覆盖Equals(),这解释了您的参考案例之间的答案不一致。

此外,许多参考类型(例如String)会覆盖==运算符以提供值相等的语义。所以你最好的选择,直到你记住哪些类型是哪一个,就是查找文档。

简而言之:

  • 值类型
    • ==是值相等(对于框架类型)
    • 不是引用类型,所以引用相等是无意义
  • 参考类型
    • ReferenceEquals()总是引用相等
    • ==是默认参考平等,但可以是(并且通常是用于骨架类型)覆盖,以提供值相等
    • Equals()是默认参考平等,但可以是(并且通常是为框架型)重写以提供值相等
+0

所有这一切的一个很好的更新可以在这里找到:http:// stackoverflow .com/questions/384294/where-the-implementation-of-internalequalsobject-obja-object-objb,它展示了C++代码的内幕。基本上,它明确表明值类型被“Equals”特别对待。 – Abel 2009-10-18 16:27:27

1

ReferenceEquals两个对象是相同的,如果它们指向存储器中的同一个地方。对于两种不同的值类型,情况从来就不是这样。

Equals如果等于覆盖认为它们相等,则两个对象相等。这通常意味着如果ReferenceEqual将返回true,并且这些属性返回true。每个对象或结构对于Equals的行为往往不同。 注意:每个内置值类型(int,double,IntPtr)已被重写Equals,这就是为什么它对值类型(比较内容)和ReferenceEquals(比较地址)有所不同。

==返回true,如果两个对象具有相同的引用,或如果两个值类型具有相同的内容。盒装值类型在进行比较之前先进行拆箱,然后将它们明确地转换为对象。

请注意,您的new MyClass(...)返回虚假Equals。这是因为MyClass的执行没有覆盖Equals方法。结果:它的行为与ReferenceEquals相同。

更新:在Equals值类型

+0

整数ReferenceEquals()发生了什么? – anonymous 2009-10-18 16:09:28

+0

而且,为什么int整数= 1; int integer2 = 1; bool referenceEquality =(integer == integer2); // true – anonymous 2009-10-18 16:10:22

+0

== ==直接调用'ReferenceEquals'的行为不同。对于值类型,其行为与调用“Equals”相同。 – Abel 2009-10-18 16:13:41

1

ReferenceEquals检查补充说明,如果两个对象引用指向同一对象。也就是说,他们指向内存中的相同位置。

Equals是一个虚拟的方法,所以它可能在实践中被重写做任何事情。然而,该方法的目的是以某种对于类型有意义的方式比较实例,无论采用何种方式。如果Equals未被覆盖,则使用object.Equals的实现,其相当于ReferenceEquals

== 是相等运算符,默认情况下,它为引用类型(即类,盒装值类型,接口)和值类型实例(即结构体)比较引用相等性和值相等(字段值相同) 。 ==可能被重载以提供自定义行为,但它不是虚拟的,如Equals

通过它传递给像ReferenceEquals的方法,其具有object参数,盒int,产生与内部的整数的堆中的对象使用一个int作为object,例如。基本上是指object.ReferenceEquals((object)integer1, (object)integer2)

通过引用相等(ReferenceEquals==)相同的整数的不同盒装实例比较将给false,而值相等(Equals)会给true。对于未装箱的相同整数(值类型),==Equals都比较值相等,因此会给出true

1

默认情况下,当用作a==b时,operator==的行为如下。请注意,operator==可以被覆盖以执行任何操作。

  • 如果a是值类型,则编译为a.Equals(b)
  • 如果a是引用类型,则编译为object.Equals(a,b)

object.Equals(a, b)只在引用类型进行操作,并执行以下操作:

  • 如果anull,然后返回(b==null)
  • 否则调用a.Equals(b)

object.ReferenceEquals(a, b)只在引用类型进行操作。 C#/ .NET中的对象引用在内部保存为指针。如果引用ab是相同的,也就是说,如果它们在内部指向同一对象,则此方法返回true。

数值类型以两种形式存在:unboxed盒装。在下列情况下讨论值类型,我会使用以下变量:

int unboxed = 3; 
// boxing occurs automatically when a value type is cast to object or 
// to an interface. This allocates memory on the heap to store the value 
// and places a reference (internally a pointer) to this memory in boxed. 
object boxed = unboxed; 

在这一点上,boxed表现为引用类型。两个装箱值可能不在内存中的相同位置,如您在拨打object.ReferenceEquals(integer1, integer2)时看到的那样(由于将每个参数转换为object而发生自动装箱)。当您拨打object.Equals(integer1, integer2)时,这些值将被装箱,但由于BOX的形式为integer1不为空,因此呼叫的行为类似于integer1.Equals((object)integer2),由于装箱值均为1,所以返回true。 (请参阅下面关于为什么我在这里手动投射的注释)。

注意的手动投以上:System.Int32,与大多数其他值类型一起,有一个方法Int32.Equals(Int32 other),因此调用integer1.Equals(integer2)不会箱integer2值。这对轻量级值类型的性能有很大(正面)影响。

1

我对所做的实际比较做了更正。我为所有情况添加了相同的比较,因为您只对整数(使用==运算符)进行.Equals(int),而对其他类型不使用.Equals(object)。我还添加了明确铸件的参数显示,通过使用它们作为参数,其隐含的铸件所引起:

int integer = 1; 
int integer2 = 1; // exactly the same result as copying integer 

bool valueEquality = (integer == integer2); //true 
bool valueEquality2 = integer.Equals(integer2); //true 
bool typeAndValueEquality = integer.Equals((object)integer2); //true 
bool typeAndValueEquality2 = object.Equals((object)integer, (object)integer2); //true 
bool referenceEquality = object.ReferenceEquals((object)integer, (object)integer2); //false 

// 

MyClass obj = new MyClass(1, "Hello"); 
MyClass obj2 = obj; 

bool referenceEquality = (obj == obj2); //true 
bool referenceEquality2 = obj.Equals((object)obj2); //true 
bool typeAndReferenceEquality = object.Equals((object)obj, (object)obj2); //true 
bool referenceEquality3 = object.ReferenceEquals((object)obj, (object)obj2); //true 

// 

MyClass obj = new MyClass(1, "Hello"); 
MyClass obj2 = new MyClass(1, "Hello"); 

bool referenceEquality = (obj == obj2); //false 
bool referenceEquality2 = obj.Equals((object)obj2); //false 
bool typeAndReferenceEquality = object.Equals((object)obj, (object)obj2); //false 
bool referenceEquality = object.ReferenceEquals((object)obj, (object)obj2); //false 
+0

@Guffa,非常好。如果您之前发布过此消息,我已经接受了您的答案。 – anonymous 2009-10-19 09:43:37