Пример #1
0
        internal static TypeErrors Merge(this TypeErrors first, TypeErrors other)
        {
            if (first == null)
            {
                return other;
            }

            if (other == null)
            {
                return first;
            }

            if (first == other)
            {
                return first;
            }

            if (first.Type == other.Type)
            {
                if (first.Errors.Count == 0)
                {
                    return other;
                }

                if (other.Errors.Count == 0)
                {
                    return first;
                }

                var errors = new MergedErrors(first.Errors, other.Errors);
                return new TypeErrors(first.Type, errors);
            }

            return new TypeErrors(null, new[] { first, other });
        }
Пример #2
0
        internal static TypeErrors Merge(this TypeErrors first, TypeErrors other)
        {
            if (first == null)
            {
                return(other);
            }

            if (other == null)
            {
                return(first);
            }

            if (first == other)
            {
                return(first);
            }

            if (first.Type == other.Type)
            {
                if (first.Errors.Count == 0)
                {
                    return(other);
                }

                if (other.Errors.Count == 0)
                {
                    return(first);
                }

                var errors = new MergedErrors(first.Errors, other.Errors);
                return(new TypeErrors(first.Type, errors));
            }

            return(new TypeErrors(null, new[] { first, other }));
        }
        internal static StringBuilder AppendSuggestImmutable(this StringBuilder errorBuilder, TypeErrors errors)
        {
            var fixableTypes = errors.AllErrors.OfType<TypeErrors>()
                                     .Where(x => x.Type != errors.Type)
                                     .Select(x => x.Type)
                                     .Distinct()
                                     .ToArray();
            if (!fixableTypes.Any())
            {
                return errorBuilder;
            }

            foreach (var type in fixableTypes)
            {
                var line = type.Assembly == typeof(int).Assembly
                    ? $"* Use an immutable type instead of {type.PrettyName()}."
                    : $"* Make {type.PrettyName()} immutable or use an immutable type.";
                errorBuilder.AppendLine(line);
            }

            errorBuilder.AppendLine("  - For immutable types the following must hold:")
                        .AppendLine("    - Must be a sealed class or a struct.")
                        .AppendLine("    - All fields and properties must be readonly.")
                        .AppendLine("    - All field and property types must be immutable.")
                        .AppendLine("    - All indexers must be readonly.")
                        .AppendLine("    - Event fields are ignored.");
            return errorBuilder;
        }
Пример #4
0
        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);
        }
Пример #5
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);
     }
 }
Пример #6
0
        public static IReadOnlyList <Error> MergeAll(TypeErrors typeErrors, IReadOnlyCollection <Error> errors)
        {
            var allErrors = new List <Error> {
                typeErrors
            };

            Add(errors, allErrors);
            return(allErrors);
        }
Пример #7
0
            internal static void CanTrackValue(object value, PropertiesSettings settings)
            {
                var errors = GetOrCreateErrors(value.GetType(), settings);

                if (errors != null)
                {
                    var typeErrors = new TypeErrors(null, errors);
                    Throw.IfHasErrors(typeErrors, settings, typeof(Track).Name, nameof(Track.Changes));
                }
            }
Пример #8
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));
            }
Пример #9
0
            private static bool TryEquals(TypeErrors x, TypeErrors y, out bool result)
            {
                if (x == null || y == null)
                {
                    result = false;
                    return(false);
                }

                result = x.Type == y.Type;
                return(true);
            }
Пример #10
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);
            }
        internal static StringBuilder AppendSuggestNotify(this StringBuilder errorBuilder, TypeErrors errors)
        {
            foreach (var error in errors.AllErrors.OfType<TypeErrors>().Where(te => te.HasError<IFixWithNotify>()).Distinct())
            {
                var fixable = error.Errors.OfType<IFixWithNotify>()
                                          .First();
                fixable.AppendSuggestFixWithNotify(errorBuilder, error.Type);
            }

            return errorBuilder;
        }
Пример #12
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));
            }
Пример #13
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);
            }
Пример #14
0
        private static bool HasErrors(this TypeErrors errors)
        {
            if (errors == null)
            {
                return(false);
            }

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

            return(true);
        }
Пример #15
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);
        }
        internal static StringBuilder AppendSuggestEquatable(this StringBuilder errorBuilder, TypeErrors errors)
        {
            const string Format = "IEquatable<{0}>";
            var types = errors.AllErrors.OfType<TypeErrors>()
                              .Select(x => x.Type)
                              .Distinct();
            foreach (var type in types)
            {
                var iEquatable = string.Format(Format, type.PrettyName());
                var line = type.Assembly == typeof(int).Assembly
                    ? $"* Use a type that implements IEquatable<> instead of {type.PrettyName()}."
                    : $"* Implement {iEquatable} for {type.PrettyName()} or use a type that does.";
                errorBuilder.AppendLine(line);
            }

            return errorBuilder;
        }
Пример #17
0
        private bool TryMerge(TypeErrors error)
        {
            if (error == null)
            {
                return(false);
            }

            var match = this.errors.OfType <TypeErrors>().SingleOrDefault(e => e.Type == error.Type);

            if (match != null)
            {
                this.errors.Remove(match);
                var merged = match.Merge(error);
                this.errors.Add(merged);
                return(true);
            }

            this.errors.Add(error);
            return(true);
        }
