private static void CollectionItems(
            object source,
            object target,
            MemberSettings settings,
            ReferencePairCollection referencePairs)
        {
            if (!Is.Enumerable(source, target))
            {
                return;
            }

            if (settings.ReferenceHandling == ReferenceHandling.Throw &&
                !settings.IsImmutable(source.GetType().GetItemType()))
            {
                throw State.Throw.ShouldNeverGetHereException("Should have been checked for throw before copy");
            }

            ICopyer copyer;
            if (ArrayCopyer.TryGetOrCreate(source, target, out copyer) ||
                ListOfTCopyer.TryGetOrCreate(source, target, out copyer) ||
                ListCopyer.TryGetOrCreate(source, target, out copyer) ||
                DictionaryTKeyTValueCopyer.TryGetOrCreate(source, target, out copyer) ||
                DictionaryCopyer.TryGetOrCreate(source, target, out copyer) ||
                SetOfTCopyer.TryGetOrCreate(source, target, out copyer))
            {
                copyer.Copy(source, target, settings, referencePairs);
                return;
            }

            if (source is IEnumerable || target is IEnumerable)
            {
                throw State.Throw.ShouldNeverGetHereException("Should be checked before");
            }
        }
 private static ErrorBuilder.TypeErrorsBuilder VerifyCore(MemberSettings settings, Type type)
 {
     return(ErrorBuilder.Start()
            .CheckRequiresReferenceHandling(type, settings, t => !settings.IsImmutable(t))
            .CheckIsCopyableEnumerable(type, settings)
            .CheckIndexers(type, settings));
 }
        // ReSharper disable once UnusedParameter.Local
        private static bool MemberValueEquals(
            object x,
            object y,
            MemberInfo propertyInfo,
            MemberSettings settings,
            ReferencePairCollection referencePairs)
        {
            if (TryGetValueEquals(x, y, settings, out var result))
            {
                return(result);
            }

            switch (settings.ReferenceHandling)
            {
            case ReferenceHandling.References:
                return(ReferenceEquals(x, y));

            case ReferenceHandling.Structural:
                Verify.CanEqualByMemberValues(x, y, settings);
                return(MemberValues(x, y, settings, referencePairs));

            case ReferenceHandling.Throw:
                throw Throw.ShouldNeverGetHereException();

            default:
                throw new ArgumentOutOfRangeException(
                          nameof(settings.ReferenceHandling),
                          settings.ReferenceHandling,
                          null);
            }
        }
Exemple #4
0
        private static TypeErrorsBuilder VerifyEnumerableRecursively(
            TypeErrorsBuilder typeErrors,
            Type type,
            MemberSettings settings,
            MemberPath memberPath,
            Func <MemberSettings, MemberPath, TypeErrors> getErrorsRecursively)
        {
            if (typeof(IEnumerable).IsAssignableFrom(type))
            {
                memberPath = memberPath == null
                                 ? new MemberPath(type)
                                 : memberPath.WithCollectionItem(type);

                var recursiveErrors = getErrorsRecursively(settings, memberPath);
                if (recursiveErrors == null)
                {
                    return(typeErrors);
                }

                var collectionErrors = new CollectionErrors(memberPath, recursiveErrors);
                typeErrors = typeErrors.CreateIfNull(type)
                             .Add(collectionErrors);
            }

            return(typeErrors);
        }
Exemple #5
0
 internal static void CanEqualByMemberValues <T>(
     MemberSettings settings,
     string className,
     string methodName)
 {
     CanEqualByMemberValues(typeof(T), settings, className, methodName);
 }
Exemple #6
0
        private static TypeErrorsBuilder VerifyMemberRecursively(
            TypeErrorsBuilder typeErrors,
            Type type,
            MemberSettings settings,
            MemberPath memberPath,
            Func <MemberSettings, MemberPath, TypeErrors> getErrorsRecursively,
            MemberInfo memberInfo)
        {
            memberPath = memberPath.WithMember(memberInfo);
            if (memberPath.HasLoop())
            {
                if (settings.ReferenceHandling == ReferenceHandling.Throw)
                {
                    typeErrors = typeErrors.CreateIfNull(type)
                                 .Add(new ReferenceLoop(memberPath));
                }

                return(typeErrors);
            }

            var recursiveErrors = getErrorsRecursively(settings, memberPath);

            if (recursiveErrors == null)
            {
                return(typeErrors);
            }

            var memberErrors = new MemberErrors(memberPath, recursiveErrors);

            typeErrors = typeErrors.CreateIfNull(type)
                         .Add(memberErrors);
            return(typeErrors);
        }
