views:

200

answers:

7

I have a the following code:

object val1 = 1;
object val2 = 1;

bool result1 = (val1 == val2);//Equals false
bool result2 = val1.Equals(val2); //Equals true

What's up with that? is the only way to fix this to go with .Equals() method?

+9  A: 

yes. == checks for reference equality. use Equals where you want to compare content.

you might be wondering why this is so with objects. When you set integer (value type) to object variable operation called boxing happens. This operation wraps value type into object and put to heap and returns reference. this happens twice and references get different. (although values are same)

Andrey
+1  A: 

That is because when you cast them to objects they are "converted" to references to int values. And the two references are not equal But equals compares the referenced values instead of the references

Falle1234
+14  A: 

The operator == is static, not virtual, so the behaviour is determined by the static type and not the runtime type. The default implementation for == on objects of reference type is to compare the references (although types can implement a different behaviour, for example string). You have two different objects and they don't have the same reference so == returns false.

The solution, as you point out, is to use Equals. Equals is a virtual method. Since value1 has runtime type Int32 you end up calling Int32.Equals. From .NET Reflector you can see that the implementation of this is as follows:

public override bool Equals(object obj)
{
    return ((obj is int) && (this == ((int) obj)));
}

In other words, it checks if the argument is of type int, and if so casts it and uses the == that is defined for int. This compares the values of the integers.

Is the only way to fix this to go with .Equals() method?

An alternative is to cast your objects to int and then use ==, just as the implementation of Int32.Equals does.

Mark Byers
This seems to be the only correct answer (or, at least, I'm pretty sure you can use == on string and have it work as expected).
tc.
Okay, I don't understand why *Equals* works here. According to the docs http://msdn.microsoft.com/en-us/library/bsc2ak47.aspx "The default implementation of *Equals* supports reference equality for reference types, and bitwise equality for value types. Reference equality means the object references that are compared refer to the same *object*. "
John C
@John C: Good question. Does my updated answer make it clearer?
Mark Byers
@Mark yes, thanks, that makes sense now. And I presume for your own user-defined classes, you're expected to supply your own definition of Equals.
John C
A: 

Two objects are equal if they point to the same space in memory.

val1 == val1; //Equals true

As pointed by tc you can make an operator overload.

public static bool operator ==(Object a, Object b)

This way the behavior of the operator == will be the one defined by this method.

You should also overload the operator != when you overload ==.

Daniel Moura
Unless there's an operator overload.
tc.
@tc corrected my anwser. thanks.
Daniel Moura
+2  A: 

== checks whether the two objects are identical. They are not. They represent the same number, but are stored at different locations in memory.

It’s like comparing two apples. Both are apples and look the same, but they are different objects.

Scytale
A: 

If you aren't using object but a custom class, you can override the == and != operators, and should probably implement the IEqualityComparer<T> interface

public static bool operator ==(MyType left, MyType right)
{
    //code here, don't forget about NULLS when writing comparison code!!!
}

public static bool operator !=(MyType left, MyType right)
{
    return !(left == right);
}

public bool Equals(MyType x, MyType y)
{
    return (x == y);
}

public int GetHashCode(MyType obj)
{
    return base.GetHashCode();
}
Chad
A: 

The IL for your code boxes the two integers, then compares the two objects that result from the boxing (==). This comparison is by reference.

  .locals init ([0] object val1,
           [1] object val2,
           [2] bool result1,
           [3] bool result2)
  IL_0000:  nop
  IL_0001:  ldc.i4.1
  IL_0002:  box        [mscorlib]System.Int32
  IL_0007:  stloc.0
  IL_0008:  ldc.i4.1
  IL_0009:  box        [mscorlib]System.Int32
  IL_000e:  stloc.1
  IL_000f:  ldloc.0
  IL_0010:  ldloc.1
  IL_0011:  ceq
  IL_0013:  stloc.2
  IL_0014:  ldloc.0
  IL_0015:  ldloc.1
  IL_0016:  callvirt   instance bool [mscorlib]System.Object::Equals(object)
  IL_001b:  stloc.3

For the .Equals it calls Object.Equals, which calls Int32.Equals (virtual method call on Object):

public override bool Equals(object obj)
{
    return ((obj is int) && (this == ((int) obj)));
}

This casts to int and compares the values as integers, a value type comparison.

Simon D