/// <summary> /// Iterates through the properties and invokes compare method /// </summary> /// <param name="originalData"></param> /// <param name="deserializedData"></param> /// <param name="containerTypeAttribute"></param> private static void CompareProperties(object originalData, object deserializedData, SerializationMechanism containerTypeAttribute, ComparisionType cmpType) { BindingFlags flag = BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static; //Include private fields for DCS types if (cmpType.Equals(ComparisionType.DCS)) { flag = flag | BindingFlags.NonPublic; } foreach (System.Reflection.PropertyInfo property in originalData.GetType().GetProperties(flag)) { object newData = property.GetValue(originalData, null); SerializationMechanism fieldAttribute = ComparisonHelper.GetSerializationMechanism(newData); if (cmpType.Equals(ComparisionType.DCS)) { if (containerTypeAttribute.Equals(SerializationMechanism.DataContractAttribute)) { if ( (property.GetCustomAttributes(typeof(DataMemberAttribute), false).Length > 0) || (property.GetCustomAttributes(typeof(EnumMemberAttribute), false).Length > 0) ) { //Pass attribute of the complex type for furthur evaluation if (IsComplexType(newData)) { CompareData(newData, property.GetValue(deserializedData, null), fieldAttribute, cmpType); } else //Is a simple type { CompareData(newData, property.GetValue(deserializedData, null), containerTypeAttribute, cmpType); } } } else if (containerTypeAttribute.Equals(SerializationMechanism.SerializableAttribute)) { if (property.GetCustomAttributes(typeof(NonSerializedAttribute), false).Length == 0) { //Pass attribute of the complex type for furthur evaluation if (IsComplexType(newData)) { CompareData(newData, property.GetValue(deserializedData, null), fieldAttribute, cmpType); } else //Is a simple type, so pass Parents attribute { CompareData(newData, property.GetValue(deserializedData, null), containerTypeAttribute, cmpType); } } } } else if (cmpType.Equals(ComparisionType.POCO)) { //Ignore member with [IgnoreDataMember] attribute on a POCO type if (property.GetCustomAttributes(typeof(IgnoreDataMemberAttribute), false).Length == 0) { //On POCO types, Properties which have both getter and setter will be serialized otherwise ignored if (property.CanRead && property.CanWrite) { //Pass attribute of the complex type for furthur evaluation if (IsComplexType(newData)) { CompareData(newData, property.GetValue(deserializedData, null), fieldAttribute, cmpType); } else //Is a simple type, so pass Parents attribute { CompareData(newData, property.GetValue(deserializedData, null), containerTypeAttribute, cmpType); } } else if (property.CanRead && !property.CanWrite) //Get-Only collection { //Pass attribute of the complex type for furthur evaluation if (IsComplexType(newData)) { CompareData(newData, property.GetValue(deserializedData, null), fieldAttribute, cmpType); } else //Is a simple type, so pass Parents attribute { CompareData(newData, property.GetValue(deserializedData, null), containerTypeAttribute, cmpType); } } } } } }
private static void CompareFields(object originalData, object deserializedData, SerializationMechanism containerTypeAttribute, ComparisionType cmpType) { //Compare fields //Non-public members are not serialized for POCO types BindingFlags flag = BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static; if (cmpType.Equals(ComparisionType.DCS)) { flag = flag | BindingFlags.NonPublic; } foreach (System.Reflection.FieldInfo field in originalData.GetType().GetFields(flag)) { object newData = field.GetValue(originalData); SerializationMechanism fieldAttribute = GetSerializationMechanism(newData); if (cmpType.Equals(ComparisionType.DCS)) { if (containerTypeAttribute.Equals(SerializationMechanism.DataContractAttribute)) { if ( (field.GetCustomAttributes(typeof(DataMemberAttribute), false).Length > 0) || (field.GetCustomAttributes(typeof(EnumMemberAttribute), false).Length > 0) ) { //Pass attribute of the complex type for furthur evaluation if (ComparisonHelper.IsComplexType(newData)) { ComparisonHelper.CompareData(field.GetValue(originalData), field.GetValue(deserializedData), fieldAttribute, cmpType); } else //Is a simple type { ComparisonHelper.CompareData(field.GetValue(originalData), field.GetValue(deserializedData), containerTypeAttribute, cmpType); } } } else if (containerTypeAttribute.Equals(SerializationMechanism.SerializableAttribute)) { //Do not compare [NonSerialized] members if (!field.IsNotSerialized) { if (ComparisonHelper.IsComplexType(newData)) { ComparisonHelper.CompareData(field.GetValue(originalData), field.GetValue(deserializedData), fieldAttribute, cmpType); } else //Is a simple type { ComparisonHelper.CompareData(field.GetValue(originalData), field.GetValue(deserializedData), containerTypeAttribute, cmpType); } } } } else if (cmpType.Equals(ComparisionType.POCO)) { //ReadOnly fields should be ignored for POCO type //Ignore member with [IgnoreDataMember] attribute on a POCO type if ((!field.IsInitOnly) && (field.GetCustomAttributes(typeof(IgnoreDataMemberAttribute), false).Length == 0)) { if (ComparisonHelper.IsComplexType(newData)) { ComparisonHelper.CompareData(field.GetValue(originalData), field.GetValue(deserializedData), fieldAttribute, cmpType); } else //Is a simple type { ComparisonHelper.CompareData(field.GetValue(originalData), field.GetValue(deserializedData), containerTypeAttribute, cmpType); } } } } }
/// <summary> /// Throws an exception if mismatch is found /// </summary> /// <param name="originalData"></param> /// <param name="deserializedData"></param> private static void CompareData(object originalData, object deserializedData, SerializationMechanism containerTypeAttribute, ComparisionType cmpType) { if (originalData == null) // both are null, comparison succeeded { return; } if (originalData.GetType().Name.Equals(typeof(System.Runtime.Serialization.ExtensionDataObject).Name)) { return; } //Fail if only one of the objects is null if ((null == originalData) != (null == deserializedData)) { string message = string.Format("Comparision failed: Original data is {0}, deserialized data is {1}", originalData == null ? "null" : "not null", deserializedData == null ? "null" : "not null"); if (originalData != null) { message += string.Format("Contents of Original data are {0}", originalData.ToString()); } if (deserializedData != null) { message += string.Format("Contents of Deserialized data are {0}", deserializedData.ToString()); } throw new Exception(message); } if (originalData is IObjectReference) { //All IObjectReference types implement Equals method which compares the object returned by GetRealObject method bool result = originalData.Equals(deserializedData); if (!result) { throw new Exception("Comparision failed for type " + originalData.GetType().Name); } return; } //Return false if the type of the object is not same Type originalDataType = originalData.GetType(); Type deserializedDataType = deserializedData.GetType(); if (!originalDataType.Equals(deserializedDataType)) { throw new Exception(string.Format("Comparision failed : Original type {0} not same as deserialized type {1}", originalDataType.ToString(), deserializedDataType.ToString())); } object[] dataContractAttributes = originalDataType.GetCustomAttributes(typeof(DataContractAttribute), false); if (dataContractAttributes != null && dataContractAttributes.Length > 0) { DataContractAttribute dataContractAttribute = (DataContractAttribute)dataContractAttributes[0]; if (dataContractAttribute.IsReference) { return; } } MethodInfo equalsMethod = originalDataType.GetMethod("Equals", new Type[] { typeof(object) }); #region "new object()" if (originalDataType == typeof(object)) { return; // deserializedDataType == object as well; objects should be the same } #endregion #region String type else if (originalDataType.Equals(typeof(string))) { if (!originalData.Equals(deserializedData)) { throw new Exception(string.Format("Comparision failed: Original string data {0} is not same as deserialized string data {1}", originalData, deserializedData)); } } #endregion #region XML types else if (originalDataType.Equals(typeof(XmlElement)) || originalDataType.Equals(typeof(XmlNode))) { string originalDataXml = ((XmlNode)originalData).InnerXml; string deserializedDataXml = ((XmlNode)deserializedData).InnerXml; Trace.WriteLine(string.Format(LogMessage, originalDataType, originalDataXml, deserializedDataType, deserializedDataXml)); if (!originalDataXml.Equals(deserializedDataXml)) { throw new Exception(string.Format("Comparision failed: Original XML data ({0}) is not the same as the deserialized XML data ({1})", originalDataXml, deserializedDataXml)); } } #endregion #region Special types else if (originalDataType == typeof(DBNull)) { // only 1 possible value, DBNull.Value if ((((DBNull)originalData) == DBNull.Value) != (((DBNull)deserializedData) == DBNull.Value)) { throw new Exception(string.Format("Different instances of DBNull: original={0}, deserialized={1}", originalData, deserializedData)); } } else if (originalDataType.Equals(typeof(DateTime))) { if (!(((DateTime)originalData).ToUniversalTime().Equals(((DateTime)deserializedData).ToUniversalTime()))) { throw new Exception(string.Format("Comparision failed: Original Datetime ticks {0} is not same as deserialized Datetime ticks {1}", ((DateTime)originalData).Ticks.ToString(), ((DateTime)deserializedData).Ticks.ToString())); } } else if ( (originalDataType.Equals(typeof(TimeSpan))) || (originalDataType.Equals(typeof(Uri))) || (originalDataType.Equals(typeof(XmlQualifiedName))) || (originalDataType.Equals(typeof(Guid))) || (originalDataType.Equals(typeof(decimal))) || (originalDataType.Equals(typeof(DateTimeOffset))) ) { if (!originalData.Equals(deserializedData)) { throw new Exception(string.Format("Comparision failed : Original type data {0} is not same as deserialized type data {1}", originalData.ToString(), deserializedData.ToString())); } } #endregion #region Value Types else if (originalDataType.IsValueType) { //Value types can be Primitive types, Structs, Enums, Bool, User Defined Structs #region Primitive Types //Numeric types, bool if (originalDataType.IsPrimitive) { bool different = !originalData.Equals(deserializedData); if (different) { throw new Exception(string.Format("Comparision failed: Original primitive data {0} is not same as deserialized primitive data {1}", originalData.ToString(), deserializedData.ToString())); } } #endregion #region Enum type else if (originalDataType.IsEnum) { SerializationMechanism enumAttribute = GetSerializationMechanism(originalData); //Verify member is marked with EnumMember attribute and compare the value with the Value property of the enum if (enumAttribute.Equals(SerializationMechanism.DataContractAttribute)) { if (ComparisonHelper.IsMemberMarkedWithEnumMember(originalData, cmpType)) { //Verify this will work for all scenarios if (!originalData.ToString().Equals(deserializedData.ToString())) { throw new Exception(string.Format("Comparision failed: Original enum data {0} is not same as deserialized enum data {1}", originalData.ToString(), deserializedData.ToString())); } } } } #endregion //If not a Primitive and Enum, it has to be a struct #region User defined structs else { #region Compare Fields ComparisonHelper.CompareFields(originalData, deserializedData, containerTypeAttribute, cmpType); #endregion #region Compare properties ComparisonHelper.CompareProperties(originalData, deserializedData, containerTypeAttribute, cmpType); #endregion } #endregion } #endregion #region Types which know how to compare themselves else if (equalsMethod.DeclaringType == originalData.GetType()) { // the type knows how to compare itself, we'll use it if (!originalData.Equals(deserializedData)) { throw new Exception(string.Format("Comparision failed: Original type data {0} is not same as deserialized type data {1}", originalData.ToString(), deserializedData.ToString())); } } #endregion #region IDictionary and IDictionary<T> //Compares generic as well as non-generic dictionary types //Hashtables else if (originalData is IDictionary) { if (deserializedData is IDictionary) { IDictionaryEnumerator originalDataEnum = ((IDictionary)originalData).GetEnumerator(); IDictionaryEnumerator deserializedDataEnum = ((IDictionary)deserializedData).GetEnumerator(); while (originalDataEnum.MoveNext()) { deserializedDataEnum.MoveNext(); DictionaryEntry originalEntry = originalDataEnum.Entry; DictionaryEntry deserializedEntry = deserializedDataEnum.Entry; //Compare the keys and then the values CompareData(originalEntry.Key, deserializedEntry.Key, containerTypeAttribute, cmpType); CompareData(originalEntry.Value, deserializedEntry.Value, containerTypeAttribute, cmpType); } } else { throw new Exception(string.Format("Comparision failed: Original IDictionary type {0} and deserialized IDictionary type {1} are not of same", originalDataType.GetType().ToString(), deserializedDataType.GetType().ToString())); } } #endregion #region IEnumerable,IList,ICollection,IEnumerable<t>,IList<T>,ICollection<T> //Array,Lists,Queues,Stacks etc else if (originalData is IEnumerable) { IEnumerator originalDataEnumerator = ((IEnumerable)originalData).GetEnumerator(); IEnumerator deserializedDataEnumerator = ((IEnumerable)deserializedData).GetEnumerator(); if (null != originalDataEnumerator && null != deserializedDataEnumerator) { while (originalDataEnumerator.MoveNext()) { deserializedDataEnumerator.MoveNext(); CompareData(originalDataEnumerator.Current, deserializedDataEnumerator.Current, containerTypeAttribute, cmpType); } } else { throw new Exception(string.Format("Comparision failed: Original type {0} and deserialized type {1} are not IEnumerable", originalDataType.GetType().ToString(), deserializedDataType.GetType().ToString())); } } #endregion #region Class else if (originalDataType.IsClass) { #region Compare Fields ComparisonHelper.CompareFields(originalData, deserializedData, containerTypeAttribute, cmpType); #endregion #region Compare properties ComparisonHelper.CompareProperties(originalData, deserializedData, containerTypeAttribute, cmpType); #endregion } #endregion }