Exemple #7
0
        private static void Copy1DItems <T>(
            T[] sourceArray,
            T[] targetArray,
            MemberSettings settings,
            ReferencePairCollection referencePairs)
        {
            var copyValues = State.Copy.IsCopyValue(
                sourceArray.GetType().GetItemType(),
                settings);

            for (var i = 0; i < sourceArray.Length; i++)
            {
                if (copyValues)
                {
                    targetArray[i] = sourceArray[i];
                    continue;
                }

                var  sv = sourceArray[i];
                var  tv = targetArray[i];
                bool created;
                bool needsSync;
                var  clone = State.Copy.CloneWithoutSync(sv, tv, settings, out created, out needsSync);
                if (created)
                {
                    targetArray[i] = clone;
                }

                if (needsSync)
                {
                    State.Copy.Sync(sv, clone, settings, referencePairs);
                }
            }
        }
        public override bool Equals(
            object x,
            object y,
            MemberSettings settings,
            ReferencePairCollection referencePairs)
        {
            if (TryGetEitherNullEquals(x, y, out var result))
            {
                return(result);
            }

            var xl = (IList <T>)x;
            var yl = (IList <T>)y;

            if (xl.Count != yl.Count)
            {
                return(false);
            }

            var isEquatable = settings.IsEquatable(typeof(T));

            if (!typeof(T).IsValueType &&
                settings.ReferenceHandling == ReferenceHandling.References)
            {
                return(isEquatable
                           ? ItemsEquals(xl, yl, EqualityComparer <T> .Default.Equals)
                           : ItemsEquals(xl, yl, (xi, yi) => ReferenceEquals(xi, yi)));
            }

            return(isEquatable
                       ? ItemsEquals(xl, yl, EqualityComparer <T> .Default.Equals)
                       : Equals(xl, yl, settings, referencePairs));
        }
        private static void ThrowIfHasErrors(this TypeErrors errors, MemberSettings settings, string className, string methodName)
        {
            if (errors == null)
            {
                return;
            }

            if (errors.Errors.Count == 1 && ReferenceEquals(errors.Errors[0], RequiresReferenceHandling.ComplexType))
            {
                return;
            }

            var errorBuilder = new StringBuilder();

            errorBuilder.AppendFailed(className, methodName)
            .AppendNotSupported(errors)
            .AppendSolveTheProblemBy()
            .AppendSuggestEquatable(errors)
            .AppendLine($"* Use {settings.GetType().Name} and specify how comparing is performed:")
            .AppendSuggestReferenceHandling(errors, settings)
            .AppendSuggestExclude(errors);

            var message = errorBuilder.ToString();

            throw new NotSupportedException(message);
        }
Exemple #10
0
        private static void Members <T>(T source, T target, MemberSettings settings, ReferencePairCollection referencePairs)
        {
            Debug.Assert(source != null, nameof(source));
            Debug.Assert(target != null, nameof(target));
            Debug.Assert(source.GetType() == target.GetType(), "Must be same type");

            using (var borrowed = ListPool <IGetterAndSetter> .Borrow())
            {
                foreach (var member in settings.GetMembers(source.GetType()))
                {
                    if (settings.IsIgnoringMember(member))
                    {
                        continue;
                    }

                    var getterAndSetter = settings.GetOrCreateGetterAndSetter(member);
                    Member(source, target, settings, referencePairs, getterAndSetter);
                    if (getterAndSetter.IsInitOnly)
                    {
                        borrowed.Value.Add(getterAndSetter);
                    }
                }

                foreach (var getterAndSetter in borrowed.Value)
                {
                    var sv = getterAndSetter.GetValue(source);
                    var tv = getterAndSetter.GetValue(target);

                    if (!EqualBy.MemberValues(sv, tv, settings))
                    {
                        Throw.ReadonlyMemberDiffers(new SourceAndTargetValue(source, sv, target, tv), getterAndSetter.Member, settings);
                    }
                }
            }
        }
Exemple #11
0
        private static void TryAddCollectionDiffs(
            this DiffBuilder collectionBuilder,
            object x,
            object y,
            MemberSettings settings)
        {
            if (!Is.Enumerable(x, y))
            {
                return;
            }

            if (ListDiffBy.TryGetOrCreate(x, y, out var comparer) ||
                ReadonlyListDiffBy.TryGetOrCreate(x, y, out comparer) ||
                ArrayDiffBy.TryGetOrCreate(x, y, out comparer) ||
                DictionaryDiffBy.TryGetOrCreate(x, y, out comparer) ||
                ReadOnlyDictionaryDiffBy.TryGetOrCreate(x, y, out comparer) ||
                SetDiffBy.TryGetOrCreate(x, y, out comparer) ||
                EnumerableDiffBy.TryGetOrCreate(x, y, out comparer))
            {
                comparer.AddDiffs(collectionBuilder, x, y, settings);
                return;
            }

            throw Throw.ShouldNeverGetHereException("All enumarebles must be checked here");
        }
