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)); } }
private bool CompareDM(object lhObj, ClassDataContract lhDataContract, object rhObj, ClassDataContract rhDataContract) { bool result = true; //DM differences must be whole version, no partial version data int lhVEnd = 0; int rhVEnd = 0; DataMember lhDataMember; object lhMemberValue; DataMember rhDataMember; object rhMemberValue; while (lhVEnd < lhDataContract.Members.Count && rhVEnd < rhDataContract.Members.Count) { //Members of the data contract has been sorted alphabetic then VersionAdded lhDataMember = lhDataContract.Members[lhVEnd++]; rhDataMember = rhDataContract.Members[rhVEnd++]; if (!lhDataMember.Equals(rhDataMember)) { return(false); } lhMemberValue = lhDataMember.GetMemberValue(lhObj); rhMemberValue = rhDataMember.GetMemberValue(rhObj); if (lhMemberValue != null && rhMemberValue != null) { result = this.CompareObjects(lhMemberValue, rhMemberValue); if (!result) { return(false); } } else if (lhMemberValue == null && rhMemberValue == null) { continue; } else { return(false); } } //For different version, remaining DM's versionadded need to be greater then tested if (lhVEnd < lhDataContract.Members.Count && rhVEnd == rhDataContract.Members.Count && rhDataContract.Members.Count > 0) { result &= lhDataContract.Members[lhVEnd].VersionAdded > rhDataContract.Members[rhVEnd - 1].VersionAdded; } else if (rhVEnd < rhDataContract.Members.Count && lhVEnd == lhDataContract.Members.Count && lhDataContract.Members.Count > 0) { result &= rhDataContract.Members[rhVEnd].VersionAdded > lhDataContract.Members[lhVEnd - 1].VersionAdded; } if (!result) { return(false); } if (lhDataContract.BaseContract != null && rhDataContract.BaseContract != null) { return(CompareDM(lhObj, lhDataContract.BaseContract, rhObj, rhDataContract.BaseContract)); } else if (lhDataContract.BaseContract == null && rhDataContract.BaseContract == null) { return(true); } else { return(false); } }