This class compares 2 objects with eachother (custom objects)
With the possibility to do a deep compare.
You can off course implement a IComparable interface and do it manually,
but i find it a little more useful to do it with an utility, so that i can use it on no-mather which class.
If you have comments or can make it better, don't hesitate to post a comment.
There are probably other ways to do it, but i find this method a fast-enough method for most of the applications.
1: /// <summary>
2: /// Compares 2 objects with each other.
3: /// </summary>
4: public class Comparer
5: {6: #region Declarations
7: 8: private static readonly Type _stringType;
9: private delegate int ILCompareHandler(object o1, object o2);
10: private static ILCompareHandler _ILComparer;
11: 12: #endregion
13: 14: #region Static Constructor
15: 16: static Comparer()
17: {18: _stringType = typeof(string);
19: } 20: 21: #endregion
22: 23: #region Public Methods
24: 25: /// <summary>
26: /// Checks wether 2 objects are equal.
27: /// </summary>
28: /// <param name="o1">Object 1</param>
29: /// <param name="o2">Object 2</param>
30: /// <param name="valueTypesOnly">Only check the value-types? (false = also check the associated-classes)</param>
31: /// <returns>Wether the 2 objects are equal in VALUE</returns>
32: public static bool CompareTo(object o1, object o2, bool valueTypesOnly)
33: { 34: Type to1 = o1.GetType(); 35: Type to2 = o1.GetType();36: if (to1.FullName.CompareTo(to2.FullName) != 0)
37: return false;
38: PropertyInfo[] props = to1.GetProperties();39: // Types are equal, compare each value of each object
40: if (valueTypesOnly)
41: {42: return TestOnValuesOnly(props, o1, o2);
43: }44: else
45: {46: bool innervaluesAreEqual = TestRecursiveValues(props, o1, o2, false);
47: return innervaluesAreEqual;
48: } 49: } 50: 51: #endregion
52: 53: #region Private Methods
54: 55: private static bool TestRecursiveValues(PropertyInfo[] props, object o1, object o2, bool inside)
56: {57: if (o1 == null && o2 == null)
58: return true;
59: if ((o1 != null && o2 == null) || (o1 == null && o2 != null))
60: return false;
61: 62: bool classOK = true;
63: for (int i = 0; i < props.Length; i++)
64: { 65: PropertyInfo pi = props[i];66: if (pi.PropertyType.IsClass && pi.PropertyType != _stringType)
67: {68: object object1 = pi.GetValue(o1, null);
69: object object2 = pi.GetValue(o2, null);
70: if (object1 is IEnumerable)
71: {72: classOK = false;
73: IEnumerator enumerator1 = (object1 as IEnumerable).GetEnumerator();
74: IEnumerator enumerator2 = (object2 as IEnumerable).GetEnumerator();
75: while (enumerator1.MoveNext() && enumerator2.MoveNext())
76: {77: classOK = TestRecursiveValues(enumerator1.Current.GetType().GetProperties(), enumerator1.Current, enumerator2.Current, true);
78: if (!classOK)
79: return classOK;
80: }81: if (!classOK)
82: return classOK;
83: }84: else
85: {86: classOK = TestRecursiveValues(pi.PropertyType.GetProperties(), object1, object2, true);
87: if (!classOK)
88: return classOK;
89: } 90: }91: else
92: {93: if (inside)
94: {95: if (o1.GetType().IsValueType || o1 is string)
96: {97: if (o1.GetType().IsValueType)
98: if (ILCompareValueTypes(o1, o2) != 0)
99: return false;
100: if (o1 is string && o1 != o2)
101: return false;
102: }103: else
104: {105: // We have an inside class , check our values
106: classOK = TestOnValuesOnly(props, o1, o2);107: if (!classOK)
108: return classOK;
109: } 110: } 111: } 112: }113: return classOK;
114: } 115: 116: private static bool TestOnValuesOnly(PropertyInfo[] props, object o1, object o2)
117: {118: if (o1 == null && o2 == null)
119: return true;
120: if ((o1 != null && o2 == null) || (o1 == null && o2 != null))
121: return false;
122: for (int i = 0; i < props.Length; i++)
123: { 124: PropertyInfo pi = props[i];125: if (pi.PropertyType.IsValueType && !pi.PropertyType.IsArray)
126: {127: object so1 = pi.GetValue(o1, null) ?? string.Empty;
128: object so2 = pi.GetValue(o2, null) ?? string.Empty;
129: 130: if (ILCompareValueTypes(so1, so2) != 0)
131: return false;
132: }133: if (pi.PropertyType == _stringType)
134: {135: object so1 = pi.GetValue(o1, null) as string ?? string.Empty;
136: object so2 = pi.GetValue(o2, null) as string ?? string.Empty;
137: 138: if (so1 != so2)
139: return false;
140: } 141: }142: return true;
143: } 144: 145: private static int ILCompareValueTypes(object value1, object value2)
146: {147: if (_ILComparer == null)
148: {149: Type[] _argTypes = { typeof(object), typeof(object) };
150: 151: DynamicMethod dynam =152: new DynamicMethod(
153: "ILComparer",
154: typeof(int),
155: _argTypes,156: typeof(Comparer));
157: ILGenerator il = dynam.GetILGenerator(); 158: 159: il.Emit(OpCodes.Ldarg_0); 160: il.Emit(OpCodes.Ldarg_1); 161: il.Emit(OpCodes.Ceq); 162: il.Emit(OpCodes.Ret); 163: 164: _ILComparer = dynam.CreateDelegate(typeof(ILCompareHandler)) as ILCompareHandler;
165: }166: return _ILComparer(value1, value2);
167: } 168: 169: #endregion
170: }