Exemple #12
0
        private static void CollectionItems(
            object source,
            object target,
            MemberSettings settings,
            ReferencePairCollection referencePairs)
        {
            if (!Is.Enumerable(source, target))
            {
                return;
            }

            if (settings.ReferenceHandling == ReferenceHandling.Throw &&
                !settings.IsImmutable(source.GetType().GetItemType()))
            {
                throw State.Throw.ShouldNeverGetHereException("Should have been checked for throw before copy");
            }

            if (ArrayCopyer.TryGetOrCreate(source, target, out var copyer) ||
                ListOfTCopyer.TryGetOrCreate(source, target, out copyer) ||
                ListCopyer.TryGetOrCreate(source, target, out copyer) ||
                DictionaryTKeyTValueCopyer.TryGetOrCreate(source, target, out copyer) ||
                DictionaryCopyer.TryGetOrCreate(source, target, out copyer) ||
                SetOfTCopyer.TryGetOrCreate(source, target, out copyer))
            {
                copyer.Copy(source, target, settings, referencePairs);
                return;
            }

            if (source is IEnumerable || target is IEnumerable)
            {
                throw State.Throw.ShouldNeverGetHereException("Should be checked before");
            }
        }
Exemple #13
0
        /// <inheritdoc />
        public override bool Equals(
            object x,
            object y,
            MemberSettings settings,
            ReferencePairCollection referencePairs)
        {
            bool result;

            if (TryGetEitherNullEquals(x, y, out result))
            {
                return(result);
            }

            var xd = (IReadOnlyDictionary <TKey, TValue>)x;
            var yd = (IReadOnlyDictionary <TKey, TValue>)y;

            if (xd.Count != yd.Count)
            {
                return(false);
            }

            if (settings.IsEquatable(typeof(TValue)))
            {
                return(KeysAndValuesEquals(xd, yd, EqualityComparer <TValue> .Default.Equals));
            }

            if (settings.ReferenceHandling == ReferenceHandling.References)
            {
                return(KeysAndValuesEquals(xd, yd, (xi, yi) => ReferenceEquals(xi, yi)));
            }

            return(KeysAndValuesEquals(xd, yd, settings, referencePairs));
        }
Exemple #14
0
        internal static bool KeysAndValuesEquals(
            IReadOnlyDictionary <TKey, TValue> x,
            IReadOnlyDictionary <TKey, TValue> y,
            MemberSettings settings,
            ReferencePairCollection referencePairs)
        {
            foreach (var key in x.Keys)
            {
                var xv = x[key];

                TValue yv;
                if (!y.TryGetValue(key, out yv))
                {
                    return(false);
                }

                if (referencePairs?.Contains(xv, yv) == true)
                {
                    continue;
                }

                if (!EqualBy.MemberValues(xv, yv, settings, referencePairs))
                {
                    return(false);
                }
            }

            return(true);
        }
Exemple #15
0
        private static void Copy2DItems <T>(
            T[,] sourceArray,
            T[,] targetArray,
            MemberSettings settings,
            ReferencePairCollection referencePairs)
        {
            var copyValues = State.Copy.IsCopyValue(
                sourceArray.GetType().GetItemType(),
                settings);

            for (var i = sourceArray.GetLowerBound(0); i <= sourceArray.GetUpperBound(0); i++)
            {
                for (var j = sourceArray.GetLowerBound(1); j <= sourceArray.GetUpperBound(1); j++)
                {
                    if (copyValues)
                    {
                        targetArray[i, j] = sourceArray[i, j];
                        continue;
                    }

                    var sv    = sourceArray[i, j];
                    var tv    = targetArray[i, j];
                    var clone = State.Copy.CloneWithoutSync(sv, tv, settings, out var created, out var needsSync);
                    if (created)
                    {
                        targetArray[i, j] = clone;
                    }

                    if (needsSync)
                    {
                        State.Copy.Sync(sv, clone, settings, referencePairs);
                    }
                }
            }
        }
Exemple #16
0
        internal static TypeErrorsBuilder VerifyRecursive(
            this TypeErrorsBuilder typeErrors,
            Type type,
            MemberSettings settings,
            MemberPath memberPath,
            Func <MemberSettings, MemberPath, TypeErrors> getPropertyErrors)
        {
            if (settings.ReferenceHandling == ReferenceHandling.References)
            {
                return(typeErrors);
            }

            typeErrors = VerifyEnumerableRecursively(typeErrors, type, settings, memberPath, getPropertyErrors);

            foreach (var member in settings.GetMembers(type))
            {
                if (settings.IsIgnoringMember(member))
                {
                    continue;
                }

                if (memberPath == null)
                {
                    memberPath = new MemberPath(type);
                }

                typeErrors = VerifyMemberRecursively(typeErrors, type, settings, memberPath, getPropertyErrors, member);
            }

            return(typeErrors);
        }