Пример #18
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);
        }
Пример #19
0
            // ReSharper disable once UnusedParameter.Local
            private static string GetErrorText(TypeErrors errors, MemberSettings settings, string className, string methodName)
            {
                var errorBuilder = new StringBuilder();

                errorBuilder.AppendLine($"{className}.{methodName}(x, y) failed.")
                .AppendNotSupported(errors)
                .AppendSolveTheProblemBy()
                .AppendSuggestNotify(errors)
                .AppendSuggestImmutable(errors)
                .AppendSuggestResizableCollection(errors)
                .AppendSuggestDefaultCtor(errors)
                .AppendLine($"* Use {settings?.GetType().Name} and specify how change tracking is performed:")
                .AppendLine($"  - {typeof(ReferenceHandling).Name}.{nameof(ReferenceHandling.Structural)} means that a the entire graph is tracked.")
                .AppendLine($"  - {typeof(ReferenceHandling).Name}.{nameof(ReferenceHandling.References)} means that only the root level changes are tracked.")
                .AppendSuggestExclude(errors);

                var message = errorBuilder.ToString();

                return(message);
            }
Пример #20
0
        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;
        }
        internal static StringBuilder AppendNotSupported(this StringBuilder errorBuilder, TypeErrors errors)
        {
            foreach (var error in errors.AllErrors.OfType<INotSupported>().Distinct())
            {
                error.AppendNotSupported(errorBuilder);
            }

            foreach (var member in errors.AllErrors.OfType<MemberErrors>().Select(x => x.Member).Distinct())
            {
                errorBuilder.AppendNotSupportedMember(member);
            }

            if (errors.AllErrors.OfType<UnsupportedIndexer>().Any())
            {
                errorBuilder.AppendLine("Indexers are not supported.");
                foreach (var indexer in errors.AllErrors.OfType<UnsupportedIndexer>().Select(x => x.Indexer).Distinct())
                {
                    errorBuilder.AppendNotSupportedMember(indexer);
                }
            }

            return errorBuilder;
        }
Пример #22
0
        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);
        }
Пример #23
0
        internal static StringBuilder AppendNotSupported(this StringBuilder errorBuilder, TypeErrors errors)
        {
            foreach (var error in errors.AllErrors.OfType <INotSupported>().Distinct())
            {
                error.AppendNotSupported(errorBuilder);
            }

            foreach (var member in errors.AllErrors.OfType <MemberErrors>().Select(x => x.Member).Distinct())
            {
                errorBuilder.AppendNotSupportedMember(member);
            }

            if (errors.AllErrors.OfType <UnsupportedIndexer>().Any())
            {
                errorBuilder.AppendLine("Indexers are not supported.");
                foreach (var indexer in errors.AllErrors.OfType <UnsupportedIndexer>().Select(x => x.Indexer).Distinct())
                {
                    errorBuilder.AppendNotSupportedMember(indexer);
                }
            }

            return(errorBuilder);
        }
        internal static StringBuilder AppendSuggestDefaultCtor(this StringBuilder errorBuilder, TypeErrors errors)
        {
            foreach (var type in errors.AllErrors.OfType<CannotCreateInstanceError>().Select(x => x.Type).Distinct())
            {
                errorBuilder.AppendLine($"* Add a parameterless constructor to {type.PrettyName()}, can be private.");
            }

            return errorBuilder;
        }
        internal static StringBuilder AppendSuggestResizableCollection(this StringBuilder errorBuilder, TypeErrors errors)
        {
            foreach (var type in errors.AllErrors.OfType<CannotCopyFixedSizeCollectionsError>().Select(x => x.Type).Distinct())
            {
                errorBuilder.AppendLine($"* Use a resizable collection like List<{type.GetItemType().PrettyName()}> instead of {type.PrettyName()}.")
                            .AppendLine("* Check that the collections are the same size before calling.");
            }

            return errorBuilder;
        }
Пример #26
0
 public MemberErrors(MemberPath path, TypeErrors errors)
 {
     this.Path = path;
     this.Error = errors;
     this.Errors = errors == null ? EmptyErrors : new[] { errors };
 }
Пример #27
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);
 }
Пример #28
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);
 }
Пример #29
0
        internal static StringBuilder AppendSuggestResizableCollection(this StringBuilder errorBuilder, TypeErrors errors)
        {
            foreach (var type in errors.AllErrors.OfType <CannotCopyFixedSizeCollectionsError>().Select(x => x.Type).Distinct())
            {
                errorBuilder.AppendLine($"* Use a resizable collection like List<{type.GetItemType().PrettyName()}> instead of {type.PrettyName()}.")
                .AppendLine("* Check that the collections are the same size before calling.");
            }

            return(errorBuilder);
        }
