示例#1
0
        private List <string> GetMatchingSpec(ComparisonResult result, Type type)
        {
            if (type == null)
            {
                return new List <string> {
                           "(null)"
                }
            }
            ;

            //The user defined a key for the order
            var matchingBasePresent = result.Config.CollectionMatchingSpec.Keys.FirstOrDefault(k => k.IsAssignableFrom(type));

            if (matchingBasePresent != null)
            {
                return(result.Config.CollectionMatchingSpec.First(p => p.Key == matchingBasePresent).Value.ToList());
            }

            //Make a key out of primitive types, date, decimal, string, guid, and enum of the class
            List <string> list = Cache.GetPropertyInfo(result.Config, type)
                                 .Where(o => o.CanWrite && !ExcludeLogic.ShouldExcludeMember(result.Config, o, o.DeclaringType) && (TypeHelper.IsSimpleType(o.PropertyType) || TypeHelper.IsEnum(o.PropertyType)))
                                 .Select(o => o.Name).ToList();

            return(list);
        }
    }
示例#2
0
        /// <summary>
        /// Compare two objects that implement IList
        /// </summary>
        public override void CompareType(CompareParms parms)
        {
            //This should never happen, null check happens one level up
            if (parms.Object1 == null || parms.Object2 == null)
            {
                return;
            }

            try
            {
                parms.Result.AddParent(parms.Object1);
                parms.Result.AddParent(parms.Object2);

                Type t1 = parms.Object1.GetType();
                Type t2 = parms.Object2.GetType();

                //Check if the class type should be excluded based on the configuration
                if (ExcludeLogic.ShouldExcludeClass(parms.Config, t1, t2))
                {
                    return;
                }

                parms.Object1Type = t1;
                parms.Object2Type = t2;

                if (parms.Result.ExceededDifferences)
                {
                    return;
                }

                bool countsDifferent = ListsHaveDifferentCounts(parms);

                // If items is collections, need to use default compare logic, not ignore order logic.
                // We cannot ignore order for nested collections because we will get an reflection exception.
                // May be need to display some warning or write about this behavior in documentation.
                if (parms.Config.IgnoreCollectionOrder && !ChildShouldBeComparedWithoutOrder(parms))
                {
                    // TODO: allow IndexerComparer to works with types (now it works only with properties).
                    IgnoreOrderLogic ignoreOrderLogic = new IgnoreOrderLogic(RootComparer);
                    ignoreOrderLogic.CompareEnumeratorIgnoreOrder(parms, countsDifferent);
                }
                else
                {
                    CompareItems(parms);
                }

                //Properties on the root of a collection
                CompareProperties(parms);
                CompareFields(parms);
            }
            finally
            {
                parms.Result.RemoveParent(parms.Object1);
                parms.Result.RemoveParent(parms.Object2);
            }
        }
        /// <summary>
        /// Compare two objects that implement IList
        /// </summary>
        public override void CompareType(CompareParms parms)
        {
            //This should never happen, null check happens one level up
            if (parms.Object1 == null || parms.Object2 == null)
            {
                return;
            }

            try
            {
                parms.Result.AddParent(parms.Object1.GetHashCode());
                parms.Result.AddParent(parms.Object2.GetHashCode());

                Type t1 = parms.Object1.GetType();
                Type t2 = parms.Object2.GetType();

                //Check if the class type should be excluded based on the configuration
                if (ExcludeLogic.ShouldExcludeClass(parms.Config, t1, t2))
                {
                    return;
                }

                parms.Object1Type = t1;
                parms.Object2Type = t2;

                if (parms.Result.ExceededDifferences)
                {
                    return;
                }

                bool countsDifferent = ListsHaveDifferentCounts(parms);

                if (parms.Config.IgnoreCollectionOrder && !ChildIsListOrDictionary(parms))
                {
                    IgnoreOrderLogic ignoreOrderLogic = new IgnoreOrderLogic(RootComparer);
                    ignoreOrderLogic.CompareEnumeratorIgnoreOrder(parms, countsDifferent);
                }
                else
                {
                    CompareItems(parms);
                }

                //Properties on the root of a collection
                CompareProperties(parms);
                CompareFields(parms);
            }
            finally
            {
                parms.Result.RemoveParent(parms.Object1.GetHashCode());
                parms.Result.RemoveParent(parms.Object2.GetHashCode());
            }
        }