Exemple #17
0
        private static void CopyAnyDimension(
            Array sourceArray,
            Array targetArray,
            MemberSettings settings,
            ReferencePairCollection referencePairs)
        {
            var copyValues = State.Copy.IsCopyValue(
                sourceArray.GetType().GetItemType(),
                settings);

            foreach (var index in sourceArray.Indices())
            {
                if (copyValues)
                {
                    targetArray.SetValue(sourceArray.GetValue(index), index);
                    continue;
                }

                var  sv = sourceArray.GetValue(index);
                var  tv = targetArray.GetValue(index);
                bool created;
                bool needsSync;
                var  clone = State.Copy.CloneWithoutSync(sv, tv, settings, out created, out needsSync);
                if (created)
                {
                    targetArray.SetValue(clone, index);
                }

                if (needsSync)
                {
                    State.Copy.Sync(sv, clone, settings, referencePairs);
                }
            }
        }
        internal static bool TryGetValueEquals <T>(T x, T y, MemberSettings settings, out bool result)
        {
            if (ReferenceEquals(x, y))
            {
                result = true;
                return(true);
            }

            if (x == null || y == null)
            {
                result = false;
                return(true);
            }

            if (x.GetType() != y.GetType())
            {
                result = false;
                return(true);
            }

            if (settings.TryGetComparer(x.GetType(), out var comparer))
            {
                result = comparer.Equals(x, y);
                return(true);
            }

            if (settings.IsEquatable(x.GetType()))
            {
                result = Equals(x, y);
                return(true);
            }

            result = false;
            return(false);
        }
Exemple #19
0
        internal static object CreateInstance(object sourceValue, MemberSettings settings)
        {
            if (sourceValue == null)
            {
                return(null);
            }

            var type = sourceValue.GetType();

            if (type.IsArray)
            {
                var constructor = type.GetConstructor(new[] { typeof(int) });
                var parameters  = new[] { type.GetProperty("Length").GetValue(sourceValue) };
                //// ReSharper disable once PossibleNullReferenceException nope, never null here
                var array = constructor.Invoke(parameters);
                return(array);
            }

            if (settings.IsImmutable(type))
            {
                return(sourceValue);
            }

            try
            {
                return(Activator.CreateInstance(type, true));
            }
            catch (Exception e)
            {
                throw Throw.CreateCannotCreateInstanceException(sourceValue, settings, e);
            }
        }
Exemple #20
0
        internal static bool TryCreate(object x, object y, MemberSettings settings, out IRefCounted <DiffBuilder> subDiffBuilder)
        {
            bool created;

            subDiffBuilder = TrackerCache.GetOrAdd(x, y, settings, pair => new DiffBuilder(pair, settings), out created);
            return(created);
        }
        /// <inheritdoc />
        public override bool Equals(
            object x,
            object y,
            MemberSettings settings,
            ReferencePairCollection referencePairs)
        {
            bool result;

            if (TryGetEitherNullEquals(x, y, out result))
            {
                return(result);
            }

            var isEquatable = settings.IsEquatable(typeof(T));

            if (settings.ReferenceHandling == ReferenceHandling.References)
            {
                return(isEquatable
                           ? ItemsEquals((IEnumerable <T>)x, (IEnumerable <T>)y, EqualityComparer <T> .Default.Equals)
                           : ItemsEquals((IEnumerable <T>)x, (IEnumerable <T>)y, (xi, yi) => ReferenceEquals(xi, yi)));
            }

            return(isEquatable
                       ? ItemsEquals((IEnumerable <T>)x, (IEnumerable <T>)y, EqualityComparer <T> .Default.Equals)
                       : ItemsEquals((IEnumerable <T>)x, (IEnumerable <T>)y, (xi, yi) => EqualBy.MemberValues(xi, yi, settings, referencePairs)));
        }
        private static void Copy <T>(
            ISet <T> source,
            ISet <T> target,
            MemberSettings settings,
            ReferencePairCollection referencePairs)
        {
            if (Is.IsFixedSize(source, target) && source.Count != target.Count)
            {
                throw State.Copy.Throw.CannotCopyFixesSizeCollections(source, target, settings);
            }

            if (settings.IsImmutable(typeof(T)))
            {
                using (var borrow = HashSetPool <T> .Borrow(EqualityComparer <T> .Default))
                {
                    borrow.Value.UnionWith(source);
                    target.IntersectWith(borrow.Value);
                    target.UnionWith(borrow.Value);
                    return;
                }
            }

            switch (settings.ReferenceHandling)
            {
            case ReferenceHandling.Throw:
                break;

            case ReferenceHandling.References:
                using (var borrow = HashSetPool <T> .Borrow((x, y) => ReferenceEquals(x, y), x => RuntimeHelpers.GetHashCode(x)))
                {
                    borrow.Value.UnionWith(source);
                    target.IntersectWith(borrow.Value);
                    target.UnionWith(borrow.Value);
                }

                break;

            case ReferenceHandling.Structural:
                IEqualityComparer <T> comparer;
                if (!Set.TryGetComparer(source, out comparer))
                {
                    comparer = EqualityComparer <T> .Default;
                }

                var copyIngComparer = new CopyingComparer <T>(comparer, settings, referencePairs);
                using (var borrow = HashSetPool <T> .Borrow(copyIngComparer))
                {
                    borrow.Value.UnionWith(source);
                    target.IntersectWith(borrow.Value);
                    copyIngComparer.StartCopying();
                    target.UnionWith(borrow.Value);
                }

                return;

            default:
                throw new ArgumentOutOfRangeException();
            }
        }
 public void AddDiffs(
     DiffBuilder collectionBuilder,
     object x,
     object y,
     MemberSettings settings)
 {
     this.AddDiffs(collectionBuilder, (IReadOnlyList <T>)x, (IReadOnlyList <T>)y, settings);
 }
 public void AddDiffs(
     DiffBuilder collectionBuilder,
     object x,
     object y,
     MemberSettings settings)
 {
     this.AddDiffs(collectionBuilder, (IDictionary <TKey, TValue>)x, (IDictionary <TKey, TValue>)y, settings);
 }
