Barış Velioğlu
Barış Velioğlu

Reputation: 5817

Object equality behaves different in .NET

I have these statements and their' results are near them.

string a = "abc";
string b = "abc";

Console.Writeline(a == b); //true

object x = a;
object y = b;

Console.Writeline(x == y); // true

string c = new string(new char[] {'a','b','c'});
string d = new string(new char[] {'a','b','c'});

Console.Writeline(c == d); // true

object k = c;
object m = d;

Console.Writeline(k.Equals(m)) //true

Console.Writeline(k == m); // false

Why the last equality gives me false ?

The question is why ( x == y ) is true ( k == m ) is false

Upvotes: 6

Views: 710

Answers (9)

Sessamekesh
Sessamekesh

Reputation: 430

The == operator compares references (the memory addresses) while .Equals compares the actual object values. In the case of string, you get lucky and two identical strings can refer to the same address frequently. One of the joys of managed languages.

Upvotes: 0

rskar
rskar

Reputation: 4657

Building on Bob2Chiv's, I tried the equivalent in VB (VS2010):

    Dim a As String = "abc"
    Dim b As String = "abc"

    Console.WriteLine(a = b) ' True

    Dim x As Object = a
    Dim y As Object = b

    Console.WriteLine(x = y) ' True

    Dim c As String = New String(New Char() {"a"c, "b"c, "c"c})
    Dim d As String = New String(New Char() {"a"c, "b"c, "c"c})

    Console.WriteLine(c = d) ' True

    Dim k As Object = c
    Dim m As Object = d

    Console.WriteLine(k.Equals(m)) ' True

    Console.WriteLine(k = m) ' True (Yes, True!!)

    Console.WriteLine(k Is m) ' False (Like in C#)

    Console.WriteLine(a Is b) ' True (Like in C#)

(At least I think it's the equivalent - I welcome being corrected on this.)

Moral?: Be careful of == in C# - prefer .Equals() when the comparison of values is what's desired?

Upvotes: 1

cHao
cHao

Reputation: 86506

When you say string1 == string2, the comparison uses the string type's overloaded == operator, which compares the strings' values.

When you say object1 == object2, even though they're strings in this case, they won't qualify as strings for the purposes of finding an operator. So the comparison uses the default == operator, which compares the references for equality. Which means, if the two objects aren't the exact same object, it will return false.

Upvotes: 1

Tim Schmelter
Tim Schmelter

Reputation: 460028

String has overloaded the equality operator so that you can use == for value comparison. Hence

a == b //true.

When you're downcasting them to object, you're only comparing references. String looks into an internal string-pool if another string instance is already available, otherwise a new instance will be created and added to the pool. So actually a, b, x and y are even the same reference, that's why

x == y //true.

With using the constructor of String, you're forcing .NET to create a new instance even if another string with the same value(length and character sequence) exists. That's why

k == m //false

http://en.csharp-online.net/CSharp_String_Theory%E2%80%94String_intern_pool

Upvotes: 1

Krisc
Krisc

Reputation: 1427

As seen on C# FAQ on MSDN - the compiler cannot use the overloaded method and falls back to comparing the references.

The bigger question is why it succeeds in the first object comparison. My best guess is that succeeds because a and b are both given the same reference. For c and d, you are forcing different references.

Upvotes: 1

Oded
Oded

Reputation: 498904

In the case of strings, the == operator is overloaded to test for value equality, when using object reference equality is used.

Since c and d are strings, when you use Equals in the k and m, the overloaded method is used.

And c == d is true for the reason state above - value equality is used on string types as the operator is overloaded.

Upvotes: 10

Tigran
Tigran

Reputation: 62248

   string c = new string(new char[] {'a','b','c'});
   string d = new string(new char[] {'a','b','c'});

   Console.WriteLine(c == d); // true

   object k = c;
   object m = d;

   Console.WriteLine(k.Equals(m)); //true

   Console.WriteLine(k == m); // false

Generates IL code, like this:

IL_0001:  ldc.i4.3    
IL_0002:  newarr      System.Char
IL_0007:  dup         
IL_0008:  ldtoken     <PrivateImplementationDetails>{61BB33F4-0CA5-4733-B259-764124AD1A79}.$$method0x6000002-1
IL_000D:  call        System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray
IL_0012:  newobj      System.String..ctor
IL_0017:  stloc.0     
IL_0018:  ldc.i4.3    
IL_0019:  newarr      System.Char
IL_001E:  dup         
IL_001F:  ldtoken     <PrivateImplementationDetails>{61BB33F4-0CA5-4733-B259-764124AD1A79}.$$method0x6000002-2
IL_0024:  call        System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray
IL_0029:  newobj      System.String..ctor
IL_002E:  stloc.1     
IL_002F:  ldloc.0     
IL_0030:  ldloc.1     
IL_0031:  call        System.String.op_Equality   //STRING EQUALITY 
IL_0036:  call        System.Console.WriteLine
IL_003B:  nop         
IL_003C:  ldloc.0     
IL_003D:  stloc.2     
IL_003E:  ldloc.1     
IL_003F:  stloc.3     
IL_0040:  ldloc.2     
IL_0041:  ldloc.3     
IL_0042:  callvirt    System.Object.Equals
IL_0047:  call        System.Console.WriteLine
IL_004C:  nop         
IL_004D:  ldloc.2     
IL_004E:  ldloc.3     
IL_004F:  ceq         //CEQ INSTRUCTION: **VALUES** EQUALITY !
IL_0051:  call        System.Console.WriteLine

As you can see the last instruction call CEQ instruction that makes comparison of values equality pushed on stack. The values pushed on stack are references of both boxed string, which are not equal.

Upvotes: 2

Bob2Chiv
Bob2Chiv

Reputation: 1968

string a = "abc"; 
string b = "abc"; 

Console.Writeline(a == b); //true 

String references are the same for the same string due to String Interning

object x = a; 
object y = b; 

Console.Writeline(x == y); // true 

Because the references are the same, two objects created from the same reference are also the same.

string c = new string(new char[] {'a','b','c'}); 
string d = new string(new char[] {'a','b','c'}); 

Here you create two NEW arrays of characters, these references are different.

Console.Writeline(c == d); // true 

Strings have overloaded == to compare by value.

object k = c; 
object m = d; 

Since the previous references are different, these objects are different.

Console.Writeline(k.Equals(m)) //true 

.Equals uses the overloaded String equals method, which again compare by value

Console.Writeline(k == m); // false 

Here we check to see if the two references are the same... they are not

The key is figuring out when an equality is comparing references or values.

Objects, unless otherwise overloaded, compare references.

Structs, unless otherwise overloaded, compare values.

Upvotes: 9

Nick
Nick

Reputation: 25799

Because they are two different object references. The built-in comparison for this is to compare whether they point to the same actual object or not.

Due to String Interning, a and b are both references to the same string object.

c==d is true because the string equality operator is being used.

Upvotes: 3

Related Questions