示例#4
0
        private void CompareField(CompareParms parms, FieldInfo item)
        {
            //Skip if this is a shallow compare
            if (!parms.Config.CompareChildren && TypeHelper.CanHaveChildren(item.FieldType))
            {
                return;
            }

            //Skip if it should be excluded based on the configuration
            if (ExcludeLogic.ShouldExcludeMember(parms.Config, item))
            {
                return;
            }

            //If we ignore types then we must get correct FieldInfo object
            FieldInfo secondFieldInfo = GetSecondFieldInfo(parms, item);

            //If the field does not exist, and we are ignoring the object types, skip it
            if (parms.Config.IgnoreObjectTypes && secondFieldInfo == null)
            {
                return;
            }

            object objectValue1 = item.GetValue(parms.Object1);
            object objectValue2 = secondFieldInfo != null?secondFieldInfo.GetValue(parms.Object2) : null;

            bool object1IsParent = objectValue1 != null && (objectValue1 == parms.Object1 || parms.Result.IsParent(objectValue1));
            bool object2IsParent = objectValue2 != null && (objectValue2 == parms.Object2 || parms.Result.IsParent(objectValue2));

            //Skip fields that point to the parent
            if ((TypeHelper.IsClass(item.FieldType) || TypeHelper.IsInterface(item.FieldType)) &&
                (object1IsParent || object2IsParent))
            {
                return;
            }

            string currentBreadCrumb = AddBreadCrumb(parms.Config, parms.BreadCrumb, item.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);
        }
        private static List <PropertyEntity> AddPropertyInfos(CompareParms parms,
                                                              object objectValue,
                                                              Type objectType,
                                                              IEnumerable <PropertyInfo> properties)
        {
            List <PropertyEntity> currentProperties = new List <PropertyEntity>();

            foreach (var property in properties)
            {
                if (ExcludeLogic.ShouldExcludeMember(parms.Config, property, objectType))
                {
                    continue;
                }

                PropertyEntity propertyEntity = new PropertyEntity();
                propertyEntity.IsDynamic    = false;
                propertyEntity.Name         = property.Name;
                propertyEntity.CanRead      = property.CanRead;
                propertyEntity.CanWrite     = property.CanWrite;
                propertyEntity.PropertyType = property.PropertyType;
#if !NETSTANDARD
                propertyEntity.ReflectedType = property.ReflectedType;
#endif
                propertyEntity.Indexers.AddRange(property.GetIndexParameters());
                propertyEntity.DeclaringType = objectType;

                if (propertyEntity.CanRead && (propertyEntity.Indexers.Count == 0))
                {
                    try
                    {
                        propertyEntity.Value = property.GetValue(objectValue, null);
                    }
                    catch (System.Reflection.TargetInvocationException)
                    {
                    }
                    catch (System.NotSupportedException)
                    {
                    }
                }

                propertyEntity.PropertyInfo = property;

                currentProperties.Add(propertyEntity);
            }

            return(currentProperties);
        }
        /// <summary>
        /// Compare two classes
        /// </summary>
        public override void CompareType(CompareParms parms)
        {
            try
            {
                parms.Result.AddParent(parms.Object1);
                parms.Result.AddParent(parms.Object2);

                //Custom classes that implement IEnumerable may have the same hash code
                //Ignore objects with the same hash code
                if (!(parms.Object1 is IEnumerable) &&
                    ReferenceEquals(parms.Object1, parms.Object2))
                {
                    return;
                }

                Type t1 = parms.Object1.GetType();
                Type t2 = parms.Object2.GetType();

                //Check if the class type should be excluded based on the configuration
                if (ExcludeLogic.ShouldExcludeClass(parms.Config, t1, t2))
                {
                    return;
                }

                parms.Object1Type = t1;
                parms.Object2Type = t2;

                //Compare the properties
                if (parms.Config.CompareProperties)
                {
                    _propertyComparer.PerformCompareProperties(parms);
                }

                //Compare the fields
                if (parms.Config.CompareFields)
                {
                    _fieldComparer.PerformCompareFields(parms);
                }
            }
            finally
            {
                parms.Result.RemoveParent(parms.Object1);
                parms.Result.RemoveParent(parms.Object2);
            }
        }
示例#7
0
        public override void CompareType(CompareParms parms)
        {
            Type t1 = parms.Object1.GetType();
            Type t2 = parms.Object2.GetType();

            //Check if the class type should be excluded based on the configuration
            if (ExcludeLogic.ShouldExcludeClass(parms.Config, t1, t2))
            {
                return;
            }

            parms.Object1Type = t1;
            parms.Object2Type = t2;

            if (!parms.Config.IgnoreCollectionOrder)
            {
                CompareItems(parms);
            }
        }