Exemple #25
0
 public void AddDiffs(
     DiffBuilder collectionBuilder,
     object x,
     object y,
     MemberSettings settings)
 {
     this.AddDiffs(collectionBuilder, (Array)x, (Array)y, settings);
 }
 public void AddDiffs(
     DiffBuilder collectionBuilder,
     object x,
     object y,
     MemberSettings settings)
 {
     this.AddDiffs(collectionBuilder, (IEnumerable <T>)x, (IEnumerable <T>)y, settings);
 }
 public void Copy(
     object source,
     object target,
     MemberSettings settings,
     ReferencePairCollection referencePairs)
 {
     Copy((IDictionary)source, (IDictionary)target, settings, referencePairs);
 }
Exemple #28
0
 public void Copy(
     object source,
     object target,
     MemberSettings settings,
     ReferencePairCollection referencePairs)
 {
     Copy((Array)source, (Array)target, settings, referencePairs);
 }
Exemple #29
0
 public void AddDiffs(
     DiffBuilder collectionBuilder,
     object x,
     object y,
     MemberSettings settings)
 {
     this.AddDiffs(collectionBuilder, (Array)x, (Array)y, settings);
 }
Exemple #30
0
 // ReSharper disable once UnusedParameter.Local
 internal static void IfHasErrors(TypeErrors errors, MemberSettings settings, string className, string methodName)
 {
     if (errors.HasErrors())
     {
         var message = GetErrorText(errors, settings, className, methodName);
         throw new NotSupportedException(message);
     }
 }
        public bool TryGetValueEquals(object x, object y, MemberSettings settings, out bool equal, out object xv, out object yv)
        {
            var result = this.TryGetValueEquals((TSource)x, (TSource)y, settings, out equal, out var xValue, out var yValue);

            xv = xValue;
            yv = yValue;
            return(result);
        }
Exemple #32
0
        internal static bool IsCopyValue(Type type, MemberSettings settings)
        {
            if (settings.IsImmutable(type) || settings.ReferenceHandling == ReferenceHandling.References)
            {
                return(true);
            }

            return(false);
        }
 public CopyingComparer(
     IEqualityComparer <T> inner,
     MemberSettings settings,
     ReferencePairCollection referencePairs)
 {
     this.inner          = inner;
     this.settings       = settings;
     this.referencePairs = referencePairs;
 }
Exemple #34
0
 // ReSharper disable once UnusedParameter.Local
 internal static Exception CannotCopyFixesSizeCollections(
     IEnumerable source,
     IEnumerable target,
     MemberSettings settings)
 {
     var error = new CannotCopyFixedSizeCollectionsError(source, target);
     var typeErrors = new TypeErrors(target.GetType(), error);
     var message = typeErrors.GetErrorText(settings, typeof(Copy).Name, settings.CopyMethodName());
     return new InvalidOperationException(message);
 }
