none
decimal in a datatable - == and equals disagreeing RRS feed

  • Question

  • In a simple data table, with a decimal column I am getting different results when using Equals and ==.  I'm sure there is a good reason for this, I just cannot find it - can anyone please explain to me why these would be different?  

    using System.Data;
    
    namespace ConsoleApplication1
    {
        class Program
        {
            static void Main(string[] args)
            {
                DataTable dt = new DataTable();
                dt.Columns.Add(new DataColumn("amount", typeof(int)));
                dt.Columns.Add(new DataColumn("code", typeof(string)));
    
                DataRow dr = dt.NewRow();
                dr["amount"] = 10;
                dr["code"] = "A";
    
                dt.Rows.Add(dr);
                dr.AcceptChanges();
    
                bool a = dr["amount", DataRowVersion.Current].Equals(dr["amount", DataRowVersion.Original]);
                bool b = dr["amount", DataRowVersion.Current] == dr["amount", DataRowVersion.Original];
    
                bool c = dr["code", DataRowVersion.Current].Equals(dr["code", DataRowVersion.Original]);
                bool d = dr["code", DataRowVersion.Current] == dr["code", DataRowVersion.Original];
            }
        }
    }

    While I fully expect c and d to be equal, notice that a and b are not considered equal when using the == operator.  ??

    Monday, November 10, 2014 7:24 PM

Answers

  • Hello John,

    >>Makes sense - but what confuses me is why would the string class behave differently?

    If you use the ildasm.exe to see the IL code, you could see that for the int type column, it performs the box behavior:

        IL_0050:  ldstr      "amount"
    
        IL_0055:  ldc.i4.s   10
    
        IL_0057:  box        [mscorlib]System.Int32
    
    IL_005c:  callvirt   instance void [System.Data]System.Data.DataRow::set_Item(string, object)
    

    So this comparison using “==” would compare two different object for the int type column.

    While for the string type column, it does not perform the box behavior:

        IL_0063:  ldstr      "code"
    
        IL_0068:  ldstr      "A"
    
    IL_006d:  callvirt   instance void [System.Data]System.Data.DataRow::set_Item(string, object)
    

    So it should still compare the same object.

    Regards.


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    • Marked as answer by John Hennesey Tuesday, November 11, 2014 2:11 PM
    Tuesday, November 11, 2014 3:02 AM
    Moderator
  • Makes sense - but what confuses me is why would the string class behave differently? 

    For strings, you should take into consideration some specific aspects. In contrast with numbers, a string is already an object (since it derives from object), therefore no boxing is performed. In addition, to conserve storage, similar literal strings are represented by the same string instance due to “string interning” mechanism [http://msdn.microsoft.com/en-us/library/system.string.isinterned(v=vs.110).aspx].

    In the next experiment, objects ox and oy represents the same object, which can be checked with ReferenceEqual:

    string x = "A";

    string y = "A";

    object ox = x;

    object oy = y;

    Console.WriteLine( ox == oy ); // True

    Console.WriteLine( object.ReferenceEquals( ox, oy ) ); // True

    If you want to achieve a situation when two similar strings are stored in two distinct string objects, then try this:

    string x = 1234.ToString();

    string y = 1234.ToString();

    object ox = x;

    object oy = y;

    Console.WriteLine( ox == oy ); // False

    Console.WriteLine( object.ReferenceEquals( ox, oy ) ); // False

     

    In order to reduce the storage and force keeping these strings in the same internal object, consider this:

    string x = string.Intern( 1234.ToString() );

    string y = string.Intern( 1234.ToString() );

    • Marked as answer by John Hennesey Tuesday, November 11, 2014 2:11 PM
    Tuesday, November 11, 2014 8:40 AM

All replies

  • I suggest this experiment:

    decimal x = 1234;

    decimal y = 1234;

    object ox = x;

    object oy = y;

    Console.WriteLine( x == y ); // True

    Console.WriteLine( ox == oy ); // False

    Console.WriteLine( ox.Equals( oy ) ); // True

    Console.WriteLine( (decimal)x == (decimal)y ); // True

    The False result is caused by the fact that objects ox and oy, even if both contain the same 1234 value, represent two different memory objects, created automatically in the ox = x and oy = y lines during a process, which is called “boxing” [http://msdn.microsoft.com/en-us/library/yz2be5wk.aspx]. The ‘==’ operator only tests here if the operands represents the same object. The Equals function performs more job and also compare the contained values.

    DataTable is a class that keeps objects, including boxed ones.


    • Edited by Viorel_MVP Tuesday, November 11, 2014 8:41 AM Changed 'oy = x' to 'oy = y'.
    Monday, November 10, 2014 8:30 PM
  • Makes sense - but what confuses me is why would the string class behave differently? 
    Monday, November 10, 2014 8:44 PM
  • Hello John,

    >>Makes sense - but what confuses me is why would the string class behave differently?

    If you use the ildasm.exe to see the IL code, you could see that for the int type column, it performs the box behavior:

        IL_0050:  ldstr      "amount"
    
        IL_0055:  ldc.i4.s   10
    
        IL_0057:  box        [mscorlib]System.Int32
    
    IL_005c:  callvirt   instance void [System.Data]System.Data.DataRow::set_Item(string, object)
    

    So this comparison using “==” would compare two different object for the int type column.

    While for the string type column, it does not perform the box behavior:

        IL_0063:  ldstr      "code"
    
        IL_0068:  ldstr      "A"
    
    IL_006d:  callvirt   instance void [System.Data]System.Data.DataRow::set_Item(string, object)
    

    So it should still compare the same object.

    Regards.


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    • Marked as answer by John Hennesey Tuesday, November 11, 2014 2:11 PM
    Tuesday, November 11, 2014 3:02 AM
    Moderator
  • Makes sense - but what confuses me is why would the string class behave differently? 

    For strings, you should take into consideration some specific aspects. In contrast with numbers, a string is already an object (since it derives from object), therefore no boxing is performed. In addition, to conserve storage, similar literal strings are represented by the same string instance due to “string interning” mechanism [http://msdn.microsoft.com/en-us/library/system.string.isinterned(v=vs.110).aspx].

    In the next experiment, objects ox and oy represents the same object, which can be checked with ReferenceEqual:

    string x = "A";

    string y = "A";

    object ox = x;

    object oy = y;

    Console.WriteLine( ox == oy ); // True

    Console.WriteLine( object.ReferenceEquals( ox, oy ) ); // True

    If you want to achieve a situation when two similar strings are stored in two distinct string objects, then try this:

    string x = 1234.ToString();

    string y = 1234.ToString();

    object ox = x;

    object oy = y;

    Console.WriteLine( ox == oy ); // False

    Console.WriteLine( object.ReferenceEquals( ox, oy ) ); // False

     

    In order to reduce the storage and force keeping these strings in the same internal object, consider this:

    string x = string.Intern( 1234.ToString() );

    string y = string.Intern( 1234.ToString() );

    • Marked as answer by John Hennesey Tuesday, November 11, 2014 2:11 PM
    Tuesday, November 11, 2014 8:40 AM
  • Very thorough and readable responses!  Thank you both very much - it's clear now.

    John

    Tuesday, November 11, 2014 2:11 PM