Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Object equality behaves different in .NET

Tags:

c#

.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

like image 937
Barış Velioğlu Avatar asked Apr 16 '12 15:04

Barış Velioğlu


People also ask

Is == and Equals the same in C#?

Difference between == and . Equals method in c# The Equality Operator ( ==) is the comparison operator and the Equals() method in C# is used to compare the content of a string. The Equals() method compares only content.

Which is better Equals or == in C#?

Answering to the point “There is no difference between equality comparison using “==” and “Equals()”, except when you are comparing “String” comparison. The common comparison Rule :-Whenever youare comparing variables they are either value types or reference types.

How do you equal an object in C#?

The most common way to compare objects in C# is to use the == operator. For predefined value types, the equality operator (==) returns true if the values of its operands are equal, false otherwise. For reference types other than string, == returns true if its two operands refer to the same object.

What is the difference between == and === in C#?

== is the equality operator it is used to determine if variable is equal to another variable. === is the operator for strict equality, this checks not only that what is in the bucket is the same, but that the type of variable is also the same, so for instance...


8 Answers

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.

like image 124
Oded Avatar answered Oct 06 '22 01:10

Oded


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.

like image 25
Bob2Chiv Avatar answered Oct 06 '22 02:10

Bob2Chiv


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.

like image 31
Nick Avatar answered Oct 06 '22 02:10

Nick


   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.

like image 44
Tigran Avatar answered Oct 06 '22 00:10

Tigran


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.

like image 34
Krisc Avatar answered Oct 06 '22 02:10

Krisc


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

like image 37
Tim Schmelter Avatar answered Oct 06 '22 02:10

Tim Schmelter


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.

like image 30
cHao Avatar answered Oct 06 '22 00:10

cHao


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?

like image 27
rskar Avatar answered Oct 06 '22 00:10

rskar