Exemple #35
0
            // ReSharper disable once UnusedParameter.Local
            internal static void ReadonlyMemberDiffers(
                SourceAndTargetValue sourceAndTargetValue,
                MemberInfo member,
                MemberSettings settings)
            {
                var error = new ReadonlyMemberDiffersError(sourceAndTargetValue, member);
                var typeErrors = new TypeErrors(sourceAndTargetValue.Source?.GetType(), error);

                var message = typeErrors.GetErrorText(settings, typeof(Copy).Name, settings.CopyMethodName());
                throw new InvalidOperationException(message);
            }
        /// <inheritdoc />
        public override bool Equals(
            object x,
            object y,
            MemberSettings settings,
            ReferencePairCollection referencePairs)
        {
            bool result;
            if (TryGetEitherNullEquals(x, y, out result))
            {
                return result;
            }

            return Equals((Array)x, (Array)y, settings, referencePairs);
        }
Exemple #37
0
        // ReSharper disable once UnusedParameter.Local
        private static void ThrowIfHasErrors(this TypeErrors errors, MemberSettings settings, string className, string methodName)
        {
            if (errors == null)
            {
                return;
            }

            if (errors.Errors.Count == 1 && ReferenceEquals(errors.Errors[0], RequiresReferenceHandling.ComplexType))
            {
                return;
            }

            var message = errors.GetErrorText(settings, className, methodName);
            throw new NotSupportedException(message);
        }
Exemple #38
0
        internal static TypeErrorsBuilder CheckRequiresReferenceHandling(
            this TypeErrorsBuilder typeErrors,
            Type type,
            MemberSettings settings,
            Func<Type, bool> requiresReferenceHandling)
        {
            if (settings.ReferenceHandling == ReferenceHandling.Throw)
            {
                if (typeof(IEnumerable).IsAssignableFrom(type))
                {
                    if (type.Implements(typeof(IDictionary<,>)))
                    {
                        var arguments = type.GetGenericArguments();
                        if (arguments.Length != 2 ||
                            requiresReferenceHandling(arguments[0]) ||
                            requiresReferenceHandling(arguments[1]))
                        {
                            typeErrors = typeErrors.CreateIfNull(type)
                                                   .Add(RequiresReferenceHandling.Enumerable);
                        }
                    }
                    else if (requiresReferenceHandling(type.GetItemType()))
                    {
                        typeErrors = typeErrors.CreateIfNull(type)
                                               .Add(RequiresReferenceHandling.Enumerable);
                    }
                }
                else if (type.IsKeyValuePair())
                {
                    var arguments = type.GetGenericArguments();
                    if (requiresReferenceHandling(arguments[0]) || requiresReferenceHandling(arguments[1]))
                    {
                        typeErrors = typeErrors.CreateIfNull(type)
                                               .Add(RequiresReferenceHandling.ComplexType);
                    }
                }
                else if (requiresReferenceHandling(type))
                {
                    typeErrors = typeErrors.CreateIfNull(type)
                                           .Add(RequiresReferenceHandling.ComplexType);
                }
            }

            return typeErrors;
        }
Exemple #39
0
        private void AddDiffs(
            DiffBuilder collectionBuilder,
            Array x,
            Array y,
            MemberSettings settings)
        {
            RankDiff rankDiff;
            if (TryGetRankDiff(x, y, out rankDiff))
            {
                collectionBuilder.Add(rankDiff);
                return;
            }

            foreach (var index in x.Indices())
            {
                collectionBuilder.UpdateCollectionItemDiff(x.GetValue(index), y.GetValue(index), new Index(index), settings);
            }
        }
Exemple #40
0
        // ReSharper disable once UnusedParameter.Local
        private static string GetErrorText(this TypeErrors errors, MemberSettings settings, string className, string methodName)
        {
            var errorBuilder = new StringBuilder();
            errorBuilder.AppendCopyFailed(className, methodName)
                        .AppendNotSupported(errors)
                        .AppendSolveTheProblemBy()
                        .AppendSuggestImmutable(errors)
                        .AppendSuggestResizableCollection(errors)
                        .AppendSuggestDefaultCtor(errors)
                        .AppendLine($"* Use {settings.GetType().Name} and specify how copying is performed:")
                        .AppendLine($"  - {typeof(ReferenceHandling).Name}.{nameof(ReferenceHandling.Structural)} means that a the entire graph is traversed and immutable property values are copied.")
                        .AppendLine($"    - For structural Activator.CreateInstance is used to create instances so a parameterless constructor may be needed, can be private.")
                        .AppendLine($"  - {typeof(ReferenceHandling).Name}.{nameof(ReferenceHandling.References)} means that references are copied.")
                        .AppendSuggestExclude(errors);

            var message = errorBuilder.ToString();
            return message;
        }
        internal static void Copy(
            IDictionary source,
            IDictionary target,
            MemberSettings settings,
            ReferencePairCollection referencePairs)
        {
            using (var toRemove = ListPool<object>.Borrow())
            {
                foreach (var key in target.Keys)
                {
                    if (!source.Contains(key))
                    {
                        toRemove.Value.Add(key);
                    }
                    else
                    {
                        // Synchronize key?
                    }
                }

                foreach (var key in toRemove.Value)
                {
                    target.Remove(key);
                }
            }

            foreach (var key in source.Keys)
            {
                var sv = source[key];
                var tv = target.ElementAtOrDefault(key);
                bool created;
                bool needsSync;
                var clone = State.Copy.CloneWithoutSync(sv, tv, settings, out created, out needsSync);
                if (created)
                {
                    target[key] = clone;
                }

                if (needsSync)
                {
                    State.Copy.Sync(sv, clone, settings, referencePairs);
                }
            }
        }
