1

Possible Duplicate:
What is “Best Practice” For Comparing Two Instances of a Reference Type?

I have this custom Class for my application. There are two instances (A and B) of this class, which I'm trying to compare. However, I'm having problems; I'm implementing the IEquatable<T> interface to do this comparison, using an overridden Equals methods.

The Equals methods calls the ReferenceEquals function, which is misbehaving.

Here are the test cases:

Case 1: A and B are different instances, and contain different data .. ReferenceEquals says: They are different (which is correct !)

Case 2: A and B are different instances, but B was instantiated by using A's variable values (i.e. both A and B contain exactly same data!) .. ReferenceEquals says: They are different (which is wrong !)

Case 3: A and B are same instances (i.e. A is passed in twice e.g. Equals (A, A) ) ReferenceEquals says: They are same (which is correct !)

So how do I get the result of Case 2 to be correct as well ?

Class in which IEquatable<T> is implemented:

namespace DBtestApp1
{
    class QuantityBasedDiscount : IEquatable<QuantityBasedDiscount>
    {
        public string pType { get; set; }
        public string pSubType { get; set; }
        public DataTable quantityDiscountsDT { get; set; }

        public QuantityBasedDiscount()
        {
            pType = "";
            pSubType = "";
            quantityDiscountsDT = new DataTable();
        }

        public QuantityBasedDiscount(string iProdType, string iProdSubType, DataTable iQuantitiesDT)
        {
            pType = iProdType;
            pSubType = iProdSubType;
            quantityDiscountsDT = iQuantitiesDT;
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        public override bool Equals(Object obj)
        {

            var other = obj as QuantityBasedDiscount;
            if (other == null) return false;

            return Equals(other);
        }

        public bool Equals(QuantityBasedDiscount other)
        {
            if (other == null)
            {
                return false;
            }

            if (ReferenceEquals(this, other))
            {
                return true;
            }

            return false;
        }
    }
}

Code which calls the Equals method (configured for Case 2 here):

private bool AnyUnsavedChanges()
{
    QuantityBasedDiscount copyB = new QuantityBasedDiscount(copyA.pType, copyA.pSubType, copyA.quantityDiscountsDT);

    if (copyA.Equals(copyB))
    {
         return false; //They are the same!
    }
    else
    {
         return true; //They are NOT the same!
    }

}

So what's the problem in this code ?

Community
  • 1
  • 1
Ahmad
  • 12,886
  • 30
  • 93
  • 146
  • 1
    I dont understand case 2. _"... contain exactly same data. ReferenceEquals says: They are different which is wrong"_ `ReferenceEquals` determines whether the specified Object instances are the same instance and not if it has the same values. – Tim Schmelter Dec 23 '12 at 15:11
  • Oh I see ... How can I do such a comparison then for the case when the instance is different but values are the same ? I thought ReferenceEquals handles this situation too .. – Ahmad Dec 23 '12 at 15:14
  • @Ahmad: you must handle it manually, by comparing the current object fields with the other object fields... that's the purpose of overriding `Equals(object other)`... – digEmAll Dec 23 '12 at 15:27
  • Comparison fields individually would be an extremely difficult task, and I was looking to avoid that somehow ! Many other classes that I've defined that also need this instance comparison functionality, contain a lot of fields, whose datatypes are complex structures ... Surely there must be some way to do such a class instance comparison ? – Ahmad Dec 23 '12 at 15:35
  • @Ahmad: unfortunately you can't. Maybe resharper or some other tools can create the code for this comparison automatically but there's no built-in function to do this for classes (reference types). Value types are inherently implemented like this, but it's not recommended to implement objects with many fields as structs... – digEmAll Dec 23 '12 at 15:48
  • @digEmAll, which I said 'structures', I didn't literally mean that :) ... I meant to say that my classes contain many variables which are instances of other classes, and so on. So if I decide to manually compare each and every field, I'm going to have to compare such class instance variables too, and thats basically the same problem I'm having now .. Can I compare object instances using the `GetHashCode` method ? If there are two instances of the same class, and they both contain the exact same data, will their hash codes be the same ? – Ahmad Dec 23 '12 at 16:05
  • @Ahmad: GetHashCode method it's not supposed to be used for comparison but to be used by dictionaries/hashsets, and anyway it needs to be overriden in a similar way as Equals. As I said, unfortunately you need to override equals for each class and classes used by fields that you want to compare. I'm sure resharper plugin for VS helps you in this work, but it costs... – digEmAll Dec 23 '12 at 16:17

2 Answers2

2

Though not an exact duplicate, you have all the answers here: What is "Best Practice" For Comparing Two Instances of a Reference Type?. Get the snippet provided Konrad's answer from that thread to never get it wrong.


In short, you are doing it wrong. You're not comparing the actual values in your generic Equals method. Furthermore its not safe to call == operator inside Equals methods. Do it like this:

public override int GetHashCode()
{
    return pType.GetHashCode() ^ pSubType.GetHashCode() ^ quantityDiscountsDT.GetHashCode();
    //or something similar, but fast.
}

public bool Equals(QuantityBasedDiscount other)
{
   if (ReferenceEquals(null, other))
    {
        return false;
    }

    if (ReferenceEquals(this, other))
    {
        return true;
    }

    return pType == other.pType && pSubType == other.pSubType && 
           quantityDiscountsDT == other.quantityDiscountsDT;
}

This might still give you inconsistent results if your DataTable field is modified. All that depends on how == operator is implemented for a DataTable. To have more control on that you will have to derive your own DataTable..

Additionally you might want to overload == and != operator as well. For all that check the provided link.

Community
  • 1
  • 1
nawfal
  • 70,104
  • 56
  • 326
  • 368
0

You have to override Equals and GetHashCode and if you like/need the syntax you need also to overload '==' and '!=' operators. In overriding Equals you can first check if ReferenceEquals returns true and if not then compare the content of the objects.

Personally I prefer to avoid using ReferenceEquals in such cases.

Kaveh Shahbazian
  • 13,088
  • 13
  • 80
  • 139