0

Suppose I have a class like below:

public class A { public string prop1 { get; set; } public List<B> prop2 { get; set; } //B is a user-defined type // and so on } 

Now suppose I have two objects of type A, a1 and a2. But not all of the properties of them are initialized. I need to check whether a1 has the same values for all the non-null properties of a2 (I don't know what is the term for this, maybe "sub-equality"?).

What I am trying to do is to overwrite Equals() method for all the types used in A, and then iterate through properties of a2 like this, and check the equality of the corresponding properties (if it is a List then I should use HashSet and SetEquals()).

Is there a better (more efficient, less code, etc) way?

8
  • That answer uses reflection. In your case a more efficient approach would be to not use reflection because you know the objects and what properties they have at compile time. Commented Apr 16, 2018 at 3:42
  • Dupe to this stackoverflow.com/questions/8400028/… ? Commented Apr 16, 2018 at 3:45
  • Further questions. For a1 and a2 to be equal in your eyes, do they have to be the same list or is it enough that they contain equal elements? If the Lists can be different objects, do they need to be in the same order to be regarded as equal or is it sufficient for them to exist in both lists. You mention Hashset / SetEquals, but what if my A is List<int> and I run a1.prop2 = new List { 1, 2, 3} and a2.prop2 = new List { 1, 2, 3, 2}? Are these equal? Commented Apr 16, 2018 at 3:53
  • You could serialize both objects and compare the serialized versions, such as converting to JSON and compare the strings for equality. Commented Apr 16, 2018 at 3:56
  • @kurakura88 in my case, a2 might have different set of non-null properties each time it is compared to some a1 Commented Apr 16, 2018 at 4:24

1 Answer 1

1

There are several techniques, but here is something to start with. I have used an extension method which works all the way down to object (why not), but you could restrict it to higher levels of make it part of your base class itself.

Note that reflection is relatively expensive so if it is the sort of operation that you are doing often, you should consider caching the relevant PropertyInfos.

namespace ConsoleApp1 { using System; using System.Collections; using System.Collections.Generic; using System.Reflection; public class BaseClass<T> { public string prop1 { get; set; } public List<T> prop2 { get; set; } //B is a user-defined type } public class DescendentClass<T> : BaseClass<T> { } public static class DeepComparer { public static bool IsDeeplyEquivalent(this object current, object other) { if (current.Equals(other)) return true; Type currentType = current.GetType(); // Assumption, cannot be equivalent if another class (descendent classes??) if (currentType != other.GetType()) { return false; } foreach (PropertyInfo propertyInfo in currentType.GetProperties()) { object currentValue = propertyInfo.GetValue(current, null); object otherValue = propertyInfo.GetValue(other, null); // Assumption, nulls for a given property are considered equivalent if (currentValue == null && otherValue == null) { continue; } // One is null, the other isn't so are not equal if (currentValue == null || otherValue == null) { return false; } ICollection currentCollection = currentValue as ICollection; if (currentCollection == null) { // Not a collection, just check equality if (!currentValue.Equals(otherValue)) { return false; } } else { // Collection, not interested whether list/array/etc are same object, just that they contain equal elements // questioner guaranteed that all elements are unique HashSet<object> elements = new HashSet<object>(); foreach (object o in currentCollection) { elements.Add(o); } List<object> otherElements = new List<object>(); foreach (object o in (ICollection)otherValue) { otherElements.Add(o); } // cast below can be safely made because we have already asserted that // current and other are the same type if (!elements.SetEquals(otherElements)) { return false; } } } return true; } } public class Program { public static void Main(string[] args) { BaseClass<int> a1 = new BaseClass<int>{prop1 = "Foo", prop2 = new List<int>{1, 2, 3}}; BaseClass<int> a2 = new BaseClass<int>{prop1 = "Foo", prop2 = new List<int>{2, 1, 3}}; BaseClass<int> a3 = new BaseClass<int>{prop1 = "Bar", prop2 = new List<int>{2, 1, 3}}; BaseClass<string> a4 = new BaseClass<string>{prop1 = "Bar", prop2 = new List<string>()}; BaseClass<int> a5 = new BaseClass<int>{prop1 = "Bar", prop2 = new List<int>{1, 3}}; DateTime d1 = DateTime.Today; DateTime d2 = DateTime.Today; List<string> s1 = new List<string>{"s1", "s2"}; string[] s2 = {"s1", "s2"}; BaseClass<DayOfWeek> b1 = new BaseClass<DayOfWeek>{prop1 = "Bar", prop2 = new List<DayOfWeek>{DayOfWeek.Monday, DayOfWeek.Tuesday}}; DescendentClass<DayOfWeek> b2 = new DescendentClass<DayOfWeek>{prop1 = "Bar", prop2 = new List<DayOfWeek>{DayOfWeek.Monday, DayOfWeek.Tuesday}}; Console.WriteLine("a1 == a2 : " + a1.IsDeeplyEquivalent(a2)); // true, different order ignored Console.WriteLine("a1 == a3 : " + a1.IsDeeplyEquivalent(a3)); // false, different prop1 Console.WriteLine("a3 == a4 : " + a3.IsDeeplyEquivalent(a4)); // false, different types Console.WriteLine("a3 == a5 : " + a3.IsDeeplyEquivalent(a5)); // false, difference in list elements Console.WriteLine("d1 == d2 : " + d1.IsDeeplyEquivalent(d2)); // true Console.WriteLine("s1 == s2 : " + s1.IsDeeplyEquivalent(s2)); // false, different types Console.WriteLine("b1 == b2 : " + s1.IsDeeplyEquivalent(s2)); // false, different types Console.WriteLine("b1 == b1 : " + b1.IsDeeplyEquivalent(b1)); // true, same object Console.ReadLine(); } } } 
Sign up to request clarification or add additional context in comments.

1 Comment

this is what I had in mind, and it does what I want except replacing if (currentValue == null && otherValue == null) with if (currentValue == null), and if (currentValue == null || otherValue == null) with if (otherValue == null)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.