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: }