示例#8
0
        /// <summary>
        /// Compare two collections.
        /// </summary>
        public override void CompareType(CompareParms parms)
        {
            try
            {
                parms.Result.AddParent(parms.Object1);
                parms.Result.AddParent(parms.Object2);

                Type t1 = parms.Object1.GetType();
                Type t2 = parms.Object2.GetType();

                //Check if the class type should be excluded based on the configuration
                if (ExcludeLogic.ShouldExcludeClass(parms.Config, t1, t2))
                {
                    return;
                }

                parms.Object1Type = t1;
                parms.Object2Type = t2;

                bool countsDifferent = CollectionsDifferentCount(parms);

                if (parms.Result.ExceededDifferences)
                {
                    return;
                }

                if (parms.Config.IgnoreCollectionOrder)
                {
                    IgnoreOrderLogic logic = new IgnoreOrderLogic(RootComparer);
                    logic.CompareEnumeratorIgnoreOrder(parms, countsDifferent);
                }
                else
                {
                    CompareItems(parms);
                }
            }
            finally
            {
                parms.Result.RemoveParent(parms.Object1);
                parms.Result.RemoveParent(parms.Object2);
            }
        }
        /// <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);
        }
示例#10
0
        /// <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;
                }
            }
        }
示例#11
0
        /// <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);
        }
示例#12
0
        /// <summary>
        /// Compare the fields of a class
        /// </summary>
        public void PerformCompareFields(CompareParms parms)
        {
            IEnumerable <FieldInfo> currentFields = 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))
                    {
                        currentFields = Cache.GetFieldInfo(parms.Config, type);
                        break;
                    }
                }
            }

            if (currentFields == null)
            {
                currentFields = Cache.GetFieldInfo(parms.Config, parms.Object1Type);
            }


            foreach (FieldInfo item in currentFields)
            {
                //Skip if this is a shallow compare
                if (!parms.Config.CompareChildren && TypeHelper.CanHaveChildren(item.FieldType))
                {
                    continue;
                }

                //Skip if it should be excluded based on the configuration
                if (ExcludeLogic.ShouldExcludeMember(parms.Config, item))
                {
                    continue;
                }

                object objectValue1 = item.GetValue(parms.Object1);
                object objectValue2 = item.GetValue(parms.Object2);

                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 fields that point to the parent
                if ((TypeHelper.IsClass(item.FieldType) || TypeHelper.IsInterface(item.FieldType)) &&
                    (object1IsParent || object2IsParent))
                {
                    continue;
                }

                string currentBreadCrumb = AddBreadCrumb(parms.Config, parms.BreadCrumb, item.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 object1Property, PropertyEntity object2Property)
        {
            //If we can't read it, skip it
            if (object1Property?.CanRead == false || object2Property.CanRead == false)
            {
                return;
            }

            //Skip if this is a shallow compare
            if (!parms.Config.CompareChildren && TypeHelper.CanHaveChildren(object1Property?.PropertyType) ||
                !parms.Config.CompareChildren && TypeHelper.CanHaveChildren(object2Property.PropertyType))
            {
                return;
            }

            //Skip if it should be excluded based on the configuration
            if (object1Property?.PropertyInfo != null && ExcludeLogic.ShouldExcludeMember(parms.Config, object1Property.PropertyInfo) ||
                object2Property.PropertyInfo != null && ExcludeLogic.ShouldExcludeMember(parms.Config, object2Property.PropertyInfo))
            {
                return;
            }

            //If we should ignore read only, skip it
            if (!parms.Config.CompareReadOnly && object1Property?.CanWrite == false ||
                !parms.Config.CompareReadOnly && object2Property.CanWrite == false)
            {
                return;
            }

            //If the property does not exist, and we are ignoring the object types, skip it
            //We need to disscus this!!!!
            //if (parms.Config.IgnoreObjectTypes && secondObjectInfo == null)
            //    return;

            object objectValue1 = object1Property?.Value;
            object objectValue2 = object2Property?.Value;

            /*
             * //need deep investigation about indexerComparer!!!
             * if (!IsValidIndexer(parms.Config, object1Property, parms.BreadCrumb))
             * {
             *  objectValue1 = object1Property.Value;
             *  objectValue2 = object2Property != null ? object2Property.Value : null;
             * }
             * else
             * {
             *  _indexerComparer.CompareIndexer(parms, object1Property);
             *  return;
             * }
             * //need deep investigation about indexerComparer!!!
             */

            bool object1IsParent = objectValue1 != null && (objectValue1 == parms.Object1 || parms.Object1.GetHashCode().Equals(objectValue1.GetHashCode()));
            bool object2IsParent = objectValue2 != null && (objectValue2 == parms.Object2 || parms.Object2.GetHashCode().Equals(objectValue2.GetHashCode()));

            //Skip properties where both point to the corresponding parent
            if ((TypeHelper.IsClass(object1Property?.PropertyType) || TypeHelper.IsInterface(object1Property?.PropertyType) || TypeHelper.IsStruct(object1Property?.PropertyType) ||
                 TypeHelper.IsClass(object2Property.PropertyType) || TypeHelper.IsInterface(object2Property.PropertyType) || TypeHelper.IsStruct(object2Property.PropertyType)) &&
                (object1IsParent && object2IsParent))
            {
                return;
            }

            string currentBreadCrumb = AddBreadCrumb(parms.Config, parms.BreadCrumb, object1Property.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);
        }