3

How to override Equals, so you can compare two identical class with two directories without specifying them statically? At the moment, there is an object composed of the following fields. For Types String, Int32, etc. Equals satisfies the conditions.

public class RatiosAVG
{
    public RatiosAVG()
    {
        Dict1 = new Dictionary<Int32, OtherObject1>();
        Dict2 = new Dictionary<Int32, OtherObject2>();
    }

    public OtherObject1 Obj { get; set; }
    public Dictionary<Int32, OtherObject1> Dict1 { get; set; }
    public Dictionary<Int32, OtherObject2> Dict2 { get; set; }
    public String Name { get; set; }
    public Int32 Value { get; set; }

    public override bool Equals(Object obj)
    {
        try
        {
            if (!(obj is RatiosAVG))
                return false;

            RatiosAVG other = (RatiosAVG)obj;
            Type type = typeof(RatiosAVG);
            foreach (System.Reflection.PropertyInfo property in type.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance))
            {

                Object selfValue = type.GetProperty(property.Name).GetValue(this, null);
                Object otherValue = type.GetProperty(property.Name).GetValue(other, null);

                if ((selfValue == null || !selfValue.Equals(otherValue)) && selfValue != otherValue)
                        return false;
            }

            if (type.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance).Count() == 0) 
               return false; 
            else 
               return true;
        }
        catch (Exception) { return false; }
    }
}

OtherObject1 and OtherObject2 is Object

GhostCKY
  • 764
  • 10
  • 19
  • 1
    Try googling `deep object comparison` here are some results from StackOverflow: [1](http://stackoverflow.com/questions/1539989/c-sharp-implementation-of-deep-recursive-object-comparison-in-net-3-5), [2](http://stackoverflow.com/questions/5212039/c-sharp-object-comparison), [3](http://stackoverflow.com/questions/375996/compare-the-content-of-two-objects-for-equality) – Aleksei Poliakov Dec 30 '13 at 08:58
  • I certainly interested in regular means, without the use of additional libraries and serialization. But if nothing is found, it is necessary to resort to them. – GhostCKY Dec 30 '13 at 09:14
  • There are a lot of open source projects out there - I am sure you can find one with license that suits you. For example [this one](https://github.com/jamesfoster/DeepEqual) - there is not need to place it as separate libraty - you can integrate classes that actually do the comparison into your codebase – Aleksei Poliakov Dec 30 '13 at 09:17

1 Answers1

4

There're many issues in your code:

  1. Check simple cases (e.g. obj == null)
  2. Use as instead of is + ()
  3. Do not catch all the exceptions without throw
  4. Do not use Reflection when have three distinct properties to compare

Possible implementation can be

  public override Boolean Equals(Object obj) {
    // If obj is actually "this" then true
    if (Object.ReferenceEquals(this, obj))
      return true;

    // "as " is better the "is" + "(RatiosAVG)" 
    RatiosAVG other = obj as RatiosAVG;

    // obj is either null or not a RatiosAVG
    if (Object.ReferenceEquals(null, other))
      return false;

    // When you have 3 properties to compare, reflection is a bad idea 
    if (other.Value != Value)
      return false;
    else if (!String.Equals(other.Name, Name, StringComparison.Ordinal))
      return false;
    else if (!Object.Equals(other.Obj, Obj))
      return false;

    // Finally, dictionaries. If, the criterium is: 
    // "Dictionaries are considered being equal if and only 
    // if they have the same {key, value} pairs"
    // you can use Linq: SequenceEqual. 
    // Otherwise you should provide details for the dictionaries comparison
    if (!Enumerable.SequenceEqual(other.Dict1, Dict1))
      return false;
    else if (!Enumerable.SequenceEqual(other.Dict2, Dict2))
      return false;

    return true;
  }

  // Do not forget to override GetHashCode:
  public override int GetHashCode() {
    return Value; // <- Simplest version; probably you have to put more elaborated one
  }
Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215
  • Yes, it certainly is good, but if the project is not two dictionaries, and hundreds have to sort through them all in code. I wanted to bust all carried out dynamically. – GhostCKY Dec 30 '13 at 11:04
  • Well, the class (RatiosAVG) you are implementing Equals for has only two dictionaries and three other properties to compare. If you're planning to extend RatiosAVG so it'll have, say, 100 dictionaries you'd rather organaize these dictionaries: put them into List<> or Dictionary<>; in that case can just add a simple loop to my implementation. – Dmitry Bychenko Dec 30 '13 at 11:18
  • It's not specified whether the dictionary properties are supposed to encapsulate the *identities* of dictionaries or their *contents*, though properties of mutable types should only themselves be mutable when encapsulating *identity*, in which case the proper method of comparison would be reference equality. If the dictionaries were private fields used to encapsulate the contents, they should be first compared for reference equality (if they're reference-equal, there's no need to enumerate them) and then for item count (if they have different numbers of items, they're not equal). – supercat Jan 05 '14 at 21:36
  • If the dictionaries are distinct but contain the same number of items and use the same comparer, I don't know any alternative to testing whether one dictionary contains all the items in the other. It's too bad dictionaries don't include a method to enumerate `(Key,Value,KeyHash)` triplets, since that would improve the efficiency of comparisons. If the dictionaries might use different comparers, I don't know any way to really test for equivalence; since a case-insensitive dictionary which includes entries for "George", "Fred", and "Ginny" could compare equivalent to a case-sensitive one... – supercat Jan 05 '14 at 21:43
  • ...with "GEORGE", "George", and "george" [the former dictionary contains all three entries of the latter]. In some more complicated scenarios, one could have two dictionaries, each of which contain all of the entries of the other, but each of whose items would include "duplicates" by the standards of the other's comparer. – supercat Jan 05 '14 at 21:48