tags:

views:

946

answers:

5

I need to write a generic method in the base class that would accept 2 objects as parameters and compares them for equality.

Ex:

public abstract class BaseData
{

  public bool AreEqual(object O1, object O2)
  {
    //Need to implement this
  }
}

public class DataTypeOne : BaseData
{
  public string Name;
  public string Address;
}

public class DataTypeTwo : BaseData
{
  public int CustId;
  public string CustName;
}

The AreEqual() method would accept 2 instances of DataTypeOne or 2 instances of DataTypeTwo.

My guess is I need to use Reflection? I can use LINQ if it can be more readable/concise.

EDIT: The reason I would like to implement this method in the base class is because of project restrictions. There are a large number of devs working on the derived classes. By implementing this in the base class, I am trying to have 1 less thing for them to worry about.

+5  A: 

(Assuming that what you want is to compare all the fields of the two objects for equality.)

Usually, you wouldn't bother using reflection for this, you'd just compare each field yourself. The IEquatable<T> interface exists for this purpose, and you also might want to override Object.Equals() on the types in question. For example:

public class DataTypeTwo : BaseData, IEquatable<DataTypeTwo>
{
    public int CustId;
    public string CustName;

    public override int GetHashCode()
    {
        return CustId ^ CustName.GetHashCode(); // or whatever
    }

    public override bool Equals(object other)
    {
        return this.Equals(other as DataTypeTwo);
    }

    public bool Equals(DataTypeTwo other)
    {
        return (other != null &&
                other.CustId == this.CustId &&
                other.CustName == this.CustName);
    }
}

Also, consider whether or not your type makes sense as a struct instead. Value types automatically compare equality by doing a field-by-field comparison.

Note that by overriding Equals, you basically achieve what (it seems to me) you're trying to achieve with your "master equals method" scheme. That is, people using DataTypeTwo will be able to naturally test for equality without having to know anything special about your API -- they'll just use Equals like they would with other things.

EDIT: Thanks to Jared for reminding me about GetHashCode. You'll also want to override it to maintain normal-looking behavior in hashtables by making sure that any two objects which are "equal" also return the same hash code.

mquander
You still need ot override GetHashCode
JaredPar
Why you need GetHashCode, Equals not sufficient?
Ahmed Said
A: 

Yes, you will have to use reflection, because the base class knows nothing about derived classes. But why do you want to implement that function in the base class? Why not in the derived classes?

Further there is a standard way to do this by overriding Object.GetHashCode() and Object.Equals().

Daniel Brückner
+1  A: 

I would probably do something like this:

public abstract class BaseData : IEquatable<BaseData>
{
    public abstract bool Equals(BaseData other);
}

public class DataTypeOne : BaseData
{
    public string Name;
    public string Address;

    public override bool Equals(BaseData other)
    {
        var o = other as DataTypeOne;
        if(o == null)
            return false;
        return Name.Equals(o.Name) && Address.Equals(o.Address);
    }
}

public class DataTypeTwo : BaseData
{
    public int CustId;
    public string CustName;

    public override bool Equals(BaseData other)
    {
        var o = other as DataTypeTwo;
        if (o == null)
            return false;
        return CustId == o.CustId && CustName.Equals(o.CustName);
    }
}
Svish
Perhaps an explanation as to why it's "insane" would be nice.
madcolor
Well, I just think it is really no need of comparing DataTypeOne and DataTypeTwo, since they will never be equal. In other words I would probably just implement IEquatable<DataTypeOne> in DataTypeOne and/or IEquatable<DataTypeTwo> in DataTypeTwo. Or most likely I would just use linq or something to i.e. look for a particlar DataTypeTwo with a particular CustId for example and not bother with the IEquatable or override Equals or anything like that.
Svish
+1  A: 

Here's what I came up with using reflection. Hope it helps.

public bool AreEqual(object obj)
    {
        bool returnVal = true;

        if (this.GetType() == obj.GetType())
        {
            FieldInfo[] fields = this.GetType().GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);

            foreach (FieldInfo field in fields)
            {
                if(field.GetValue(this) != field.GetValue(obj))
                {
                    returnVal = false;
                    break;
                }
            }
        }
        else
            returnVal = false;

        return returnVal;
    }
Chris Persichetti
A: 

Don't do it. Inheritance is the way to go and each class, should override the Equal and GetHashCode where needed.

Maybe you'll get some work done out of those developers now but I'll come back to bite you in the ass in the future when the product needs to be maintained.

Seriously, just try to find another way to help.

Jorge Córdoba