/// <summary> /// Compare the properties of a class /// </summary> public void PerformCompareProperties(CompareParms parms) { IEnumerable <PropertyInfo> currentProperties = null; //Interface Member Logic if (parms.Config.InterfaceMembers.Count > 0) { Type[] interfaces = parms.Object1Type.GetInterfaces(); foreach (var type in parms.Config.InterfaceMembers) { if (interfaces.Contains(type)) { currentProperties = Cache.GetPropertyInfo(parms.Result, type); break; } } } if (currentProperties == null) { currentProperties = Cache.GetPropertyInfo(parms.Result, parms.Object1Type); } foreach (PropertyInfo info in currentProperties) { //If we can't read it, skip it if (info.CanRead == false) { continue; } //Skip if this is a shallow compare if (!parms.Config.CompareChildren && TypeHelper.CanHaveChildren(info.PropertyType)) { continue; } //Skip if it should be excluded based on the configuration if (ExcludeLogic.ShouldExcludeMember(parms.Config, info)) { continue; } //If we should ignore read only, skip it if (!parms.Config.CompareReadOnly && info.CanWrite == false) { continue; } //If we ignore types then we must get correct PropertyInfo object PropertyInfo secondObjectInfo = null; if (parms.Config.IgnoreObjectTypes) { var secondObjectPropertyInfos = Cache.GetPropertyInfo(parms.Result, parms.Object2Type); foreach (var propertyInfo in secondObjectPropertyInfos) { if (propertyInfo.Name != info.Name) { continue; } secondObjectInfo = propertyInfo; break; } } else { secondObjectInfo = info; } object objectValue1; object objectValue2; if (!IsValidIndexer(parms.Config, info, parms.BreadCrumb)) { objectValue1 = info.GetValue(parms.Object1, null); objectValue2 = secondObjectInfo != null?secondObjectInfo.GetValue(parms.Object2, null) : null; } else { _indexerComparer.CompareIndexer(parms, info); continue; } bool object1IsParent = objectValue1 != null && (objectValue1 == parms.Object1 || parms.Result.Parents.ContainsKey(objectValue1.GetHashCode())); bool object2IsParent = objectValue2 != null && (objectValue2 == parms.Object2 || parms.Result.Parents.ContainsKey(objectValue2.GetHashCode())); //Skip properties where both point to the corresponding parent if ((TypeHelper.IsClass(info.PropertyType) || TypeHelper.IsInterface(info.PropertyType) || TypeHelper.IsStruct(info.PropertyType)) && (object1IsParent && object2IsParent)) { continue; } string currentBreadCrumb = AddBreadCrumb(parms.Config, parms.BreadCrumb, info.Name); CompareParms childParms = new CompareParms { Result = parms.Result, Config = parms.Config, ParentObject1 = parms.Object1, ParentObject2 = parms.Object2, Object1 = objectValue1, Object2 = objectValue2, BreadCrumb = currentBreadCrumb }; _rootComparer.Compare(childParms); if (parms.Result.ExceededDifferences) { return; } } }
/// <summary> /// Compare a single property of a class /// </summary> /// <param name="parms"></param> /// <param name="info"></param> /// <param name="object2Properties"></param> private void CompareProperty(CompareParms parms, PropertyEntity info, List <PropertyEntity> object2Properties) { //If we can't read it, skip it if (info.CanRead == false) { return; } //Skip if this is a shallow compare if (!parms.Config.CompareChildren && TypeHelper.CanHaveChildren(info.PropertyType)) { return; } //Skip if it should be excluded based on the configuration if (info.PropertyInfo != null && ExcludeLogic.ShouldExcludeMember(parms.Config, info.PropertyInfo)) { return; } //This is a dynamic property to be excluded on an expando object if (info.IsDynamic && ExcludeLogic.ShouldExcludeDynamicMember(parms.Config, info.Name, info.DeclaringType)) { return; } //If we should ignore read only, skip it if (!parms.Config.CompareReadOnly && info.CanWrite == false) { return; } //If we ignore types then we must get correct PropertyInfo object PropertyEntity secondObjectInfo = GetSecondObjectInfo(info, object2Properties); //If the property does not exist, and we are ignoring the object types, skip it if (parms.Config.IgnoreObjectTypes && secondObjectInfo == null) { return; } object objectValue1; object objectValue2; if (!IsValidIndexer(parms.Config, info, parms.BreadCrumb)) { objectValue1 = info.Value; objectValue2 = secondObjectInfo != null ? secondObjectInfo.Value : null; } else { _indexerComparer.CompareIndexer(parms, info, secondObjectInfo); return; } bool object1IsParent = objectValue1 != null && (objectValue1 == parms.Object1 || parms.Result.Parents.ContainsKey(objectValue1.GetHashCode())); bool object2IsParent = objectValue2 != null && (objectValue2 == parms.Object2 || parms.Result.Parents.ContainsKey(objectValue2.GetHashCode())); //Skip properties where both point to the corresponding parent if ((TypeHelper.IsClass(info.PropertyType) || TypeHelper.IsInterface(info.PropertyType) || TypeHelper.IsStruct(info.PropertyType)) && (object1IsParent && object2IsParent)) { return; } string currentBreadCrumb = AddBreadCrumb(parms.Config, parms.BreadCrumb, info.Name); CompareParms childParms = new CompareParms { Result = parms.Result, Config = parms.Config, ParentObject1 = parms.Object1, ParentObject2 = parms.Object2, Object1 = objectValue1, Object2 = objectValue2, BreadCrumb = currentBreadCrumb }; _rootComparer.Compare(childParms); }
/// <summary> /// Compare a single property of a class /// </summary> /// <param name="parms"></param> /// <param name="info"></param> private void CompareProperty(CompareParms parms, PropertyInfo info) { //If we can't read it, skip it if (info.CanRead == false) { return; } //Skip if this is a shallow compare if (!parms.Config.CompareChildren && TypeHelper.CanHaveChildren(info.PropertyType)) { return; } //Skip if it should be excluded based on the configuration if (ExcludeLogic.ShouldExcludeMember(parms.Config, info)) { return; } //If we should ignore read only, skip it if (!parms.Config.CompareReadOnly && info.CanWrite == false) { return; } //If we ignore types then we must get correct PropertyInfo object PropertyInfo secondObjectInfo = GetSecondObjectInfo(parms, info); //If the property does not exist, and we are ignoring the object types, skip it if (parms.Config.IgnoreObjectTypes && secondObjectInfo == null) { return; } object objectValue1; object objectValue2; if (!IsValidIndexer(parms.Config, info, parms.BreadCrumb)) { objectValue1 = info.GetValue(parms.Object1, null); objectValue2 = secondObjectInfo != null?secondObjectInfo.GetValue(parms.Object2, null) : null; } else { _indexerComparer.CompareIndexer(parms, info); return; } bool object1IsParent = objectValue1 != null && (objectValue1 == parms.Object1 || parms.Result.Parents.ContainsKey(objectValue1.GetHashCode())); bool object2IsParent = objectValue2 != null && (objectValue2 == parms.Object2 || parms.Result.Parents.ContainsKey(objectValue2.GetHashCode())); //Skip properties where both point to the corresponding parent if ((TypeHelper.IsClass(info.PropertyType) || TypeHelper.IsInterface(info.PropertyType) || TypeHelper.IsStruct(info.PropertyType)) && (object1IsParent && object2IsParent)) { return; } /* var name = info.Name; * var resource = string.Empty; * foreach (DisplayAttribute item in info.GetCustomAttributes(typeof(DisplayAttribute), true)) * { * if (item.ResourceType != null) * { * resource = Convert.ToString(item.ResourceType.GetProperty(item.Name, BindingFlags.Static | BindingFlags.Public).GetValue(null, null)); * } * if (string.IsNullOrWhiteSpace(resource)) * { * if (!string.IsNullOrWhiteSpace(item.Description)) * { * name = item.Description; * } * else if (!string.IsNullOrWhiteSpace(item.Prompt)) * { * name = item.Prompt; * } * else if (!string.IsNullOrWhiteSpace(item.Name)) * { * name = item.Name; * } * } * else * { * name = resource; * } * } */ string currentBreadCrumb = AddBreadCrumb(parms.Config, parms.BreadCrumb, info.Name); CompareParms childParms = new CompareParms { Result = parms.Result, Config = parms.Config, ParentObject1 = parms.Object1, ParentObject2 = parms.Object2, Object1 = objectValue1, Object2 = objectValue2, BreadCrumb = currentBreadCrumb }; _rootComparer.Compare(childParms); }