Exemple #42
0
        private static void Copy(
            IList source,
            IList target,
            MemberSettings settings,
            ReferencePairCollection referencePairs)
        {
            if ((source.IsFixedSize || target.IsFixedSize) && source.Count != target.Count)
            {
                throw State.Copy.Throw.CannotCopyFixesSizeCollections(source, target, settings);
            }

            var copyValues = State.Copy.IsCopyValue(
                        source.GetType().GetItemType(),
                        settings);
            for (var i = 0; i < source.Count; i++)
            {
                if (copyValues)
                {
                    target.SetElementAt(i, source[i]);
                    continue;
                }

                var sv = source[i];
                var tv = target.ElementAtOrDefault(i);
                bool created;
                bool needsSync;
                var clone = State.Copy.CloneWithoutSync(sv, tv, settings, out created, out needsSync);
                if (created)
                {
                    target.SetElementAt(i, clone);
                }

                if (needsSync)
                {
                    State.Copy.Sync(sv, clone, settings, referencePairs);
                }
            }

            target.TrimLengthTo(source);
        }
        private static StringBuilder AppendSuggestReferenceHandling(
            this StringBuilder errorBuilder,
            TypeErrors errors,
            MemberSettings settings)
        {
            var references = $"  - {typeof(ReferenceHandling).Name}.{nameof(ReferenceHandling.References)} means that reference equality is used.";
            if (settings.ReferenceHandling == ReferenceHandling.Throw)
            {
                if (errors.AllErrors.OfType<RequiresReferenceHandling>().Any())
                {
                    return errorBuilder.AppendLine($"  - {typeof(ReferenceHandling).Name}.{nameof(ReferenceHandling.Structural)} means that a deep equals is performed.")
                                       .AppendLine(references);
                }
            }

            if (errors.AllErrors.OfType<ReferenceLoop>().Any())
            {
                return errorBuilder.AppendLine(references);
            }

            return errorBuilder;
        }
        private static bool Equals(
            Array x,
            Array y,
            MemberSettings settings,
            ReferencePairCollection referencePairs)
        {
            if (!Is.SameSize(x, y))
            {
                return false;
            }

            var isEquatable = settings.IsEquatable(x.GetType().GetItemType());
            if (settings.ReferenceHandling == ReferenceHandling.References)
            {
                return isEquatable
                           ? ItemsEquals(x, y, Equals)
                           : ItemsEquals(x, y, ReferenceEquals);
            }

            return isEquatable
                       ? ItemsEquals(x, y, Equals)
                       : ItemsEquals(x, y, (xi, yi) => EqualBy.MemberValues(xi, yi, settings, referencePairs));
        }
        private static void ThrowIfHasErrors(this TypeErrors errors, MemberSettings settings, string className, string methodName)
        {
            if (errors == null)
            {
                return;
            }

            if (errors.Errors.Count == 1 && ReferenceEquals(errors.Errors[0], RequiresReferenceHandling.ComplexType))
            {
                return;
            }

            var errorBuilder = new StringBuilder();
            errorBuilder.AppendFailed(className, methodName)
                        .AppendNotSupported(errors)
                        .AppendSolveTheProblemBy()
                        .AppendSuggestEquatable(errors)
                        .AppendLine($"* Use {settings.GetType().Name} and specify how comparing is performed:")
                        .AppendSuggestReferenceHandling(errors, settings)
                        .AppendSuggestExclude(errors);

            var message = errorBuilder.ToString();
            throw new NotSupportedException(message);
        }
Exemple #46
0
        internal static TypeErrorsBuilder CheckIndexers(this TypeErrorsBuilder typeErrors, Type type, MemberSettings settings)
        {
            var propertiesSettings = settings as PropertiesSettings;
            var propertyInfos = type.GetProperties(settings.BindingFlags);
            foreach (var propertyInfo in propertyInfos)
            {
                if (propertyInfo.GetIndexParameters().Length == 0)
                {
                    continue;
                }

                if (propertiesSettings?.IsIgnoringProperty(propertyInfo) == true)
                {
                    continue;
                }

                if (settings.IsIgnoringDeclaringType(propertyInfo.DeclaringType))
                {
                    continue;
                }

                typeErrors = typeErrors.CreateIfNull(type)
                                       .Add(UnsupportedIndexer.GetOrCreate(propertyInfo));
            }

            return typeErrors;
        }
