private bool CompareObjects(object lhObj, object rhObj) { if (lhObj == null && rhObj == null) { return(true); } if (lhObj == null || rhObj == null) { return(false); } Type lhObjType = lhObj.GetType(); Type rhObjType = rhObj.GetType(); //both objects have same circular reference if (lhsObjectHashTable[lhObj] != null && rhsObjectHashTable[rhObj] != null) { return(true); } // one object has circular ref, so not equal else if (lhsObjectHashTable[lhObj] != null || rhsObjectHashTable[rhObj] != null) { return(false); } DataContract lhDataContract = DataContract.GetDataContract(lhObjType); DataContract rhDataContract = DataContract.GetDataContract(rhObjType); //if either type is not serializable or DC, then above GetDataContract would throw //so both DataContracts are not null now if (!lhDataContract.Equals(rhDataContract)) { return(false); } //lhDataContract and rhDataContract have same qname now (that's the Equals compare //enum, primitive, string and decimal can be compared by .Equals, note decimal is not a primitive //in this case, lhObjType should be equal to rhObjType if (lhObjType.IsEnum || lhObjType == typeof(Decimal) || lhObjType.IsPrimitive || lhObj is string) { System.Diagnostics.Debug.Assert(lhObjType == rhObjType, "types must be same for the compared objects when they are enum/primitive/string/decimal", string.Format("left type is {0}, right type is {1}", lhObjType, rhObjType)); return(lhObj.Equals(rhObj)); } else if (lhObjType.IsArray && rhObjType.IsArray) { Array lhArray = (Array)lhObj; Array rhArray = (Array)rhObj; if (lhArray.Length != rhArray.Length) { return(false); } //indeces and bounds of the array to be compared //indeces is the current position Array indeces = Array.CreateInstance(typeof(int), lhArray.Rank); //bounds is the upper bounds of the array Array bounds = Array.CreateInstance(typeof(int), lhArray.Rank); int arrayTotalLength = 0; for (int i = 0; i < indeces.Length; i++) { indeces.SetValue(0, i); bounds.SetValue(lhArray.GetLength(i), i); if (i == 0) { arrayTotalLength = lhArray.GetLength(0); } else { arrayTotalLength *= (int)lhArray.GetLength(i); } } int index = 0; bool notEnd = true; //UNDONE: only need one condition, use both to double check here while (index < arrayTotalLength && notEnd) { if (!this.CompareObjects(lhArray.GetValue((int[])indeces), rhArray.GetValue((int[])indeces))) { return(false); } //increase array indeces to the next element in the array //always increment from the highest dimension notEnd = this.IncIndex((int[])indeces, (int[])bounds, indeces.Length - 1); index++; } return(true); } else { lhsObjectHashTable.Add(lhObj, lhObj); rhsObjectHashTable.Add(rhObj, rhObj); ClassDataContract lhClassDataContract = lhDataContract as ClassDataContract; ClassDataContract rhClassDataContract = rhDataContract as ClassDataContract; if (rhClassDataContract == null || lhClassDataContract == null) { throw new Exception("type mismatch! not both are class/struct"); } return(CompareDM(lhObj, lhClassDataContract, rhObj, rhClassDataContract)); } }