Dynamic equality checking of multiple properties of a type's objects

2.4k views Asked by At

I have a type like:

class Order
{
  public List<IItem> AllItems { get; set; }
  public string Name { get; set; }
  public double TotalPurchases { get; set; }
  public long Amount { get; set; }
  public int Code { get; set; }
}

I've implemented the IEquatable<T> interface to check if two objects of this type are same or not. The current Equals method looks like:

public virtual bool Equals(Order other)
{
  if ((object)other == null)
  {
    return false;
  }
  return (this.AllItems.Equals(other.AllItems)
       && this.Name.Equals(other.Name)
       && this.TotalPurchases.Equals(other.TotalPurchases)
       && this.Amount.Equals(other.Amount))
       && this.Code.Equals(other.Code));
}

But I wish to implement this method in such a way that it dynamically checks for equality of all the existing properties (or maybe certain properties of this type) without explicitly writing the code for comparison checks as above.

Hope I was able to express my question with clarity. :)

Thanks!

2

There are 2 answers

0
MattDavey On

You could write a custom attribute that attaches to the properties on your type which you want to be included in the comparision. Then in the Equals method you could reflect over the type and extract all the properties which have the attribute, and run a comparison on them dynamically.

Psuedo code:

[AttributeUsage(AttributeTarget.Property)]
class IncludeInComparisonAttribute : Attribute { }

class Order
{
    List<AllItem> Items { get; set; }

    [IncludeInComparison]
    string Name { get; set; }

    long Amount { get; set; }

    [IncludeInComparison]
    int Code { get; set; }

    override bool Equals(Order other)
    {
        Type orderType = typeof(Order);

        foreach (PropertyInfo property in orderType.GetProperties()
        {
            if (property.CustomAttributes.Includes(typeof(IncludeInComparisonAttribute))
            {
                object value1 = property.GetValue(this);
                object value2 = propetty.GetValue(other);

                if (value1.Equals(value2) == false)
                    return false;
            }
        }

        return true;
    }
}

It'll certianly need to be a bit more elaborate than that, but that should hopefully set you on the right track :)

2
Cheng Chen On

Two Orders are considered the same if all their properties are equal. It's OK for the 4 properties Name/TotalPurchases/Amount/Code, their default comparers are exactly what you want. But for the property AllItems (whose type is List<IItem>), you must tell how they consider to be equal. Currently you are using reference equals that is incorrect. this.AllItems.Equals(other.AllItems) should be something like:

this.AllItems.SequenceEqual(other.AllItems, new ItemComparer())

And the ItemComparer is a class implements IEqualityComparer<Item> to tell how to check if two Items are equal.