Пример #30
0
        internal static StringBuilder AppendSuggestDefaultCtor(this StringBuilder errorBuilder, TypeErrors errors)
        {
            foreach (var type in errors.AllErrors.OfType <CannotCreateInstanceError>().Select(x => x.Type).Distinct())
            {
                errorBuilder.AppendLine($"* Add a parameterless constructor to {type.PrettyName()}, can be private.");
            }

            return(errorBuilder);
        }
Пример #31
0
        internal static StringBuilder AppendSuggestEquatable(this StringBuilder errorBuilder, TypeErrors errors)
        {
            const string Format = "IEquatable<{0}>";
            var          types  = errors.AllErrors.OfType <TypeErrors>()
                                  .Select(x => x.Type)
                                  .Distinct();

            foreach (var type in types)
            {
                var iEquatable = string.Format(Format, type.PrettyName());
                var line       = type.Assembly == typeof(int).Assembly
                    ? $"* Use a type that implements IEquatable<> instead of {type.PrettyName()}."
                    : $"* Implement {iEquatable} for {type.PrettyName()} or use a type that does.";
                errorBuilder.AppendLine(line);
            }

            return(errorBuilder);
        }
Пример #32
0
        internal static StringBuilder AppendSuggestImmutable(this StringBuilder errorBuilder, TypeErrors errors)
        {
            var fixableTypes = errors.AllErrors.OfType <TypeErrors>()
                               .Where(x => x.Type != errors.Type)
                               .Select(x => x.Type)
                               .Distinct()
                               .ToArray();

            if (!fixableTypes.Any())
            {
                return(errorBuilder);
            }

            foreach (var type in fixableTypes)
            {
                var line = type.Assembly == typeof(int).Assembly
                    ? $"* Use an immutable type instead of {type.PrettyName()}."
                    : $"* Make {type.PrettyName()} immutable or use an immutable type.";
                errorBuilder.AppendLine(line);
            }

            errorBuilder.AppendLine("  - For immutable types the following must hold:")
            .AppendLine("    - Must be a sealed class or a struct.")
            .AppendLine("    - All fields and properties must be readonly.")
            .AppendLine("    - All field and property types must be immutable.")
            .AppendLine("    - All indexers must be readonly.")
            .AppendLine("    - Event fields are ignored.");
            return(errorBuilder);
        }
Пример #33
0
 public CollectionErrors(MemberPath memberPath, TypeErrors typeErrors)
 {
     this.Path = memberPath;
     this.Errors = new[] { typeErrors };
 }
Пример #34
0
 public CollectionErrors(MemberPath memberPath, TypeErrors typeErrors)
 {
     this.Path   = memberPath;
     this.Errors = new[] { typeErrors };
 }
Пример #35
0
        internal static StringBuilder AppendSuggestNotify(this StringBuilder errorBuilder, TypeErrors errors)
        {
            foreach (var error in errors.AllErrors.OfType <TypeErrors>().Where(te => te.HasError <IFixWithNotify>()).Distinct())
            {
                var fixable = error.Errors.OfType <IFixWithNotify>()
                              .First();
                fixable.AppendSuggestFixWithNotify(errorBuilder, error.Type);
            }

            return(errorBuilder);
        }
Пример #36
0
        internal static StringBuilder AppendSuggestExclude(this StringBuilder errorBuilder, TypeErrors errors)
        {
            var types = errors.AllErrors.OfType <TypeErrors>()
                        .Where(e => e.Type != errors.Type)
                        .Select(x => x.Type)
                        .Distinct()
                        .ToArray();

            if (types.Any() || errors.AllErrors.OfType <IExcludableMember>().Any())
            {
                errorBuilder.AppendLine("  - Exclude a combination of the following:");
                foreach (var member in errors.AllErrors.OfType <IExcludableMember>().Select(x => x.Member).Distinct())
                {
                    errorBuilder.AppendSuggestExcludeMember(member);
                }

                foreach (var type in types)
                {
                    if (type == errors.Type)
                    {
                        continue;
                    }

                    errorBuilder.AppendLine($"    - The type {type.PrettyName()}.");
                }
            }

            return(errorBuilder);
        }
        internal static StringBuilder AppendSuggestExclude(this StringBuilder errorBuilder, TypeErrors errors)
        {
            var types = errors.AllErrors.OfType<TypeErrors>()
                              .Where(e => e.Type != errors.Type)
                              .Select(x => x.Type)
                              .Distinct()
                              .ToArray();

            if (types.Any() || errors.AllErrors.OfType<IExcludableMember>().Any())
            {
                errorBuilder.AppendLine("  - Exclude a combination of the following:");
                foreach (var member in errors.AllErrors.OfType<IExcludableMember>().Select(x => x.Member).Distinct())
                {
                    errorBuilder.AppendSuggestExcludeMember(member);
                }

                foreach (var type in types)
                {
                    if (type == errors.Type)
                    {
                        continue;
                    }

                    errorBuilder.AppendLine($"    - The type {type.PrettyName()}.");
                }
            }

            return errorBuilder;
        }
Пример #38
0
 public MemberErrors(MemberPath path, TypeErrors errors)
 {
     this.Path   = path;
     this.Error  = errors;
     this.Errors = errors == null ? EmptyErrors : new[] { errors };
 }