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 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; }
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); }
// 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 static IReadOnlyList <Error> MergeAll(TypeErrors typeErrors, IReadOnlyCollection <Error> errors) { var allErrors = new List <Error> { typeErrors }; Add(errors, allErrors); return(allErrors); }
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)); } }
// 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)); }
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); }
// 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; }
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)); }
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); }
// 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; }
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); }
// 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); }
// 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); }
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; }
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); }
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; }
public MemberErrors(MemberPath path, TypeErrors errors) { this.Path = path; this.Error = errors; this.Errors = errors == null ? EmptyErrors : new[] { errors }; }
// 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); }
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); }
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); }
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 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); }
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); }
public CollectionErrors(MemberPath memberPath, TypeErrors typeErrors) { this.Path = memberPath; this.Errors = new[] { typeErrors }; }
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); }
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; }