Exemple #47
0
        private static TypeErrorsBuilder VerifyMemberRecursively(
            TypeErrorsBuilder typeErrors,
            Type type,
            MemberSettings settings,
            MemberPath memberPath,
            Func<MemberSettings, MemberPath, TypeErrors> getErrorsRecursively,
            MemberInfo memberInfo)
        {
            memberPath = memberPath.WithMember(memberInfo);
            if (memberPath.HasLoop())
            {
                if (settings.ReferenceHandling == ReferenceHandling.Throw)
                {
                    typeErrors = typeErrors.CreateIfNull(type)
                                           .Add(new ReferenceLoop(memberPath));
                }

                return typeErrors;
            }

            var recursiveErrors = getErrorsRecursively(settings, memberPath);
            if (recursiveErrors == null)
            {
                return typeErrors;
            }

            var memberErrors = new MemberErrors(memberPath, recursiveErrors);
            typeErrors = typeErrors.CreateIfNull(type)
                                   .Add(memberErrors);
            return typeErrors;
        }
Exemple #48
0
        private static TypeErrorsBuilder VerifyEnumerableRecursively(
            TypeErrorsBuilder typeErrors,
            Type type,
            MemberSettings settings,
            MemberPath memberPath,
            Func<MemberSettings, MemberPath, TypeErrors> getErrorsRecursively)
        {
            if (typeof(IEnumerable).IsAssignableFrom(type))
            {
                memberPath = memberPath == null
                                 ? new MemberPath(type)
                                 : memberPath.WithCollectionItem(type);

                var recursiveErrors = getErrorsRecursively(settings, memberPath);
                if (recursiveErrors == null)
                {
                    return typeErrors;
                }

                var collectionErrors = new CollectionErrors(memberPath, recursiveErrors);
                typeErrors = typeErrors.CreateIfNull(type)
                                       .Add(collectionErrors);
            }

            return typeErrors;
        }
Exemple #49
0
        internal static TypeErrorsBuilder VerifyRecursive(
            this TypeErrorsBuilder typeErrors,
            Type type,
            MemberSettings settings,
            MemberPath memberPath,
            Func<MemberSettings, MemberPath, TypeErrors> getPropertyErrors)
        {
            if (settings.ReferenceHandling == ReferenceHandling.References)
            {
                return typeErrors;
            }

            typeErrors = VerifyEnumerableRecursively(typeErrors, type, settings, memberPath, getPropertyErrors);

            foreach (var member in settings.GetMembers(type))
            {
                if (settings.IsIgnoringMember(member))
                {
                    continue;
                }

                if (memberPath == null)
                {
                    memberPath = new MemberPath(type);
                }

                typeErrors = VerifyMemberRecursively(typeErrors, type, settings, memberPath, getPropertyErrors, member);
            }

            return typeErrors;
        }
Exemple #50
0
        internal static TypeErrorsBuilder CheckNotifies(this TypeErrorsBuilder typeErrors, Type type, MemberSettings settings)
        {
            if (settings.IsImmutable(type))
            {
                return typeErrors;
            }

            if (type.IsValueType)
            {
                if (typeof(INotifyCollectionChanged).IsAssignableFrom(type) ||
                    typeof(INotifyPropertyChanged).IsAssignableFrom(type))
                {
                    return typeErrors.CreateIfNull(type)
                                     .Add(StructMustNotNotifyError.GetOrCreate(type));
                }

                return typeErrors;
            }

            if (typeof(IEnumerable).IsAssignableFrom(type))
            {
                if (!typeof(INotifyCollectionChanged).IsAssignableFrom(type))
                {
                    return typeErrors.CreateIfNull(type)
                                           .Add(CollectionMustNotifyError.GetOrCreate(type));
                }
            }
            else if (!typeof(INotifyPropertyChanged).IsAssignableFrom(type))
            {
                if (settings.IsIgnoringDeclaringType(type))
                {
                    return typeErrors;
                }

                return typeErrors.CreateIfNull(type)
                                 .Add(TypeMustNotifyError.GetOrCreate(type));
            }

            return typeErrors;
        }
Exemple #51
0
 internal static InvalidOperationException CreateCannotCreateInstanceException(
     object sourceValue,
     MemberSettings settings,
     Exception exception)
 {
     var cannotCopyError = new CannotCreateInstanceError(sourceValue);
     var typeErrors = new TypeErrors(sourceValue.GetType(), new Error[] { cannotCopyError });
     var message = typeErrors.GetErrorText(settings, typeof(Copy).Name, settings.CopyMethodName());
     return new InvalidOperationException(message, exception);
 }