From 667a3d5286e96551b753b94f8141f602e45bfe4c Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Sat, 30 Jul 2022 07:19:10 +0300 Subject: [PATCH 01/67] use Enum.Parse --- src/AutoMapper/Mappers/StringToEnumMapper.cs | 31 ++++++++++++-------- src/AutoMapper/Mappers/ToStringMapper.cs | 23 ++------------- src/UnitTests/Enumerations.cs | 7 +++++ 3 files changed, 28 insertions(+), 33 deletions(-) diff --git a/src/AutoMapper/Mappers/StringToEnumMapper.cs b/src/AutoMapper/Mappers/StringToEnumMapper.cs index 6906823e28..f84e0868f8 100644 --- a/src/AutoMapper/Mappers/StringToEnumMapper.cs +++ b/src/AutoMapper/Mappers/StringToEnumMapper.cs @@ -9,29 +9,36 @@ namespace AutoMapper.Internal.Mappers using static Expression; public class StringToEnumMapper : IObjectMapper { - private static readonly MethodInfo EqualsMethod = typeof(StringToEnumMapper).GetMethod("StringCompareOrdinalIgnoreCase"); - private static readonly MethodInfo ParseMethod = typeof(Enum).GetMethod("Parse", new[] { typeof(Type), typeof(string), typeof(bool) }); - private static readonly MethodInfo IsNullOrEmptyMethod = typeof(string).GetMethod("IsNullOrEmpty"); + private static readonly MethodInfo EqualsMethod = typeof(StringToEnumMapper).GetMethod(nameof(StringCompareOrdinalIgnoreCase)); + private static readonly MethodInfo ParseMethod = typeof(Enum).StaticGenericMethod("Parse", parametersCount: 2); + private static readonly PropertyInfo Length = typeof(string).GetProperty("Length"); public bool IsMatch(TypePair context) => context.SourceType == typeof(string) && context.DestinationType.IsEnum; public Expression MapExpression(IGlobalConfiguration configurationProvider, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) { var destinationType = destExpression.Type; + var ignoreCase = True; + var enumParse = Call(ParseMethod.MakeGenericMethod(destinationType), sourceExpression, ignoreCase); + var enumMember = CheckEnumMember(sourceExpression, destinationType, enumParse, EqualsMethod); + return Condition(Equal(Property(sourceExpression, Length), Zero), Default(destinationType), enumMember); + } + internal static Expression CheckEnumMember(Expression sourceExpression, Type enumType, Expression defaultExpression, MethodInfo comparison = null) + { List switchCases = null; - foreach (var memberInfo in destinationType.GetFields(TypeExtensions.StaticFlags)) + foreach (var memberInfo in enumType.GetFields(TypeExtensions.StaticFlags)) { var attributeValue = memberInfo.GetCustomAttribute()?.Value; - if (attributeValue != null) + if (attributeValue == null) { - var switchCase = SwitchCase( - ToType(Constant(Enum.ToObject(destinationType, memberInfo.GetValue(null))), destinationType), Constant(attributeValue)); - switchCases ??= new(); - switchCases.Add(switchCase); + continue; } + var enumToObject = Constant(Enum.ToObject(enumType, memberInfo.GetValue(null))); + var attributeConstant = Constant(attributeValue); + var (body, testValue) = comparison == null ? (attributeConstant, enumToObject) : (ToType(enumToObject, enumType), attributeConstant); + switchCases ??= new(); + switchCases.Add(SwitchCase(body, testValue)); } - var enumParse = ToType(Call(ParseMethod, Constant(destinationType), sourceExpression, True), destinationType); - var parse = switchCases != null ? Switch(sourceExpression, enumParse, EqualsMethod, switchCases) : enumParse; - return Condition(Call(IsNullOrEmptyMethod, sourceExpression), Default(destinationType), parse); + return switchCases == null ? defaultExpression : Switch(sourceExpression, defaultExpression, comparison, switchCases); } public static bool StringCompareOrdinalIgnoreCase(string x, string y) => StringComparer.OrdinalIgnoreCase.Equals(x, y); } diff --git a/src/AutoMapper/Mappers/ToStringMapper.cs b/src/AutoMapper/Mappers/ToStringMapper.cs index dcf65c3977..fc6a297976 100644 --- a/src/AutoMapper/Mappers/ToStringMapper.cs +++ b/src/AutoMapper/Mappers/ToStringMapper.cs @@ -1,9 +1,5 @@ using AutoMapper.Execution; -using System; -using System.Collections.Generic; using System.Linq.Expressions; -using System.Reflection; -using System.Runtime.Serialization; namespace AutoMapper.Internal.Mappers { using static Expression; @@ -13,23 +9,8 @@ public class ToStringMapper : IObjectMapper public Expression MapExpression(IGlobalConfiguration configurationProvider, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) { var sourceType = sourceExpression.Type; - Expression toStringCall = Call(sourceExpression, ExpressionBuilder.ObjectToString); - return sourceType.IsEnum ? EnumToString(sourceExpression, sourceType, toStringCall) : toStringCall; - } - private static Expression EnumToString(Expression sourceExpression, Type sourceType, Expression toStringCall) - { - List switchCases = null; - foreach (var memberInfo in sourceType.GetFields(TypeExtensions.StaticFlags)) - { - var attributeValue = memberInfo.GetCustomAttribute()?.Value; - if (attributeValue != null) - { - var switchCase = SwitchCase(Constant(attributeValue), Constant(Enum.ToObject(sourceType, memberInfo.GetValue(null)))); - switchCases ??= new(); - switchCases.Add(switchCase); - } - } - return switchCases != null ? Switch(sourceExpression, toStringCall, null, switchCases) : toStringCall; + var toStringCall = Call(sourceExpression, ExpressionBuilder.ObjectToString); + return sourceType.IsEnum ? StringToEnumMapper.CheckEnumMember(sourceExpression, sourceType, toStringCall) : toStringCall; } } } \ No newline at end of file diff --git a/src/UnitTests/Enumerations.cs b/src/UnitTests/Enumerations.cs index c3cf932315..15b982f5d5 100644 --- a/src/UnitTests/Enumerations.cs +++ b/src/UnitTests/Enumerations.cs @@ -6,6 +6,13 @@ namespace AutoMapper.Tests { + public class InvalidStringToEnum : AutoMapperSpecBase + { + protected override MapperConfiguration CreateConfiguration() => new(_=> { }); + [Fact] + public void Should_throw() => new Action(()=>Map("d")).ShouldThrow().InnerException.Message.ShouldBe( + "Requested value 'd' was not found."); + } public class DefaultEnumValueToString : AutoMapperSpecBase { Destination _destination; From 77086e8a5a9c55908260c7cd0e865e829e0a81e4 Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Sun, 31 Jul 2022 09:57:39 +0300 Subject: [PATCH 02/67] less allocations --- src/AutoMapper/Execution/ExpressionBuilder.cs | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/AutoMapper/Execution/ExpressionBuilder.cs b/src/AutoMapper/Execution/ExpressionBuilder.cs index e5a91285ff..e9a14e892d 100644 --- a/src/AutoMapper/Execution/ExpressionBuilder.cs +++ b/src/AutoMapper/Execution/ExpressionBuilder.cs @@ -6,6 +6,7 @@ using System.Reflection; using System.ComponentModel; using System.Runtime.CompilerServices; +using System.Collections.ObjectModel; namespace AutoMapper.Execution { using Internal; @@ -352,15 +353,21 @@ Expression NullCheck(ParameterExpression variable) var assignment = Assign(newVariable, UpdateTarget(member.Expression, variable)); return variable.IfNullElse(defaultReturn, Block(assignment, NullCheck(newVariable))); } - static Expression UpdateTarget(Expression sourceExpression, Expression newTarget) => - sourceExpression switch - { - MemberExpression memberExpression => memberExpression.Update(newTarget), - MethodCallExpression { Method.IsStatic: true, Arguments: var args } methodCall when args[0] != newTarget => - methodCall.Update(null, args.Skip(1).Prepend(newTarget)), - MethodCallExpression { Method.IsStatic: false } methodCall => methodCall.Update(newTarget, methodCall.Arguments), - _ => sourceExpression, - }; + static Expression UpdateTarget(Expression sourceExpression, Expression newTarget) => sourceExpression switch + { + MemberExpression memberExpression => memberExpression.Update(newTarget), + MethodCallExpression { Object: null, Arguments: var args } methodCall when args[0] != newTarget => + ExtensionMethod(methodCall.Method, newTarget, args), + MethodCallExpression { Object: Expression target } methodCall when target != newTarget => + Expression.Call(newTarget, methodCall.Method, methodCall.Arguments), + _ => sourceExpression, + }; + static MethodCallExpression ExtensionMethod(MethodInfo method, Expression newTarget, ReadOnlyCollection args) + { + var newArgs = args.ToArray(); + newArgs[0] = newTarget; + return Expression.Call(method, newArgs); + } } public static Expression IfNullElse(this Expression expression, Expression then, Expression @else) => expression.Type.IsValueType ? (expression.Type.IsNullableType() ? Condition(Property(expression, "HasValue"), ToType(@else, then.Type), then) : @else) : From e3aecd30a24c09b0549553a7f32a7db608214c3f Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Mon, 1 Aug 2022 13:44:51 +0300 Subject: [PATCH 03/67] reuse the execution plan between user Map calls and internal Map calls --- .../Configuration/MapperConfiguration.cs | 6 +++--- src/AutoMapper/Execution/ExpressionBuilder.cs | 18 ++++------------ .../Execution/TypeMapPlanBuilder.cs | 5 ++--- src/AutoMapper/Internal/TypePair.cs | 6 +++--- src/AutoMapper/Mapper.cs | 1 + src/AutoMapper/Mappers/CollectionMapper.cs | 21 +------------------ src/AutoMapper/MemberMap.cs | 12 +++-------- 7 files changed, 17 insertions(+), 52 deletions(-) diff --git a/src/AutoMapper/Configuration/MapperConfiguration.cs b/src/AutoMapper/Configuration/MapperConfiguration.cs index d378775cc4..96624fe37a 100644 --- a/src/AutoMapper/Configuration/MapperConfiguration.cs +++ b/src/AutoMapper/Configuration/MapperConfiguration.cs @@ -173,7 +173,7 @@ public MapperConfiguration(Action configure) public IMapper CreateMapper(Func serviceCtor) => new Mapper(this, serviceCtor); public void CompileMappings() { - foreach (var request in _resolvedMaps.Keys.Where(t => !t.IsGenericTypeDefinition).Select(types => new MapRequest(types, types)).ToArray()) + foreach (var request in _resolvedMaps.Keys.Where(t => !t.IsGenericTypeDefinition).Select(types => new MapRequest(types, types, MemberMap.Instance)).ToArray()) { GetExecutionPlan(request); } @@ -181,7 +181,7 @@ public void CompileMappings() public LambdaExpression BuildExecutionPlan(Type sourceType, Type destinationType) { var typePair = new TypePair(sourceType, destinationType); - return this.Internal().BuildExecutionPlan(new(typePair, typePair)); + return this.Internal().BuildExecutionPlan(new(typePair, typePair, MemberMap.Instance)); } LambdaExpression IGlobalConfiguration.BuildExecutionPlan(in MapRequest mapRequest) { @@ -237,7 +237,7 @@ LambdaExpression GenerateObjectMapperExpression(in MapRequest mapRequest, IObjec var throwExpression = Throw(newException, runtimeDestinationType); fullExpression = TryCatch(ToType(map, runtimeDestinationType), Catch(ExceptionParameter, throwExpression)); } - var profileMap = mapRequest.MemberMap?.Profile ?? Configuration; + var profileMap = mapRequest.MemberMap.Profile ?? Configuration; var nullCheckSource = NullCheckSource(profileMap, source, destination, fullExpression, mapRequest.MemberMap); return Lambda(nullCheckSource, source, destination, ContextParameter); } diff --git a/src/AutoMapper/Execution/ExpressionBuilder.cs b/src/AutoMapper/Execution/ExpressionBuilder.cs index e9a14e892d..681105b3df 100644 --- a/src/AutoMapper/Execution/ExpressionBuilder.cs +++ b/src/AutoMapper/Execution/ExpressionBuilder.cs @@ -31,7 +31,7 @@ public static class ExpressionBuilder public static readonly MethodInfo OverTypeDepthMethod = typeof(ResolutionContext).GetInstanceMethod(nameof(ResolutionContext.OverTypeDepth)); public static readonly MethodInfo CacheDestinationMethod = typeof(ResolutionContext).GetInstanceMethod(nameof(ResolutionContext.CacheDestination)); public static readonly MethodInfo GetDestinationMethod = typeof(ResolutionContext).GetInstanceMethod(nameof(ResolutionContext.GetDestination)); - private static readonly MethodCallExpression CheckContextCall = Expression.Call( + public static readonly MethodCallExpression CheckContextCall = Expression.Call( typeof(ResolutionContext).GetStaticMethod(nameof(ResolutionContext.CheckContext)), ContextParameter); private static readonly MethodInfo ContextMapMethod = typeof(ResolutionContext).GetInstanceMethod(nameof(ResolutionContext.MapInternal)); private static readonly MethodInfo ArrayEmptyMethod = typeof(Array).GetStaticMethod(nameof(Array.Empty)); @@ -81,9 +81,7 @@ public static Expression NullCheckSource(ProfileMap profileMap, Expression sourc var destinationType = destinationParameter.Type; var isCollection = destinationType.IsCollection(); var mustUseDestination = memberMap is { MustUseDestination: true }; - var ifSourceNull = memberMap == null ? - destinationParameter.IfNullElse(DefaultDestination(), ClearDestinationCollection()) : - mustUseDestination ? ClearDestinationCollection() : DefaultDestination(); + var ifSourceNull = mustUseDestination ? ClearDestinationCollection() : DefaultDestination(); return sourceParameter.IfNullElse(ifSourceNull, mapExpression); Expression ClearDestinationCollection() { @@ -109,13 +107,13 @@ Expression ClearDestinationCollection() } var destinationElementType = GetEnumerableElementType(destinationType); destinationCollectionType = typeof(ICollection<>).MakeGenericType(destinationElementType); - collection = Convert(collection, destinationCollectionType); + collection = TypeAs(collection, destinationCollectionType); } clearMethod = destinationCollectionType.GetMethod("Clear"); } return Block(new[] { destinationVariable }, Assign(destinationVariable, destinationParameter), - Condition(ReferenceEqual(destinationVariable, Null), Empty, Expression.Call(collection, clearMethod)), + Condition(ReferenceEqual(collection, Null), Empty, Expression.Call(collection, clearMethod)), destinationVariable); } Expression DefaultDestination() @@ -141,14 +139,6 @@ public static Expression ContextMap(TypePair typePair, Expression sourceParamete var mapMethod = ContextMapMethod.MakeGenericMethod(typePair.SourceType, typePair.DestinationType); return Expression.Call(ContextParameter, mapMethod, sourceParameter, destinationParameter, Constant(memberMap, typeof(MemberMap))); } - public static Expression CheckContext(TypeMap typeMap) - { - if (typeMap.MaxDepth > 0 || typeMap.PreserveReferences) - { - return CheckContextCall; - } - return null; - } public static Expression OverMaxDepth(TypeMap typeMap) => typeMap?.MaxDepth > 0 ? Expression.Call(ContextParameter, OverTypeDepthMethod, Constant(typeMap)) : null; public static Expression NullSubstitute(this MemberMap memberMap, Expression sourceExpression) => Coalesce(sourceExpression, ToType(Constant(memberMap.NullSubstitute), sourceExpression.Type)); diff --git a/src/AutoMapper/Execution/TypeMapPlanBuilder.cs b/src/AutoMapper/Execution/TypeMapPlanBuilder.cs index c2efa3a7c0..e57a51ab44 100644 --- a/src/AutoMapper/Execution/TypeMapPlanBuilder.cs +++ b/src/AutoMapper/Execution/TypeMapPlanBuilder.cs @@ -54,10 +54,9 @@ public LambdaExpression CreateMapperLambda(HashSet typeMapsPath) var createDestinationFunc = CreateDestinationFunc(); var assignmentFunc = CreateAssignmentFunc(createDestinationFunc); var mapperFunc = CreateMapperFunc(assignmentFunc); - var checkContext = CheckContext(_typeMap); - if (checkContext != null) + if (_typeMap.MaxDepth > 0 || _typeMap.PreserveReferences) { - statements.Add(checkContext); + statements.Add(CheckContextCall); } statements.Add(mapperFunc); variables.Add(_destination); diff --git a/src/AutoMapper/Internal/TypePair.cs b/src/AutoMapper/Internal/TypePair.cs index 75ad184cc9..50f9b4c331 100644 --- a/src/AutoMapper/Internal/TypePair.cs +++ b/src/AutoMapper/Internal/TypePair.cs @@ -8,16 +8,16 @@ namespace AutoMapper.Internal public readonly TypePair RequestedTypes; public readonly TypePair RuntimeTypes; public readonly MemberMap MemberMap; - public MapRequest(TypePair requestedTypes, TypePair runtimeTypes, MemberMap memberMap = null) + public MapRequest(TypePair requestedTypes, TypePair runtimeTypes, MemberMap memberMap) { RequestedTypes = requestedTypes; RuntimeTypes = runtimeTypes; MemberMap = memberMap; } public bool Equals(MapRequest other) => RequestedTypes.Equals(other.RequestedTypes) && RuntimeTypes.Equals(other.RuntimeTypes) && - (MemberMap == other.MemberMap || (MemberMap?.MapperEquals(other.MemberMap)).GetValueOrDefault()); + (MemberMap == other.MemberMap || MemberMap.MapperEquals(other.MemberMap)); public override bool Equals(object obj) => obj is MapRequest other && Equals(other); - public override int GetHashCode() => HashCode.Combine(RequestedTypes, RuntimeTypes, MemberMap?.MapperGetHashCode()); + public override int GetHashCode() => HashCode.Combine(RequestedTypes, RuntimeTypes, MemberMap.MapperGetHashCode()); public static bool operator ==(in MapRequest left, in MapRequest right) => left.Equals(right); public static bool operator !=(in MapRequest left, in MapRequest right) => !left.Equals(right); } diff --git a/src/AutoMapper/Mapper.cs b/src/AutoMapper/Mapper.cs index 928fa747a5..9c272a2fb9 100644 --- a/src/AutoMapper/Mapper.cs +++ b/src/AutoMapper/Mapper.cs @@ -198,6 +198,7 @@ private TDestination MapCore( { TypePair requestedTypes = new(typeof(TSource), typeof(TDestination)); TypePair runtimeTypes = new(source?.GetType() ?? sourceType ?? typeof(TSource), destination?.GetType() ?? destinationType ?? typeof(TDestination)); + memberMap ??= destination == null ? MemberMap.Instance : MemberMap.InstanceUseDestination; MapRequest mapRequest = new(requestedTypes, runtimeTypes, memberMap); return _configurationProvider.GetExecutionPlan(mapRequest)(source, destination, context); } diff --git a/src/AutoMapper/Mappers/CollectionMapper.cs b/src/AutoMapper/Mappers/CollectionMapper.cs index 7785af7f72..d9b4d4f8f4 100644 --- a/src/AutoMapper/Mappers/CollectionMapper.cs +++ b/src/AutoMapper/Mappers/CollectionMapper.cs @@ -74,17 +74,12 @@ Expression MapCollectionCore(Expression destExpression) addItems = Condition(overMaxDepth, ExpressionBuilder.Empty, addItems); } var clearMethod = isIList ? IListClear : destinationCollectionType.GetMethod("Clear"); - var checkNull = Block(new[] { newExpression, passedDestination }, + return Block(new[] { newExpression, passedDestination }, Assign(passedDestination, destExpression), assignNewExpression, Call(destination, clearMethod), addItems, destination); - if (memberMap != null) - { - return checkNull; - } - return CheckContext(); void GetDestinationType() { var immutableCollection = !mustUseDestination && destinationType.IsValueType; @@ -133,20 +128,6 @@ void UseDestinationValue() assignNewExpression = Assign(newExpression, Coalesce(passedDestination, ObjectFactory.GenerateConstructorExpression(passedDestination.Type))); } } - Expression CheckContext() - { - var elementTypeMap = configurationProvider.ResolveTypeMap(sourceElementType, destinationElementType); - if (elementTypeMap == null) - { - return checkNull; - } - var checkContext = ExpressionBuilder.CheckContext(elementTypeMap); - if (checkContext == null) - { - return checkNull; - } - return Block(checkContext, checkNull); - } } } private static Expression CreateNameValueCollection(Expression sourceExpression) => diff --git a/src/AutoMapper/MemberMap.cs b/src/AutoMapper/MemberMap.cs index 8f72466629..6b2f17d87d 100644 --- a/src/AutoMapper/MemberMap.cs +++ b/src/AutoMapper/MemberMap.cs @@ -18,7 +18,8 @@ public class MemberMap : IValueResolver { private static readonly LambdaExpression EmptyLambda = Lambda(ExpressionBuilder.Null); protected MemberMap(TypeMap typeMap = null) => TypeMap = typeMap; - public static readonly MemberMap Instance = new(); + internal static readonly MemberMap Instance = new(); + internal static readonly MemberMap InstanceUseDestination = new PropertyMap(default(MemberInfo), null, null) { UseDestinationValue = true }; public TypeMap TypeMap { get; protected set; } public LambdaExpression CustomMapExpression => Resolver?.ProjectToExpression; public bool IsResolveConfigured => Resolver != null && Resolver != this; @@ -64,15 +65,8 @@ public Expression ChainSourceMembers(Expression source, Type destinationType, Ex public bool AllowsNullCollections => (Profile?.AllowsNullCollectionsFor(this)).GetValueOrDefault(); public ProfileMap Profile => TypeMap?.Profile; private int MaxDepth => (TypeMap?.MaxDepth).GetValueOrDefault(); - public bool MapperEquals(MemberMap other) - { - if (other == null) - { - return false; - } - return other.MustUseDestination == MustUseDestination && other.MaxDepth == MaxDepth && + public bool MapperEquals(MemberMap other) => other.MustUseDestination == MustUseDestination && other.MaxDepth == MaxDepth && other.AllowsNullDestinationValues == AllowsNullDestinationValues && other.AllowsNullCollections == AllowsNullCollections; - } public int MapperGetHashCode() => HashCode.Combine(MustUseDestination, MaxDepth, AllowsNullDestinationValues, AllowsNullCollections); protected Type GetSourceType() => Resolver?.ResolvedType ?? DestinationType; public void MapByConvention(MemberInfo[] sourceMembers) From 6581906a10c48c99d51237befa96e63f37cbb4c5 Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Tue, 2 Aug 2022 10:19:41 +0300 Subject: [PATCH 04/67] remove IObjectMapperInfo --- src/AutoMapper/ApiCompatBaseline.txt | 10 +++++++++- src/AutoMapper/Configuration/ConfigurationValidator.cs | 8 ++------ src/AutoMapper/Configuration/MapperConfiguration.cs | 4 ++-- src/AutoMapper/Mappers/CollectionMapper.cs | 4 ++-- src/AutoMapper/Mappers/IObjectMapper.cs | 6 +----- src/AutoMapper/Mappers/NullableDestinationMapper.cs | 4 ++-- src/AutoMapper/Mappers/NullableSourceMapper.cs | 4 ++-- 7 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/AutoMapper/ApiCompatBaseline.txt b/src/AutoMapper/ApiCompatBaseline.txt index 203ce3e707..c6ed379f03 100644 --- a/src/AutoMapper/ApiCompatBaseline.txt +++ b/src/AutoMapper/ApiCompatBaseline.txt @@ -14,7 +14,15 @@ CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'AutoMappe CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'AutoMapper.Configuration.Annotations.UseExistingValueAttribute' changed from '[AttributeUsageAttribute(384)]' in the contract to '[AttributeUsageAttribute(AttributeTargets.Field | AttributeTargets.Property)]' in the implementation. CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'AutoMapper.Configuration.Annotations.ValueConverterAttribute' changed from '[AttributeUsageAttribute(384)]' in the contract to '[AttributeUsageAttribute(AttributeTargets.Field | AttributeTargets.Property)]' in the implementation. CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'AutoMapper.Configuration.Annotations.ValueResolverAttribute' changed from '[AttributeUsageAttribute(384)]' in the contract to '[AttributeUsageAttribute(AttributeTargets.Field | AttributeTargets.Property)]' in the implementation. +CannotRemoveBaseTypeOrInterface : Type 'AutoMapper.Internal.Mappers.CollectionMapper' does not implement interface 'AutoMapper.Internal.Mappers.IObjectMapperInfo' in the implementation but it does in the contract. +MembersMustExist : Member 'public AutoMapper.Internal.TypePair AutoMapper.Internal.Mappers.CollectionMapper.GetAssociatedTypes(AutoMapper.Internal.TypePair)' does not exist in the implementation but it does exist in the contract. +InterfacesShouldHaveSameMembers : Default interface member 'public System.Nullable AutoMapper.Internal.Mappers.IObjectMapper.GetAssociatedTypes(AutoMapper.Internal.TypePair)' is present in the implementation but not in the contract. +TypesMustExist : Type 'AutoMapper.Internal.Mappers.IObjectMapperInfo' does not exist in the implementation but it does exist in the contract. +CannotRemoveBaseTypeOrInterface : Type 'AutoMapper.Internal.Mappers.NullableDestinationMapper' does not implement interface 'AutoMapper.Internal.Mappers.IObjectMapperInfo' in the implementation but it does in the contract. +MembersMustExist : Member 'public AutoMapper.Internal.TypePair AutoMapper.Internal.Mappers.NullableDestinationMapper.GetAssociatedTypes(AutoMapper.Internal.TypePair)' does not exist in the implementation but it does exist in the contract. +CannotRemoveBaseTypeOrInterface : Type 'AutoMapper.Internal.Mappers.NullableSourceMapper' does not implement interface 'AutoMapper.Internal.Mappers.IObjectMapperInfo' in the implementation but it does in the contract. +MembersMustExist : Member 'public AutoMapper.Internal.TypePair AutoMapper.Internal.Mappers.NullableSourceMapper.GetAssociatedTypes(AutoMapper.Internal.TypePair)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Linq.IQueryable AutoMapper.QueryableExtensions.Extensions.Map(System.Linq.IQueryable, System.Linq.IQueryable, AutoMapper.IConfigurationProvider)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Collections.Generic.IReadOnlyCollection AutoMapper.QueryableExtensions.MemberVisitor.MemberPath.get()' does not exist in the implementation but it does exist in the contract. TypesMustExist : Type 'AutoMapper.QueryableExtensions.Impl.MemberAccessQueryMapperVisitor' does not exist in the implementation but it does exist in the contract. -Total Issues: 18 +Total Issues: 26 diff --git a/src/AutoMapper/Configuration/ConfigurationValidator.cs b/src/AutoMapper/Configuration/ConfigurationValidator.cs index cf889c3d2c..ad94439bec 100644 --- a/src/AutoMapper/Configuration/ConfigurationValidator.cs +++ b/src/AutoMapper/Configuration/ConfigurationValidator.cs @@ -127,13 +127,9 @@ private void DryRunTypeMap(ICollection typeMapsChecked, TypePair types, } var context = new ValidationContext(types, memberMap, mapperToUse); Validate(context); - if(mapperToUse is IObjectMapperInfo mapperInfo) + if (mapperToUse.GetAssociatedTypes(types) is TypePair newTypes && newTypes != types) { - var newTypePair = mapperInfo.GetAssociatedTypes(types); - if (newTypePair != types) - { - DryRunTypeMap(typeMapsChecked, newTypePair, null, memberMap); - } + DryRunTypeMap(typeMapsChecked, newTypes, null, memberMap); } } } diff --git a/src/AutoMapper/Configuration/MapperConfiguration.cs b/src/AutoMapper/Configuration/MapperConfiguration.cs index 96624fe37a..bf0df5d15f 100644 --- a/src/AutoMapper/Configuration/MapperConfiguration.cs +++ b/src/AutoMapper/Configuration/MapperConfiguration.cs @@ -267,9 +267,9 @@ TypeMap IGlobalConfiguration.ResolveAssociatedTypeMap(TypePair types) { return typeMap; } - if (FindMapper(types) is IObjectMapperInfo objectMapperInfo) + if (FindMapper(types)?.GetAssociatedTypes(types) is TypePair newTypes) { - return ResolveTypeMap(objectMapperInfo.GetAssociatedTypes(types)); + return ResolveTypeMap(newTypes); } return null; } diff --git a/src/AutoMapper/Mappers/CollectionMapper.cs b/src/AutoMapper/Mappers/CollectionMapper.cs index d9b4d4f8f4..9ee2d05b24 100644 --- a/src/AutoMapper/Mappers/CollectionMapper.cs +++ b/src/AutoMapper/Mappers/CollectionMapper.cs @@ -12,9 +12,9 @@ namespace AutoMapper.Internal.Mappers using static Execution.ExpressionBuilder; using static Expression; using static ReflectionHelper; - public class CollectionMapper : IObjectMapperInfo + public class CollectionMapper : IObjectMapper { - public TypePair GetAssociatedTypes(TypePair context) => new(GetElementType(context.SourceType), GetElementType(context.DestinationType)); + public TypePair? GetAssociatedTypes(TypePair context) => new(GetElementType(context.SourceType), GetElementType(context.DestinationType)); public bool IsMatch(TypePair context) => context.IsCollection(); public Expression MapExpression(IGlobalConfiguration configurationProvider, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) { diff --git a/src/AutoMapper/Mappers/IObjectMapper.cs b/src/AutoMapper/Mappers/IObjectMapper.cs index 1d6a06b590..0063d0de1a 100644 --- a/src/AutoMapper/Mappers/IObjectMapper.cs +++ b/src/AutoMapper/Mappers/IObjectMapper.cs @@ -29,12 +29,8 @@ public interface IObjectMapper /// Map expression Expression MapExpression(IGlobalConfiguration configurationProvider, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression); + TypePair? GetAssociatedTypes(TypePair initialTypes) => null; } - public interface IObjectMapperInfo : IObjectMapper - { - TypePair GetAssociatedTypes(TypePair initialTypes); - } - /// /// Base class for simple object mappers that don't want to use expressions. /// diff --git a/src/AutoMapper/Mappers/NullableDestinationMapper.cs b/src/AutoMapper/Mappers/NullableDestinationMapper.cs index 63e682d4e9..28749d0aeb 100644 --- a/src/AutoMapper/Mappers/NullableDestinationMapper.cs +++ b/src/AutoMapper/Mappers/NullableDestinationMapper.cs @@ -3,12 +3,12 @@ using AutoMapper.Execution; namespace AutoMapper.Internal.Mappers { - public class NullableDestinationMapper : IObjectMapperInfo + public class NullableDestinationMapper : IObjectMapper { public bool IsMatch(TypePair context) => context.DestinationType.IsNullableType(); public Expression MapExpression(IGlobalConfiguration configurationProvider, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) => configurationProvider.MapExpression(profileMap, GetAssociatedTypes(sourceExpression.Type, destExpression.Type), sourceExpression, memberMap); - public TypePair GetAssociatedTypes(TypePair initialTypes) => GetAssociatedTypes(initialTypes.SourceType, initialTypes.DestinationType); + public TypePair? GetAssociatedTypes(TypePair initialTypes) => GetAssociatedTypes(initialTypes.SourceType, initialTypes.DestinationType); TypePair GetAssociatedTypes(Type sourceType, Type destinationType) => new(sourceType, Nullable.GetUnderlyingType(destinationType)); } } \ No newline at end of file diff --git a/src/AutoMapper/Mappers/NullableSourceMapper.cs b/src/AutoMapper/Mappers/NullableSourceMapper.cs index 2d78a9da5c..82558915b1 100644 --- a/src/AutoMapper/Mappers/NullableSourceMapper.cs +++ b/src/AutoMapper/Mappers/NullableSourceMapper.cs @@ -3,13 +3,13 @@ using AutoMapper.Execution; namespace AutoMapper.Internal.Mappers { - public class NullableSourceMapper : IObjectMapperInfo + public class NullableSourceMapper : IObjectMapper { public bool IsMatch(TypePair context) => context.SourceType.IsNullableType(); public Expression MapExpression(IGlobalConfiguration configurationProvider, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) => configurationProvider.MapExpression(profileMap, GetAssociatedTypes(sourceExpression.Type, destExpression.Type), ExpressionBuilder.Property(sourceExpression, "Value"), memberMap, destExpression); - public TypePair GetAssociatedTypes(TypePair initialTypes) => GetAssociatedTypes(initialTypes.SourceType, initialTypes.DestinationType); + public TypePair? GetAssociatedTypes(TypePair initialTypes) => GetAssociatedTypes(initialTypes.SourceType, initialTypes.DestinationType); TypePair GetAssociatedTypes(Type sourceType, Type destinationType) => new(Nullable.GetUnderlyingType(sourceType), destinationType); } } \ No newline at end of file From 5f0cebd97f9f2d55cdc1f330a2efffe53351b40b Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Wed, 3 Aug 2022 11:17:55 +0300 Subject: [PATCH 05/67] use the more efficient Expression.Invoke instead of ConvertReplaceParameters --- .../Configuration/MapperConfiguration.cs | 10 ++----- src/AutoMapper/Execution/ExpressionBuilder.cs | 27 +++++++++++++------ .../Execution/TypeMapPlanBuilder.cs | 5 ++-- src/AutoMapper/Mappers/CollectionMapper.cs | 17 +++++++++++- src/AutoMapper/TypeMap.cs | 2 ++ 5 files changed, 42 insertions(+), 19 deletions(-) diff --git a/src/AutoMapper/Configuration/MapperConfiguration.cs b/src/AutoMapper/Configuration/MapperConfiguration.cs index bf0df5d15f..efe5ceb799 100644 --- a/src/AutoMapper/Configuration/MapperConfiguration.cs +++ b/src/AutoMapper/Configuration/MapperConfiguration.cs @@ -199,17 +199,11 @@ static LambdaExpression GenerateTypeMapExpression(TypePair requestedTypes, TypeM { return typeMap.MapExpression; } - var mapDestinationType = typeMap.DestinationType; var requestedDestinationType = requestedTypes.DestinationType; var source = Parameter(requestedTypes.SourceType, "source"); var destination = Parameter(requestedDestinationType, "typeMapDestination"); - var checkNullValueTypeDest = CheckNullValueType(destination, mapDestinationType); - return - Lambda( - ToType( - Invoke(typeMap.MapExpression, ToType(source, typeMap.SourceType), ToType(checkNullValueTypeDest, mapDestinationType), ContextParameter), - requestedDestinationType), - source, destination, ContextParameter); + var checkNullValueTypeDest = CheckNullValueType(destination, typeMap.DestinationType); + return Lambda(ToType(typeMap.Invoke(source, checkNullValueTypeDest), requestedDestinationType), source, destination, ContextParameter); } static Expression CheckNullValueType(Expression expression, Type runtimeType) => !expression.Type.IsValueType && runtimeType.IsValueType ? Coalesce(expression, Default(runtimeType)) : expression; diff --git a/src/AutoMapper/Execution/ExpressionBuilder.cs b/src/AutoMapper/Execution/ExpressionBuilder.cs index 681105b3df..4714519fed 100644 --- a/src/AutoMapper/Execution/ExpressionBuilder.cs +++ b/src/AutoMapper/Execution/ExpressionBuilder.cs @@ -31,7 +31,7 @@ public static class ExpressionBuilder public static readonly MethodInfo OverTypeDepthMethod = typeof(ResolutionContext).GetInstanceMethod(nameof(ResolutionContext.OverTypeDepth)); public static readonly MethodInfo CacheDestinationMethod = typeof(ResolutionContext).GetInstanceMethod(nameof(ResolutionContext.CacheDestination)); public static readonly MethodInfo GetDestinationMethod = typeof(ResolutionContext).GetInstanceMethod(nameof(ResolutionContext.GetDestination)); - public static readonly MethodCallExpression CheckContextCall = Expression.Call( + private static readonly MethodCallExpression CheckContextCall = Expression.Call( typeof(ResolutionContext).GetStaticMethod(nameof(ResolutionContext.CheckContext)), ContextParameter); private static readonly MethodInfo ContextMapMethod = typeof(ResolutionContext).GetInstanceMethod(nameof(ResolutionContext.MapInternal)); private static readonly MethodInfo ArrayEmptyMethod = typeof(Array).GetStaticMethod(nameof(Array.Empty)); @@ -42,10 +42,10 @@ public static class ExpressionBuilder private static readonly BinaryExpression ResetIndex = Assign(Index, Zero); private static readonly UnaryExpression IncrementIndex = PostIncrementAssign(Index); - public static Expression MapExpression(this IGlobalConfiguration configurationProvider, ProfileMap profileMap, TypePair typePair, Expression sourceParameter, - MemberMap propertyMap = null, Expression destinationParameter = null) + public static Expression MapExpression(this IGlobalConfiguration configurationProvider, ProfileMap profileMap, TypePair typePair, Expression source, + MemberMap propertyMap = null, Expression destination = null) { - destinationParameter ??= Default(typePair.DestinationType); + destination ??= Default(typePair.DestinationType); var typeMap = configurationProvider.ResolveTypeMap(typePair); Expression mapExpression = null; bool hasTypeConverter; @@ -55,19 +55,22 @@ public static Expression MapExpression(this IGlobalConfiguration configurationPr if (!typeMap.HasDerivedTypesToInclude) { configurationProvider.Seal(typeMap); - mapExpression = typeMap.MapExpression?.ConvertReplaceParameters(sourceParameter, destinationParameter); + if (typeMap.MapExpression != null) + { + mapExpression = typeMap.Invoke(source, destination); + } } } else { hasTypeConverter = false; var mapper = configurationProvider.FindMapper(typePair); - mapExpression = mapper?.MapExpression(configurationProvider, profileMap, propertyMap, sourceParameter, destinationParameter); + mapExpression = mapper?.MapExpression(configurationProvider, profileMap, propertyMap, source, destination); } - mapExpression ??= ContextMap(typePair, sourceParameter, destinationParameter, propertyMap); + mapExpression ??= ContextMap(typePair, source, destination, propertyMap); if (!hasTypeConverter) { - mapExpression = NullCheckSource(profileMap, sourceParameter, destinationParameter, mapExpression, propertyMap); + mapExpression = NullCheckSource(profileMap, source, destination, mapExpression, propertyMap); } return ToType(mapExpression, typePair.DestinationType); } @@ -139,6 +142,14 @@ public static Expression ContextMap(TypePair typePair, Expression sourceParamete var mapMethod = ContextMapMethod.MakeGenericMethod(typePair.SourceType, typePair.DestinationType); return Expression.Call(ContextParameter, mapMethod, sourceParameter, destinationParameter, Constant(memberMap, typeof(MemberMap))); } + public static Expression CheckContext(TypeMap typeMap) + { + if (typeMap.MaxDepth > 0 || typeMap.PreserveReferences) + { + return CheckContextCall; + } + return null; + } public static Expression OverMaxDepth(TypeMap typeMap) => typeMap?.MaxDepth > 0 ? Expression.Call(ContextParameter, OverTypeDepthMethod, Constant(typeMap)) : null; public static Expression NullSubstitute(this MemberMap memberMap, Expression sourceExpression) => Coalesce(sourceExpression, ToType(Constant(memberMap.NullSubstitute), sourceExpression.Type)); diff --git a/src/AutoMapper/Execution/TypeMapPlanBuilder.cs b/src/AutoMapper/Execution/TypeMapPlanBuilder.cs index e57a51ab44..c2efa3a7c0 100644 --- a/src/AutoMapper/Execution/TypeMapPlanBuilder.cs +++ b/src/AutoMapper/Execution/TypeMapPlanBuilder.cs @@ -54,9 +54,10 @@ public LambdaExpression CreateMapperLambda(HashSet typeMapsPath) var createDestinationFunc = CreateDestinationFunc(); var assignmentFunc = CreateAssignmentFunc(createDestinationFunc); var mapperFunc = CreateMapperFunc(assignmentFunc); - if (_typeMap.MaxDepth > 0 || _typeMap.PreserveReferences) + var checkContext = CheckContext(_typeMap); + if (checkContext != null) { - statements.Add(CheckContextCall); + statements.Add(checkContext); } statements.Add(mapperFunc); variables.Add(_destination); diff --git a/src/AutoMapper/Mappers/CollectionMapper.cs b/src/AutoMapper/Mappers/CollectionMapper.cs index 9ee2d05b24..2d2652825b 100644 --- a/src/AutoMapper/Mappers/CollectionMapper.cs +++ b/src/AutoMapper/Mappers/CollectionMapper.cs @@ -74,12 +74,13 @@ Expression MapCollectionCore(Expression destExpression) addItems = Condition(overMaxDepth, ExpressionBuilder.Empty, addItems); } var clearMethod = isIList ? IListClear : destinationCollectionType.GetMethod("Clear"); - return Block(new[] { newExpression, passedDestination }, + var checkNull = Block(new[] { newExpression, passedDestination }, Assign(passedDestination, destExpression), assignNewExpression, Call(destination, clearMethod), addItems, destination); + return CheckContext(); void GetDestinationType() { var immutableCollection = !mustUseDestination && destinationType.IsValueType; @@ -128,6 +129,20 @@ void UseDestinationValue() assignNewExpression = Assign(newExpression, Coalesce(passedDestination, ObjectFactory.GenerateConstructorExpression(passedDestination.Type))); } } + Expression CheckContext() + { + var elementTypeMap = configurationProvider.ResolveTypeMap(sourceElementType, destinationElementType); + if (elementTypeMap == null) + { + return checkNull; + } + var checkContext = ExpressionBuilder.CheckContext(elementTypeMap); + if (checkContext == null) + { + return checkNull; + } + return Block(checkContext, checkNull); + } } } private static Expression CreateNameValueCollection(Expression sourceExpression) => diff --git a/src/AutoMapper/TypeMap.cs b/src/AutoMapper/TypeMap.cs index 5fecf159e2..3c11751072 100644 --- a/src/AutoMapper/TypeMap.cs +++ b/src/AutoMapper/TypeMap.cs @@ -61,6 +61,8 @@ public static Exception MissingMapException(Type sourceType, Type destinationTyp => new InvalidOperationException($"Missing map from {sourceType} to {destinationType}. Create using CreateMap<{sourceType.Name}, {destinationType.Name}>."); public bool Projection { get; set; } public LambdaExpression MapExpression { get; private set; } + public Expression Invoke(Expression source, Expression destination) => + Expression.Invoke(MapExpression, ToType(source, SourceType), ToType(destination, DestinationType), ContextParameter); internal bool CanConstructorMap() => Profile.ConstructorMappingEnabled && !DestinationType.IsAbstract && !CustomConstruction && !HasTypeConverter && DestinationConstructors.Length > 0; public TypePair Types; From 9fc7cdf159e8e49e35d0e015e4afc629fd0372a9 Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Wed, 3 Aug 2022 12:38:17 +0300 Subject: [PATCH 06/67] less allocations --- .../Configuration/INamingConvention.cs | 21 +++++++++++++------ src/AutoMapper/TypeMap.cs | 1 - src/Benchmark/Program.cs | 13 ++++++++---- 3 files changed, 24 insertions(+), 11 deletions(-) diff --git a/src/AutoMapper/Configuration/INamingConvention.cs b/src/AutoMapper/Configuration/INamingConvention.cs index 9b3fdd4154..9d297c2d04 100644 --- a/src/AutoMapper/Configuration/INamingConvention.cs +++ b/src/AutoMapper/Configuration/INamingConvention.cs @@ -1,3 +1,4 @@ +using System; using System.Text.RegularExpressions; namespace AutoMapper { @@ -15,23 +16,31 @@ public interface INamingConvention } public class ExactMatchNamingConvention : INamingConvention { - public static readonly ExactMatchNamingConvention Instance = new ExactMatchNamingConvention(); + public static readonly ExactMatchNamingConvention Instance = new(); public Regex SplittingExpression { get; } public string SeparatorCharacter => ""; public string ReplaceValue(Match match) => match.Value; } public class PascalCaseNamingConvention : INamingConvention { - private static readonly Regex PascalCase = new Regex(@"(\p{Lu}+(?=$|\p{Lu}[\p{Ll}0-9])|\p{Lu}?[\p{Ll}0-9]+)"); - public static readonly PascalCaseNamingConvention Instance = new PascalCaseNamingConvention(); + private static readonly Regex PascalCase = new(@"(\p{Lu}+(?=$|\p{Lu}[\p{Ll}0-9])|\p{Lu}?[\p{Ll}0-9]+)"); + public static readonly PascalCaseNamingConvention Instance = new(); public Regex SplittingExpression { get; } = PascalCase; public string SeparatorCharacter => string.Empty; - public string ReplaceValue(Match match) => match.Value[0].ToString().ToUpper() + match.Value.Substring(1); + public string ReplaceValue(Match match) + { + var source = match.Value; + return string.Create(source.Length, source, static (buffer, state) => + { + buffer[0] = char.ToUpper(state[0]); + state.AsSpan(1).CopyTo(buffer[1..]); + }); + } } public class LowerUnderscoreNamingConvention : INamingConvention { - private static readonly Regex LowerUnderscore = new Regex(@"[\p{Ll}\p{Lu}0-9]+(?=_?)"); - public static readonly LowerUnderscoreNamingConvention Instance = new LowerUnderscoreNamingConvention(); + private static readonly Regex LowerUnderscore = new(@"[\p{Ll}\p{Lu}0-9]+(?=_?)"); + public static readonly LowerUnderscoreNamingConvention Instance = new(); public Regex SplittingExpression { get; } = LowerUnderscore; public string SeparatorCharacter => "_"; public string ReplaceValue(Match match) => match.Value.ToLower(); diff --git a/src/AutoMapper/TypeMap.cs b/src/AutoMapper/TypeMap.cs index 3c11751072..16c4faf4a7 100644 --- a/src/AutoMapper/TypeMap.cs +++ b/src/AutoMapper/TypeMap.cs @@ -12,7 +12,6 @@ namespace AutoMapper using static Execution.ExpressionBuilder; using Configuration; using Features; - using QueryableExtensions.Impl; using Internal; /// /// Main configuration object holding all mapping configuration for a source and destination type diff --git a/src/Benchmark/Program.cs b/src/Benchmark/Program.cs index 1c2ed765c4..61e5f78689 100644 --- a/src/Benchmark/Program.cs +++ b/src/Benchmark/Program.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using Benchmark.Flattening; namespace Benchmark @@ -14,12 +15,16 @@ public static void Main(string[] args) { "Complex", new IObjectToObjectMapper[] { new ComplexTypeMapper(), new ManualComplexTypeMapper() } }, { "Deep", new IObjectToObjectMapper[] { new DeepTypeMapper(), new ManualDeepTypeMapper() } } }; - foreach(var pair in mappers) + while (true) { - foreach(var mapper in pair.Value) + foreach (var pair in mappers) { - new BenchEngine(mapper, pair.Key).Start(); + foreach (var mapper in pair.Value) + { + new BenchEngine(mapper, pair.Key).Start(); + } } + Console.ReadLine(); } } } From 7fdf9150c5ad8fb40c1152c25b0ba39a755ee86c Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Thu, 4 Aug 2022 11:54:04 +0300 Subject: [PATCH 07/67] less null checks --- .../Configuration/MapperConfiguration.cs | 27 ++++--- src/AutoMapper/Execution/ExpressionBuilder.cs | 75 ++++++++++++------- .../Execution/TypeMapPlanBuilder.cs | 9 +-- src/AutoMapper/Mappers/CollectionMapper.cs | 25 ++----- src/AutoMapper/MemberMap.cs | 6 +- 5 files changed, 77 insertions(+), 65 deletions(-) diff --git a/src/AutoMapper/Configuration/MapperConfiguration.cs b/src/AutoMapper/Configuration/MapperConfiguration.cs index efe5ceb799..a90e931c72 100644 --- a/src/AutoMapper/Configuration/MapperConfiguration.cs +++ b/src/AutoMapper/Configuration/MapperConfiguration.cs @@ -207,33 +207,38 @@ static LambdaExpression GenerateTypeMapExpression(TypePair requestedTypes, TypeM } static Expression CheckNullValueType(Expression expression, Type runtimeType) => !expression.Type.IsValueType && runtimeType.IsValueType ? Coalesce(expression, Default(runtimeType)) : expression; - LambdaExpression GenerateObjectMapperExpression(in MapRequest mapRequest, IObjectMapper mapperToUse) + LambdaExpression GenerateObjectMapperExpression(in MapRequest mapRequest, IObjectMapper mapper) { var source = Parameter(mapRequest.RequestedTypes.SourceType, "source"); - var destination = Parameter(mapRequest.RequestedTypes.DestinationType, "mapperDestination"); + var destinationType = mapRequest.RequestedTypes.DestinationType; + var destination = Parameter(destinationType, "mapperDestination"); var runtimeDestinationType = mapRequest.RuntimeTypes.DestinationType; Expression fullExpression; - if (mapperToUse == null) + bool nullCheck; + if (mapper == null) { var exception = new AutoMapperMappingException("Missing type map configuration or unsupported mapping.", null, mapRequest.RuntimeTypes) { MemberMap = mapRequest.MemberMap }; + nullCheck = true; fullExpression = Throw(Constant(exception), runtimeDestinationType); } else { var checkNullValueTypeDest = CheckNullValueType(destination, runtimeDestinationType); - var map = mapperToUse.MapExpression(this, Configuration, mapRequest.MemberMap, - ToType(source, mapRequest.RuntimeTypes.SourceType), - ToType(checkNullValueTypeDest, runtimeDestinationType)); + var mapperSource = ToType(source, mapRequest.RuntimeTypes.SourceType); + var map = mapper.MapExpression(this, Configuration, mapRequest.MemberMap, mapperSource, ToType(checkNullValueTypeDest, runtimeDestinationType)); + nullCheck = map != mapperSource; var newException = Call(MappingError, ExceptionParameter, Constant(mapRequest)); - var throwExpression = Throw(newException, runtimeDestinationType); - fullExpression = TryCatch(ToType(map, runtimeDestinationType), Catch(ExceptionParameter, throwExpression)); + fullExpression = TryCatch(ToType(map, destinationType), Catch(ExceptionParameter, Throw(newException, destinationType))); } - var profileMap = mapRequest.MemberMap.Profile ?? Configuration; - var nullCheckSource = NullCheckSource(profileMap, source, destination, fullExpression, mapRequest.MemberMap); - return Lambda(nullCheckSource, source, destination, ContextParameter); + if (nullCheck) + { + var profileMap = mapRequest.MemberMap.Profile ?? Configuration; + fullExpression = NullCheckSource(profileMap, source, destination, fullExpression, mapRequest.MemberMap); + } + return Lambda(fullExpression, source, destination, ContextParameter); } } static MapperConfigurationExpression Build(Action configure) diff --git a/src/AutoMapper/Execution/ExpressionBuilder.cs b/src/AutoMapper/Execution/ExpressionBuilder.cs index 4714519fed..48674c551d 100644 --- a/src/AutoMapper/Execution/ExpressionBuilder.cs +++ b/src/AutoMapper/Execution/ExpressionBuilder.cs @@ -43,15 +43,16 @@ public static class ExpressionBuilder private static readonly UnaryExpression IncrementIndex = PostIncrementAssign(Index); public static Expression MapExpression(this IGlobalConfiguration configurationProvider, ProfileMap profileMap, TypePair typePair, Expression source, - MemberMap propertyMap = null, Expression destination = null) + MemberMap memberMap = null, Expression destination = null) { destination ??= Default(typePair.DestinationType); var typeMap = configurationProvider.ResolveTypeMap(typePair); Expression mapExpression = null; - bool hasTypeConverter; + bool nullCheck; if (typeMap != null) { - hasTypeConverter = typeMap.HasTypeConverter; + var allowNull = memberMap?.AllowNull; + nullCheck = !typeMap.HasTypeConverter && allowNull.HasValue && allowNull != profileMap.AllowNullDestinationValues; if (!typeMap.HasDerivedTypesToInclude) { configurationProvider.Seal(typeMap); @@ -63,37 +64,41 @@ public static Expression MapExpression(this IGlobalConfiguration configurationPr } else { - hasTypeConverter = false; var mapper = configurationProvider.FindMapper(typePair); - mapExpression = mapper?.MapExpression(configurationProvider, profileMap, propertyMap, source, destination); - } - mapExpression ??= ContextMap(typePair, source, destination, propertyMap); - if (!hasTypeConverter) - { - mapExpression = NullCheckSource(profileMap, source, destination, mapExpression, propertyMap); + if (mapper != null) + { + mapExpression = mapper.MapExpression(configurationProvider, profileMap, memberMap, source, destination); + nullCheck = mapExpression != source; + mapExpression = ToType(mapExpression, typePair.DestinationType); + } + else + { + nullCheck = true; + } } - return ToType(mapExpression, typePair.DestinationType); + mapExpression ??= ContextMap(typePair, source, destination, memberMap); + return nullCheck ? NullCheckSource(profileMap, source, destination, mapExpression, memberMap) : mapExpression; } - public static Expression NullCheckSource(ProfileMap profileMap, Expression sourceParameter, Expression destinationParameter, Expression mapExpression, MemberMap memberMap) + public static Expression NullCheckSource(ProfileMap profileMap, Expression source, Expression destination, Expression mapExpression, MemberMap memberMap) { - var sourceType = sourceParameter.Type; + var sourceType = source.Type; if (sourceType.IsValueType && !sourceType.IsNullableType()) { return mapExpression; } - var destinationType = destinationParameter.Type; + var destinationType = destination.Type; var isCollection = destinationType.IsCollection(); var mustUseDestination = memberMap is { MustUseDestination: true }; var ifSourceNull = mustUseDestination ? ClearDestinationCollection() : DefaultDestination(); - return sourceParameter.IfNullElse(ifSourceNull, mapExpression); + return source.IfNullElse(ifSourceNull, mapExpression); Expression ClearDestinationCollection() { if (!isCollection) { - return destinationParameter; + return destination; } MethodInfo clearMethod; - var destinationVariable = Variable(destinationParameter.Type, "collectionDestination"); + var destinationVariable = Variable(destination.Type, "collectionDestination"); Expression collection = destinationVariable; if (destinationType.IsListType()) { @@ -106,7 +111,7 @@ Expression ClearDestinationCollection() { if (!mustUseDestination) { - return destinationParameter; + return destination; } var destinationElementType = GetEnumerableElementType(destinationType); destinationCollectionType = typeof(ICollection<>).MakeGenericType(destinationElementType); @@ -115,7 +120,7 @@ Expression ClearDestinationCollection() clearMethod = destinationCollectionType.GetMethod("Clear"); } return Block(new[] { destinationVariable }, - Assign(destinationVariable, destinationParameter), + Assign(destinationVariable, destination), Condition(ReferenceEqual(collection, Null), Empty, Expression.Call(collection, clearMethod)), destinationVariable); } @@ -123,14 +128,14 @@ Expression DefaultDestination() { if ((isCollection && profileMap.AllowsNullCollectionsFor(memberMap)) || (!isCollection && profileMap.AllowsNullDestinationValuesFor(memberMap))) { - return destinationParameter.NodeType == ExpressionType.Default ? destinationParameter : Default(destinationType); + return destination.NodeType == ExpressionType.Default ? destination : Default(destinationType); } if (destinationType.IsArray) { var destinationElementType = destinationType.GetElementType(); var rank = destinationType.GetArrayRank(); - return rank == 1 ? - Expression.Call(ArrayEmptyMethod.MakeGenericMethod(destinationElementType)) : + return rank == 1 ? + Expression.Call(ArrayEmptyMethod.MakeGenericMethod(destinationElementType)) : NewArrayBounds(destinationElementType, Enumerable.Repeat(Zero, rank)); } return ObjectFactory.GenerateConstructorExpression(destinationType); @@ -164,7 +169,7 @@ public static Expression ApplyTransformers(this MemberMap memberMap, Expression } var transformers = perMember.Concat(perMap).Concat(perProfile); return Apply(transformers, memberMap, source); - static Expression Apply(IEnumerable transformers, MemberMap memberMap, Expression source) => + static Expression Apply(IEnumerable transformers, MemberMap memberMap, Expression source) => transformers.Where(vt => vt.IsMatch(memberMap)).Aggregate(source, (current, vtConfig) => ToType(vtConfig.TransformerExpression.ReplaceParameters(ToType(current, vtConfig.ValueType)), memberMap.DestinationType)); } @@ -325,22 +330,36 @@ private static Expression Replace(this ParameterReplaceVisitor visitor, LambdaEx return newLambda; } public static Expression Replace(this Expression exp, Expression old, Expression replace) => new ReplaceVisitor(old, replace).Visit(exp); - public static Expression NullCheck(this Expression expression, Type destinationType = null, Expression defaultValue = null) + public static Expression NullCheck(this Expression expression, MemberMap memberMap = null, Expression defaultValue = null) { var chain = expression.GetChain(); - if (chain.Count == 0 || chain.Peek().Target is not ParameterExpression parameter) + var min = memberMap?.IncludedMember != null ? 1 : 2; + if (chain.Count < min || chain.Peek().Target is not ParameterExpression parameter) { return expression; } + var destinationType = memberMap?.DestinationType; var returnType = (destinationType != null && destinationType != expression.Type && Nullable.GetUnderlyingType(destinationType) == expression.Type) ? destinationType : expression.Type; var defaultReturn = (defaultValue is { NodeType: ExpressionType.Default } && defaultValue.Type == returnType) ? defaultValue : Default(returnType); ParameterExpression[] variables = null; - var name = parameter.Name; + Expression begin; + string name; + if (min == 1) + { + begin = parameter; + name = parameter.Name; + } + else + { + var second = chain.Pop(); + begin = second.Expression; + name = parameter.Name + second.MemberInfo.Name; + } int index = 0; - var nullCheckedExpression = NullCheck(parameter); + var nullCheckedExpression = NullCheck(begin); return variables == null ? nullCheckedExpression : Block(variables, nullCheckedExpression); - Expression NullCheck(ParameterExpression variable) + Expression NullCheck(Expression variable) { var member = chain.Pop(); if (chain.Count == 0) diff --git a/src/AutoMapper/Execution/TypeMapPlanBuilder.cs b/src/AutoMapper/Execution/TypeMapPlanBuilder.cs index c2efa3a7c0..8a15c88184 100644 --- a/src/AutoMapper/Execution/TypeMapPlanBuilder.cs +++ b/src/AutoMapper/Execution/TypeMapPlanBuilder.cs @@ -235,10 +235,7 @@ private Expression CreateMapperFunc(Expression assignmentFunc) { mapperFunc = Condition(overMaxDepth, Default(DestinationType), mapperFunc); } - if (_typeMap.Profile.AllowNullDestinationValues) - { - mapperFunc = Source.IfNullElse(Default(DestinationType), mapperFunc); - } + mapperFunc = NullCheckSource(_typeMap.Profile, Source, _initialDestination, mapperFunc, null); return CheckReferencesCache(mapperFunc); } private Expression CheckReferencesCache(Expression valueBuilder) @@ -421,7 +418,7 @@ public ExpressionResolver(LambdaExpression lambda) : base(lambda) { } public Expression GetExpression(MemberMap memberMap, Expression source, Expression _, Expression destinationMember) { var mapFrom = Lambda.ReplaceParameters(source); - var nullCheckedExpression = mapFrom.NullCheck(memberMap.DestinationType, destinationMember); + var nullCheckedExpression = mapFrom.NullCheck(memberMap, destinationMember); if (nullCheckedExpression != mapFrom) { return nullCheckedExpression; @@ -461,7 +458,7 @@ public Expression GetExpression(MemberMap memberMap, Expression source, Expressi var sourceMember = SourceMemberLambda?.ReplaceParameters(source) ?? (SourceMemberName != null ? PropertyOrField(source, SourceMemberName) : - memberMap.ChainSourceMembers(source, iResolverTypeArgs[1], destinationMember) ?? Throw(Constant(BuildExceptionMessage()), iResolverTypeArgs[0])); + memberMap.ChainSourceMembers(source, destinationMember) ?? Throw(Constant(BuildExceptionMessage()), iResolverTypeArgs[0])); return Call(ToType(_instance, InterfaceType), "Convert", ToType(sourceMember, iResolverTypeArgs[0]), ContextParameter); AutoMapperConfigurationException BuildExceptionMessage() => new($"Cannot find a source member to pass to the value converter of type {ConcreteType}. Configure a source member to map from."); diff --git a/src/AutoMapper/Mappers/CollectionMapper.cs b/src/AutoMapper/Mappers/CollectionMapper.cs index 2d2652825b..5ecbe12d56 100644 --- a/src/AutoMapper/Mappers/CollectionMapper.cs +++ b/src/AutoMapper/Mappers/CollectionMapper.cs @@ -74,13 +74,13 @@ Expression MapCollectionCore(Expression destExpression) addItems = Condition(overMaxDepth, ExpressionBuilder.Empty, addItems); } var clearMethod = isIList ? IListClear : destinationCollectionType.GetMethod("Clear"); - var checkNull = Block(new[] { newExpression, passedDestination }, - Assign(passedDestination, destExpression), - assignNewExpression, - Call(destination, clearMethod), - addItems, - destination); - return CheckContext(); + return Block(new[] { newExpression, passedDestination }, + CheckContext() ?? ExpressionBuilder.Empty, + Assign(passedDestination, destExpression), + assignNewExpression, + Call(destination, clearMethod), + addItems, + destination); void GetDestinationType() { var immutableCollection = !mustUseDestination && destinationType.IsValueType; @@ -132,16 +132,7 @@ void UseDestinationValue() Expression CheckContext() { var elementTypeMap = configurationProvider.ResolveTypeMap(sourceElementType, destinationElementType); - if (elementTypeMap == null) - { - return checkNull; - } - var checkContext = ExpressionBuilder.CheckContext(elementTypeMap); - if (checkContext == null) - { - return checkNull; - } - return Block(checkContext, checkNull); + return elementTypeMap == null ? null : ExpressionBuilder.CheckContext(elementTypeMap); } } } diff --git a/src/AutoMapper/MemberMap.cs b/src/AutoMapper/MemberMap.cs index 6b2f17d87d..d29db45552 100644 --- a/src/AutoMapper/MemberMap.cs +++ b/src/AutoMapper/MemberMap.cs @@ -59,8 +59,8 @@ public void MapFrom(string sourceMembersPath) } public override string ToString() => DestinationName; public Expression ChainSourceMembers(Expression source) => SourceMembers.Chain(source); - public Expression ChainSourceMembers(Expression source, Type destinationType, Expression defaultValue) => - ChainSourceMembers(source)?.NullCheck(destinationType, defaultValue); + public Expression ChainSourceMembers(Expression source, Expression defaultValue) => + ChainSourceMembers(source)?.NullCheck(this, defaultValue); public bool AllowsNullDestinationValues => Profile?.AllowsNullDestinationValuesFor(this) ?? true; public bool AllowsNullCollections => (Profile?.AllowsNullCollectionsFor(this)).GetValueOrDefault(); public ProfileMap Profile => TypeMap?.Profile; @@ -76,7 +76,7 @@ public void MapByConvention(MemberInfo[] sourceMembers) Resolver = this; } Expression IValueResolver.GetExpression(MemberMap memberMap, Expression source, Expression destination, Expression destinationMember) => - ChainSourceMembers(source, memberMap.DestinationType, destinationMember); + ChainSourceMembers(source, destinationMember); MemberInfo IValueResolver.GetSourceMember(MemberMap memberMap) => SourceMembers[0]; Type IValueResolver.ResolvedType => SourceMembers[^1].GetMemberType(); } From 4b507ee9967a5b1754bcc003492882e31e42ebf1 Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Sat, 6 Aug 2022 07:31:36 +0300 Subject: [PATCH 08/67] unreachable, As maps are sealed by default --- src/AutoMapper/Execution/TypeMapPlanBuilder.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/AutoMapper/Execution/TypeMapPlanBuilder.cs b/src/AutoMapper/Execution/TypeMapPlanBuilder.cs index 8a15c88184..22efd753e2 100644 --- a/src/AutoMapper/Execution/TypeMapPlanBuilder.cs +++ b/src/AutoMapper/Execution/TypeMapPlanBuilder.cs @@ -76,11 +76,6 @@ static void Clear(ref HashSet typeMapsPath) } private static void CheckForCycles(IGlobalConfiguration configurationProvider, TypeMap typeMap, HashSet typeMapsPath) { - if (typeMap.DestinationTypeOverride != null) - { - CheckForCycles(configurationProvider, configurationProvider.GetIncludedTypeMap(typeMap.AsPair()), typeMapsPath); - return; - } typeMapsPath.Add(typeMap); foreach (var memberMap in MemberMaps()) { From 84e3fff5b966c41f94cefd55c4e9bf424ba939ac Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Sat, 6 Aug 2022 17:39:02 +0300 Subject: [PATCH 09/67] less allocations --- src/AutoMapper/Execution/TypeMapPlanBuilder.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/AutoMapper/Execution/TypeMapPlanBuilder.cs b/src/AutoMapper/Execution/TypeMapPlanBuilder.cs index 22efd753e2..0ad2539366 100644 --- a/src/AutoMapper/Execution/TypeMapPlanBuilder.cs +++ b/src/AutoMapper/Execution/TypeMapPlanBuilder.cs @@ -47,9 +47,7 @@ public LambdaExpression CreateMapperLambda(HashSet typeMapsPath) var statements = new List(); if (_typeMap.IncludedMembersTypeMaps.Count > 0) { - variables.AddRange(_typeMap.IncludedMembersTypeMaps.Select(i => i.Variable)); - statements.AddRange(variables.Zip(_typeMap.IncludedMembersTypeMaps, (v, i) => - Assign(v, i.MemberExpression.ReplaceParameters(parameters).NullCheck()))); + IncludeMembers(parameters, variables, statements); } var createDestinationFunc = CreateDestinationFunc(); var assignmentFunc = CreateAssignmentFunc(createDestinationFunc); @@ -73,6 +71,12 @@ static void Clear(ref HashSet typeMapsPath) typeMapsPath.Clear(); } } + void IncludeMembers(ParameterExpression[] parameters, List variables, List statements) + { + variables.AddRange(_typeMap.IncludedMembersTypeMaps.Select(i => i.Variable)); + statements.AddRange(variables.Zip(_typeMap.IncludedMembersTypeMaps, (v, i) => + Assign(v, i.MemberExpression.ReplaceParameters(parameters).NullCheck()))); + } } private static void CheckForCycles(IGlobalConfiguration configurationProvider, TypeMap typeMap, HashSet typeMapsPath) { From b5cc0a67a7822126aa5e8ed882961adc01e69f37 Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Sun, 7 Aug 2022 09:53:31 +0300 Subject: [PATCH 10/67] don't try to match ignored members --- src/AutoMapper/ApiCompatBaseline.txt | 4 ++- .../Configuration/MappingExpressionBase.cs | 25 +++---------------- .../MemberConfigurationExpression.cs | 11 +++++--- src/AutoMapper/TypeMap.cs | 10 ++++++-- 4 files changed, 22 insertions(+), 28 deletions(-) diff --git a/src/AutoMapper/ApiCompatBaseline.txt b/src/AutoMapper/ApiCompatBaseline.txt index c6ed379f03..412600f308 100644 --- a/src/AutoMapper/ApiCompatBaseline.txt +++ b/src/AutoMapper/ApiCompatBaseline.txt @@ -5,6 +5,8 @@ InterfacesShouldHaveSameMembers : Interface member 'public void AutoMapper.IMapp MembersMustExist : Member 'public void AutoMapper.IMappingExpressionBase.AsProxy()' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public AutoMapper.IMappingOperationOptions AutoMapper.ResolutionContext.Options.get()' does not exist in the implementation but it does exist in the contract. TypesMustExist : Type 'AutoMapper.ValueResolverConfiguration' does not exist in the implementation but it does exist in the contract. +InterfacesShouldHaveSameMembers : Default interface member 'public System.Boolean AutoMapper.Configuration.IPropertyMapConfiguration.Ignored' is present in the implementation but not in the contract. +InterfacesShouldHaveSameMembers : Default interface member 'public System.Boolean AutoMapper.Configuration.IPropertyMapConfiguration.Ignored.get()' is present in the implementation but not in the contract. MembersMustExist : Member 'public void AutoMapper.Configuration.MappingExpressionBase.AsProxy()' does not exist in the implementation but it does exist in the contract. CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'AutoMapper.Configuration.Annotations.IgnoreAttribute' changed from '[AttributeUsageAttribute(384)]' in the contract to '[AttributeUsageAttribute(AttributeTargets.Field | AttributeTargets.Property)]' in the implementation. CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'AutoMapper.Configuration.Annotations.MapAtRuntimeAttribute' changed from '[AttributeUsageAttribute(384)]' in the contract to '[AttributeUsageAttribute(AttributeTargets.Field | AttributeTargets.Property)]' in the implementation. @@ -25,4 +27,4 @@ MembersMustExist : Member 'public AutoMapper.Internal.TypePair AutoMapper.Intern MembersMustExist : Member 'public System.Linq.IQueryable AutoMapper.QueryableExtensions.Extensions.Map(System.Linq.IQueryable, System.Linq.IQueryable, AutoMapper.IConfigurationProvider)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Collections.Generic.IReadOnlyCollection AutoMapper.QueryableExtensions.MemberVisitor.MemberPath.get()' does not exist in the implementation but it does exist in the contract. TypesMustExist : Type 'AutoMapper.QueryableExtensions.Impl.MemberAccessQueryMapperVisitor' does not exist in the implementation but it does exist in the contract. -Total Issues: 26 +Total Issues: 28 diff --git a/src/AutoMapper/Configuration/MappingExpressionBase.cs b/src/AutoMapper/Configuration/MappingExpressionBase.cs index 5c8cb30a3a..4e13c71a01 100644 --- a/src/AutoMapper/Configuration/MappingExpressionBase.cs +++ b/src/AutoMapper/Configuration/MappingExpressionBase.cs @@ -21,6 +21,7 @@ public interface ITypeMapConfiguration ITypeMapConfiguration ReverseTypeMap { get; } TypeMap TypeMap { get; } bool HasTypeConverter { get; } + IPropertyMapConfiguration GetDestinationMemberConfiguration(MemberInfo destinationMember); } public abstract class MappingExpressionBase : ITypeMapConfiguration { @@ -60,11 +61,6 @@ public void Configure(TypeMap typeMap) TypeMap = typeMap; typeMap.Projection = Projection; typeMap.ConfiguredMemberList = _memberList; - var globalIgnores = typeMap.Profile.GlobalIgnores; - if (globalIgnores.Count > 0) - { - GlobalIgnores(typeMap, globalIgnores); - } foreach (var action in TypeMapActions) { action(typeMap); @@ -151,18 +147,6 @@ private void ConfigureReverseMap(TypeMap typeMap) ReverseIncludedMembers(typeMap); } - private void GlobalIgnores(TypeMap typeMap, IReadOnlyCollection globalIgnores) - { - foreach (var ignoredPropertyName in globalIgnores.Where(p => GetDestinationMemberConfiguration(p) == null)) - { - var ignoredProperty = typeMap.DestinationSetters.SingleOrDefault(p => p.Name == ignoredPropertyName); - if (ignoredProperty != null) - { - IgnoreDestinationMember(ignoredProperty); - } - } - } - private void MapDestinationCtorToSource(TypeMap typeMap) { var sourceMembers = new List(); @@ -263,11 +247,8 @@ protected void IncludeBaseCore(Type sourceBase, Type destinationBase) TypeMapActions.Add(tm => tm.IncludeBaseTypes(baseTypes)); } - protected IPropertyMapConfiguration GetDestinationMemberConfiguration(MemberInfo destinationMember) => - GetDestinationMemberConfiguration(destinationMember.Name); - - private IPropertyMapConfiguration GetDestinationMemberConfiguration(string name) => - _memberConfigurations?.FirstOrDefault(m => m.DestinationMember.Name == name); + public IPropertyMapConfiguration GetDestinationMemberConfiguration(MemberInfo destinationMember) => + _memberConfigurations?.FirstOrDefault(m => m.DestinationMember == destinationMember); protected abstract void IgnoreDestinationMember(MemberInfo property, bool ignorePaths = true); } diff --git a/src/AutoMapper/Configuration/MemberConfigurationExpression.cs b/src/AutoMapper/Configuration/MemberConfigurationExpression.cs index 513b40ae4a..8fecabbfbf 100644 --- a/src/AutoMapper/Configuration/MemberConfigurationExpression.cs +++ b/src/AutoMapper/Configuration/MemberConfigurationExpression.cs @@ -14,7 +14,8 @@ public interface IPropertyMapConfiguration MemberInfo DestinationMember { get; } LambdaExpression SourceExpression { get; } LambdaExpression GetDestinationExpression(); - IPropertyMapConfiguration Reverse(); + IPropertyMapConfiguration Reverse(); + bool Ignored => false; } public class MemberConfigurationExpression : IMemberConfigurationExpression, IPropertyMapConfiguration { @@ -90,15 +91,18 @@ public void AddTransform(Expression> transformer) => PropertyMapActions.Add(pm => pm.AddValueTransformation(new ValueTransformerConfiguration(pm.DestinationType, transformer))); public void ExplicitExpansion() => PropertyMapActions.Add(pm => pm.ExplicitExpansion = true); public void Ignore() => Ignore(ignorePaths: true); - public void Ignore(bool ignorePaths) => + public void Ignore(bool ignorePaths) + { + Ignored = true; PropertyMapActions.Add(pm => { pm.Ignored = true; - if(ignorePaths && pm.TypeMap.PathMaps.Count > 0) + if (ignorePaths && pm.TypeMap.PathMaps.Count > 0) { pm.TypeMap.IgnorePaths(DestinationMember); } }); + } public void AllowNull() => SetAllowNull(true); public void DoNotAllowNull() => SetAllowNull(false); private void SetAllowNull(bool value) => PropertyMapActions.Add(pm => pm.AllowNull = value); @@ -148,6 +152,7 @@ private void Apply(PropertyMap propertyMap) } } public LambdaExpression SourceExpression { get; private set; } + public bool Ignored { get; private set; } public LambdaExpression GetDestinationExpression() => DestinationMember.Lambda(); public IPropertyMapConfiguration Reverse() { diff --git a/src/AutoMapper/TypeMap.cs b/src/AutoMapper/TypeMap.cs index 16c4faf4a7..7a8a56d9c7 100644 --- a/src/AutoMapper/TypeMap.cs +++ b/src/AutoMapper/TypeMap.cs @@ -37,9 +37,15 @@ public TypeMap(Type sourceType, Type destinationType, ProfileMap profile, ITypeM var sourceMembers = new List(); foreach (var destinationProperty in DestinationTypeDetails.WriteAccessors) { + var destinationName = destinationProperty.Name; + var memberConfig = typeMapConfiguration?.GetDestinationMemberConfiguration(destinationProperty); + if (memberConfig?.Ignored is true || profile.GlobalIgnores.Contains(destinationName)) + { + continue; + } sourceMembers.Clear(); var propertyType = destinationProperty.GetMemberType(); - if (profile.MapDestinationPropertyToSource(SourceTypeDetails, destinationType, propertyType, destinationProperty.Name, sourceMembers, + if (profile.MapDestinationPropertyToSource(SourceTypeDetails, destinationType, propertyType, destinationName, sourceMembers, typeMapConfiguration?.IsReverseMap is true)) { AddPropertyMap(destinationProperty, propertyType, sourceMembers); @@ -143,7 +149,7 @@ public Type MakeGenericType(Type type) => type.IsGenericTypeDefinition ? public IEnumerable GetAllIncludedMembers() => IncludedMembersNames.Length == 0 || SourceType.ContainsGenericParameters ? IncludedMembers : IncludedMembers.Concat(IncludedMembersNames.Select(name => MemberAccessLambda(SourceType, name))); public bool ConstructorParameterMatches(string destinationPropertyName) => ConstructorMapping && ConstructorMap[destinationPropertyName] != null; - public void AddPropertyMap(MemberInfo destProperty, Type destinationPropertyType, IEnumerable sourceMembers) + private void AddPropertyMap(MemberInfo destProperty, Type destinationPropertyType, IEnumerable sourceMembers) { var propertyMap = new PropertyMap(destProperty, destinationPropertyType, this); propertyMap.MapByConvention(sourceMembers.ToArray()); From df48e72dcdc0333fb185afeb568c255fdcd733fe Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Sun, 7 Aug 2022 12:11:58 +0300 Subject: [PATCH 11/67] more efficient --- src/AutoMapper/ApiCompatBaseline.txt | 7 +- .../Configuration/Conventions/Mappers.cs | 24 +++--- .../Conventions/MemberConfiguration.cs | 73 +++++-------------- .../Configuration/INamingConvention.cs | 15 +--- .../Configuration/MappingExpression.cs | 5 +- .../Configuration/MappingExpressionBase.cs | 4 +- src/AutoMapper/ProfileMap.cs | 12 +-- 7 files changed, 51 insertions(+), 89 deletions(-) diff --git a/src/AutoMapper/ApiCompatBaseline.txt b/src/AutoMapper/ApiCompatBaseline.txt index 412600f308..83957ec713 100644 --- a/src/AutoMapper/ApiCompatBaseline.txt +++ b/src/AutoMapper/ApiCompatBaseline.txt @@ -1,8 +1,13 @@ Compat issues with assembly AutoMapper: CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'AutoMapper.AutoMapAttribute' changed from '[AttributeUsageAttribute(1036, AllowMultiple=true)]' in the contract to '[AttributeUsageAttribute(AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Struct, AllowMultiple=true)]' in the implementation. +MembersMustExist : Member 'public System.String AutoMapper.ExactMatchNamingConvention.ReplaceValue(System.Text.RegularExpressions.Match)' does not exist in the implementation but it does exist in the contract. InterfacesShouldHaveSameMembers : Interface member 'public TMappingExpression AutoMapper.IMappingExpressionBase.AsProxy()' is present in the implementation but not in the contract. InterfacesShouldHaveSameMembers : Interface member 'public void AutoMapper.IMappingExpressionBase.AsProxy()' is present in the contract but not in the implementation. MembersMustExist : Member 'public void AutoMapper.IMappingExpressionBase.AsProxy()' does not exist in the implementation but it does exist in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public System.String AutoMapper.INamingConvention.ReplaceValue(System.Text.RegularExpressions.Match)' is present in the contract but not in the implementation. +MembersMustExist : Member 'public System.String AutoMapper.INamingConvention.ReplaceValue(System.Text.RegularExpressions.Match)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public System.String AutoMapper.LowerUnderscoreNamingConvention.ReplaceValue(System.Text.RegularExpressions.Match)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public System.String AutoMapper.PascalCaseNamingConvention.ReplaceValue(System.Text.RegularExpressions.Match)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public AutoMapper.IMappingOperationOptions AutoMapper.ResolutionContext.Options.get()' does not exist in the implementation but it does exist in the contract. TypesMustExist : Type 'AutoMapper.ValueResolverConfiguration' does not exist in the implementation but it does exist in the contract. InterfacesShouldHaveSameMembers : Default interface member 'public System.Boolean AutoMapper.Configuration.IPropertyMapConfiguration.Ignored' is present in the implementation but not in the contract. @@ -27,4 +32,4 @@ MembersMustExist : Member 'public AutoMapper.Internal.TypePair AutoMapper.Intern MembersMustExist : Member 'public System.Linq.IQueryable AutoMapper.QueryableExtensions.Extensions.Map(System.Linq.IQueryable, System.Linq.IQueryable, AutoMapper.IConfigurationProvider)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Collections.Generic.IReadOnlyCollection AutoMapper.QueryableExtensions.MemberVisitor.MemberPath.get()' does not exist in the implementation but it does exist in the contract. TypesMustExist : Type 'AutoMapper.QueryableExtensions.Impl.MemberAccessQueryMapperVisitor' does not exist in the implementation but it does exist in the contract. -Total Issues: 28 +Total Issues: 33 diff --git a/src/AutoMapper/Configuration/Conventions/Mappers.cs b/src/AutoMapper/Configuration/Conventions/Mappers.cs index 938fb1cef7..bd04abd715 100644 --- a/src/AutoMapper/Configuration/Conventions/Mappers.cs +++ b/src/AutoMapper/Configuration/Conventions/Mappers.cs @@ -20,7 +20,7 @@ public sealed class DefaultName : ISourceToDestinationNameMapper } public class ParentSourceToDestinationNameMapper : IParentSourceToDestinationNameMapper { - public List NamedMappers { get; } = new List { new DefaultName() }; + public List NamedMappers { get; } = new(){ new DefaultName() }; public MemberInfo GetMatchingMemberInfo(TypeDetails sourceTypeDetails, Type destType, Type destMemberType, string nameToSearch) { MemberInfo memberInfo = null; @@ -35,10 +35,10 @@ public MemberInfo GetMatchingMemberInfo(TypeDetails sourceTypeDetails, Type dest } public class PrePostfixName : ISourceToDestinationNameMapper { - public List Prefixes { get; } = new List(); - public List Postfixes { get; } = new List(); - public List DestinationPrefixes { get; } = new List(); - public List DestinationPostfixes { get; } = new List(); + public List Prefixes { get; } = new(); + public List Postfixes { get; } = new(); + public List DestinationPrefixes { get; } = new(); + public List DestinationPostfixes { get; } = new(); public MemberInfo GetMatchingMemberInfo(TypeDetails sourceTypeDetails, Type destType, Type destMemberType, string nameToSearch) { MemberInfo member; @@ -54,24 +54,28 @@ public MemberInfo GetMatchingMemberInfo(TypeDetails sourceTypeDetails, Type dest } public class ReplaceName : ISourceToDestinationNameMapper { - private readonly List _memberNameReplacers = new List(); + private readonly List _memberNameReplacers = new(); public ReplaceName AddReplace(string original, string newValue) { - _memberNameReplacers.Add(new MemberNameReplacer(original, newValue)); + _memberNameReplacers.Add(new(original, newValue)); return this; } public MemberInfo GetMatchingMemberInfo(TypeDetails sourceTypeDetails, Type destType, Type destMemberType, string nameToSearch) { var possibleSourceNames = PossibleNames(nameToSearch); + if (possibleSourceNames.Length == 0) + { + return null; + } var possibleDestNames = sourceTypeDetails.ReadAccessors.Select(mi => (mi, possibles : PossibleNames(mi.Name))).ToArray(); foreach (var sourceName in possibleSourceNames) { - foreach (var destName in possibleDestNames) + foreach (var (mi, possibles) in possibleDestNames) { - if (Array.Exists(destName.possibles, name => string.Compare(name, sourceName, StringComparison.OrdinalIgnoreCase) == 0)) + if (possibles.Contains(sourceName, StringComparer.OrdinalIgnoreCase)) { - return destName.mi; + return mi; } } } diff --git a/src/AutoMapper/Configuration/Conventions/MemberConfiguration.cs b/src/AutoMapper/Configuration/Conventions/MemberConfiguration.cs index bfbb41e92f..41e5180363 100644 --- a/src/AutoMapper/Configuration/Conventions/MemberConfiguration.cs +++ b/src/AutoMapper/Configuration/Conventions/MemberConfiguration.cs @@ -5,20 +5,14 @@ using System.ComponentModel; using System.Linq; using System.Reflection; -using System.Text.RegularExpressions; - namespace AutoMapper.Configuration.Conventions { [EditorBrowsable(EditorBrowsableState.Never)] public interface IMemberConfiguration { List MemberMappers { get; } - IMemberConfiguration AddMember(Action setupAction = null) - where TMemberMapper : IChildMemberConfiguration, new(); - - IMemberConfiguration AddName(Action setupAction = null) - where TNameMapper : ISourceToDestinationNameMapper, new(); - + IMemberConfiguration AddMember(Action setupAction = null) where TMemberMapper : IChildMemberConfiguration, new(); + IMemberConfiguration AddName(Action setupAction = null) where TNameMapper : ISourceToDestinationNameMapper, new(); IParentSourceToDestinationNameMapper NameMapper { get; set; } bool MapDestinationPropertyToSource(ProfileMap options, TypeDetails sourceType, Type destType, Type destMemberType, string nameToSearch, List resolvers, bool isReverseMap); } @@ -31,7 +25,6 @@ public interface IChildMemberConfiguration public class DefaultMember : IChildMemberConfiguration { public IParentSourceToDestinationNameMapper NameMapper { get; set; } - public bool MapDestinationPropertyToSource(ProfileMap options, TypeDetails sourceTypeDetails, Type destType, Type destMemberType, string nameToSearch, List resolvers, IMemberConfiguration parent = null, bool isReverseMap = false) { var matchingMemberInfo = NameMapper.GetMatchingMemberInfo(sourceTypeDetails, destType, destMemberType, nameToSearch); @@ -47,42 +40,33 @@ public bool MapDestinationPropertyToSource(ProfileMap options, TypeDetails sourc public class MemberConfiguration : IMemberConfiguration { public IParentSourceToDestinationNameMapper NameMapper { get; set; } - - public List MemberMappers { get; } = new List(); - - public IMemberConfiguration AddMember(Action setupAction = null) - where TMemberMapper : IChildMemberConfiguration, new() + public List MemberMappers { get; } = new(); + public IMemberConfiguration AddMember(Action setupAction = null) where TMemberMapper : IChildMemberConfiguration, new() { - GetOrAdd(_ => (IList)_.MemberMappers, setupAction); + GetOrAdd(MemberMappers, setupAction); return this; } - public IMemberConfiguration AddName(Action setupAction = null) where TNameMapper : ISourceToDestinationNameMapper, new() { - GetOrAdd(_ => (IList)_.NameMapper.NamedMappers, setupAction); + GetOrAdd(NameMapper.NamedMappers, setupAction); return this; } - - private TMemberMapper GetOrAdd(Func getList, Action setupAction = null) - where TMemberMapper : new() + private void GetOrAdd(IList list, Action setupAction = null) where TMemberMapper : new() { - var child = getList(this).OfType().FirstOrDefault(); + var child = list.OfType().FirstOrDefault(); if (child == null) { - child = new TMemberMapper(); - getList(this).Add(child); + child = new(); + list.Add(child); } setupAction?.Invoke(child); - return child; } - public MemberConfiguration() { NameMapper = new ParentSourceToDestinationNameMapper(); MemberMappers.Add(new DefaultMember { NameMapper = NameMapper }); } - public bool MapDestinationPropertyToSource(ProfileMap options, TypeDetails sourceType, Type destType, Type destMemberType, string nameToSearch, List resolvers, bool isReverseMap) { foreach (var memberMapper in MemberMappers) @@ -100,42 +84,26 @@ public class NameSplitMember : IChildMemberConfiguration { public INamingConvention SourceMemberNamingConvention { get; set; } public INamingConvention DestinationMemberNamingConvention { get; set; } - public bool MapDestinationPropertyToSource(ProfileMap options, TypeDetails sourceType, Type destType, Type destMemberType, string nameToSearch, List resolvers, IMemberConfiguration parent, bool isReverseMap) { - var destinationMemberNamingConvention = isReverseMap - ? SourceMemberNamingConvention - : DestinationMemberNamingConvention; - var sourceMemberNamingConvention = isReverseMap - ? DestinationMemberNamingConvention - : SourceMemberNamingConvention; - - var matches = destinationMemberNamingConvention.SplittingExpression - ?.Matches(nameToSearch) - .Cast() - .Select(m => sourceMemberNamingConvention.ReplaceValue(m)) - .ToArray() - ?? Array.Empty(); - + var destinationMemberNamingConvention = isReverseMap ? SourceMemberNamingConvention : DestinationMemberNamingConvention; + var sourceMemberNamingConvention = isReverseMap ? DestinationMemberNamingConvention : SourceMemberNamingConvention; + var matches = destinationMemberNamingConvention.SplittingExpression?.Matches(nameToSearch); + if (matches == null || matches.Count < 2) + { + return false; + } MemberInfo matchingMemberInfo = null; - for (var i = 1; i <= matches.Length; i++) + for (var index = 1; index <= matches.Count; index++) { - var first = string.Join( - sourceMemberNamingConvention.SeparatorCharacter, - matches.Take(i).Select(SplitMembers)); - var second = string.Join( - sourceMemberNamingConvention.SeparatorCharacter, - matches.Skip(i).Select(SplitMembers)); - + var first = string.Join(sourceMemberNamingConvention.SeparatorCharacter, matches.Take(index).Select(m=>m.Value)); matchingMemberInfo = parent.NameMapper.GetMatchingMemberInfo(sourceType, destType, destMemberType, first); - if (matchingMemberInfo != null) { resolvers.Add(matchingMemberInfo); - var details = options.CreateTypeDetails(matchingMemberInfo.GetMemberType()); + var second = string.Join(sourceMemberNamingConvention.SeparatorCharacter, matches.Skip(index).Select(m=>m.Value)); var foundMatch = parent.MapDestinationPropertyToSource(options, details, destType, destMemberType, second, resolvers, isReverseMap); - if (!foundMatch) resolvers.RemoveAt(resolvers.Count - 1); else @@ -143,7 +111,6 @@ public bool MapDestinationPropertyToSource(ProfileMap options, TypeDetails sourc } } return matchingMemberInfo != null; - string SplitMembers(string value) => sourceMemberNamingConvention.SplittingExpression.Replace(value, sourceMemberNamingConvention.ReplaceValue); } } } \ No newline at end of file diff --git a/src/AutoMapper/Configuration/INamingConvention.cs b/src/AutoMapper/Configuration/INamingConvention.cs index 9d297c2d04..c00ecc07bc 100644 --- a/src/AutoMapper/Configuration/INamingConvention.cs +++ b/src/AutoMapper/Configuration/INamingConvention.cs @@ -1,4 +1,3 @@ -using System; using System.Text.RegularExpressions; namespace AutoMapper { @@ -12,30 +11,19 @@ public interface INamingConvention /// Regex SplittingExpression { get; } string SeparatorCharacter { get; } - string ReplaceValue(Match match); } public class ExactMatchNamingConvention : INamingConvention { public static readonly ExactMatchNamingConvention Instance = new(); public Regex SplittingExpression { get; } public string SeparatorCharacter => ""; - public string ReplaceValue(Match match) => match.Value; } public class PascalCaseNamingConvention : INamingConvention { private static readonly Regex PascalCase = new(@"(\p{Lu}+(?=$|\p{Lu}[\p{Ll}0-9])|\p{Lu}?[\p{Ll}0-9]+)"); public static readonly PascalCaseNamingConvention Instance = new(); public Regex SplittingExpression { get; } = PascalCase; - public string SeparatorCharacter => string.Empty; - public string ReplaceValue(Match match) - { - var source = match.Value; - return string.Create(source.Length, source, static (buffer, state) => - { - buffer[0] = char.ToUpper(state[0]); - state.AsSpan(1).CopyTo(buffer[1..]); - }); - } + public string SeparatorCharacter => ""; } public class LowerUnderscoreNamingConvention : INamingConvention { @@ -43,6 +31,5 @@ public class LowerUnderscoreNamingConvention : INamingConvention public static readonly LowerUnderscoreNamingConvention Instance = new(); public Regex SplittingExpression { get; } = LowerUnderscore; public string SeparatorCharacter => "_"; - public string ReplaceValue(Match match) => match.Value.ToLower(); } } \ No newline at end of file diff --git a/src/AutoMapper/Configuration/MappingExpression.cs b/src/AutoMapper/Configuration/MappingExpression.cs index 371b118c3c..a15efd1d83 100644 --- a/src/AutoMapper/Configuration/MappingExpression.cs +++ b/src/AutoMapper/Configuration/MappingExpression.cs @@ -60,10 +60,7 @@ public IMappingExpression ForMember(string name, Action {}).Ignore(ignorePaths); - } + protected override void IgnoreDestinationMember(MemberInfo property, bool ignorePaths = true) => ForMember(property, o=>o.Ignore()); internal MemberConfigurationExpression ForMember(MemberInfo destinationProperty, Action memberOptions) { diff --git a/src/AutoMapper/Configuration/MappingExpressionBase.cs b/src/AutoMapper/Configuration/MappingExpressionBase.cs index 4e13c71a01..a89c14d592 100644 --- a/src/AutoMapper/Configuration/MappingExpressionBase.cs +++ b/src/AutoMapper/Configuration/MappingExpressionBase.cs @@ -248,7 +248,7 @@ protected void IncludeBaseCore(Type sourceBase, Type destinationBase) } public IPropertyMapConfiguration GetDestinationMemberConfiguration(MemberInfo destinationMember) => - _memberConfigurations?.FirstOrDefault(m => m.DestinationMember == destinationMember); + _memberConfigurations?.Find(m => m.DestinationMember == destinationMember); protected abstract void IgnoreDestinationMember(MemberInfo property, bool ignorePaths = true); } @@ -442,7 +442,7 @@ public TMappingExpression IgnoreAllSourcePropertiesWithAnInaccessibleSetter() { foreach (var property in PropertiesWithAnInaccessibleSetter(SourceType)) { - ForSourceMember(property.Name, options => options.DoNotValidate()); + ForSourceMemberCore(property, options => options.DoNotValidate()); } return this as TMappingExpression; } diff --git a/src/AutoMapper/ProfileMap.cs b/src/AutoMapper/ProfileMap.cs index a96ddf3928..c2fcac9398 100644 --- a/src/AutoMapper/ProfileMap.cs +++ b/src/AutoMapper/ProfileMap.cs @@ -16,7 +16,8 @@ namespace AutoMapper [DebuggerDisplay("{Name}")] [EditorBrowsable(EditorBrowsableState.Never)] public class ProfileMap - { + { + private static readonly HashSet EmptyHashSet = new(); private ITypeMapConfiguration[] _typeMapConfigs; private Dictionary _openTypeMapConfigs; private Dictionary _typeDetails; @@ -38,13 +39,14 @@ public ProfileMap(IProfileConfiguration profile, IGlobalConfigurationExpression ShouldUseConstructor = profile.ShouldUseConstructor ?? configuration?.ShouldUseConstructor ?? (c => true); ValueTransformers = profile.ValueTransformers.Concat(configuration?.ValueTransformers).ToArray(); _memberConfigurations = profile.MemberConfigurations.Concat(globalProfile?.MemberConfigurations).ToArray(); - var nameSplitMember = _memberConfigurations[0].MemberMappers.OfType().FirstOrDefault(); + var nameSplitMember = (NameSplitMember)_memberConfigurations[0].MemberMappers.Find(m => m is NameSplitMember); if (nameSplitMember != null) { nameSplitMember.SourceMemberNamingConvention = profile.SourceMemberNamingConvention ?? PascalCaseNamingConvention.Instance; nameSplitMember.DestinationMemberNamingConvention = profile.DestinationMemberNamingConvention ?? PascalCaseNamingConvention.Instance; - } - GlobalIgnores = profile.GlobalIgnores.Concat(globalProfile?.GlobalIgnores).ToArray(); + } + var globalIgnores = profile.GlobalIgnores.Concat(globalProfile?.GlobalIgnores); + GlobalIgnores = globalIgnores == Array.Empty() ? EmptyHashSet : new HashSet(globalIgnores); SourceExtensionMethods = profile.SourceExtensionMethods.Concat(globalProfile?.SourceExtensionMethods).ToArray(); AllPropertyMapActions = profile.AllPropertyMapActions.Concat(globalProfile?.AllPropertyMapActions).ToArray(); AllTypeMapActions = profile.AllTypeMapActions.Concat(globalProfile?.AllTypeMapActions).ToArray(); @@ -109,7 +111,7 @@ internal void Clear() public Func ShouldUseConstructor { get; } public IEnumerable> AllPropertyMapActions { get; } public IEnumerable> AllTypeMapActions { get; } - public IReadOnlyCollection GlobalIgnores { get; } + public HashSet GlobalIgnores { get; } public IEnumerable MemberConfigurations => _memberConfigurations; public IEnumerable SourceExtensionMethods { get; } public List Prefixes { get; } From 12eaef9644124b555f3f583c3f51a4bf46b29586 Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Mon, 8 Aug 2022 11:36:18 +0300 Subject: [PATCH 12/67] drop RegEx --- src/AutoMapper/ApiCompatBaseline.txt | 9 ++++- .../Conventions/MemberConfiguration.cs | 29 +++++++------- .../Configuration/INamingConvention.cs | 39 +++++++++++++------ src/UnitTests/Internal/TypeMapFactorySpecs.cs | 6 +-- src/UnitTests/ReverseMapping.cs | 5 +-- 5 files changed, 52 insertions(+), 36 deletions(-) diff --git a/src/AutoMapper/ApiCompatBaseline.txt b/src/AutoMapper/ApiCompatBaseline.txt index 83957ec713..2ad5a15987 100644 --- a/src/AutoMapper/ApiCompatBaseline.txt +++ b/src/AutoMapper/ApiCompatBaseline.txt @@ -1,13 +1,20 @@ Compat issues with assembly AutoMapper: CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'AutoMapper.AutoMapAttribute' changed from '[AttributeUsageAttribute(1036, AllowMultiple=true)]' in the contract to '[AttributeUsageAttribute(AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Struct, AllowMultiple=true)]' in the implementation. MembersMustExist : Member 'public System.String AutoMapper.ExactMatchNamingConvention.ReplaceValue(System.Text.RegularExpressions.Match)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public System.Text.RegularExpressions.Regex AutoMapper.ExactMatchNamingConvention.SplittingExpression.get()' does not exist in the implementation but it does exist in the contract. InterfacesShouldHaveSameMembers : Interface member 'public TMappingExpression AutoMapper.IMappingExpressionBase.AsProxy()' is present in the implementation but not in the contract. InterfacesShouldHaveSameMembers : Interface member 'public void AutoMapper.IMappingExpressionBase.AsProxy()' is present in the contract but not in the implementation. MembersMustExist : Member 'public void AutoMapper.IMappingExpressionBase.AsProxy()' does not exist in the implementation but it does exist in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public System.Text.RegularExpressions.Regex AutoMapper.INamingConvention.SplittingExpression' is present in the contract but not in the implementation. InterfacesShouldHaveSameMembers : Interface member 'public System.String AutoMapper.INamingConvention.ReplaceValue(System.Text.RegularExpressions.Match)' is present in the contract but not in the implementation. MembersMustExist : Member 'public System.String AutoMapper.INamingConvention.ReplaceValue(System.Text.RegularExpressions.Match)' does not exist in the implementation but it does exist in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public System.String[] AutoMapper.INamingConvention.Split(System.String)' is present in the implementation but not in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public System.Text.RegularExpressions.Regex AutoMapper.INamingConvention.SplittingExpression.get()' is present in the contract but not in the implementation. +MembersMustExist : Member 'public System.Text.RegularExpressions.Regex AutoMapper.INamingConvention.SplittingExpression.get()' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.String AutoMapper.LowerUnderscoreNamingConvention.ReplaceValue(System.Text.RegularExpressions.Match)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public System.Text.RegularExpressions.Regex AutoMapper.LowerUnderscoreNamingConvention.SplittingExpression.get()' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.String AutoMapper.PascalCaseNamingConvention.ReplaceValue(System.Text.RegularExpressions.Match)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public System.Text.RegularExpressions.Regex AutoMapper.PascalCaseNamingConvention.SplittingExpression.get()' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public AutoMapper.IMappingOperationOptions AutoMapper.ResolutionContext.Options.get()' does not exist in the implementation but it does exist in the contract. TypesMustExist : Type 'AutoMapper.ValueResolverConfiguration' does not exist in the implementation but it does exist in the contract. InterfacesShouldHaveSameMembers : Default interface member 'public System.Boolean AutoMapper.Configuration.IPropertyMapConfiguration.Ignored' is present in the implementation but not in the contract. @@ -32,4 +39,4 @@ MembersMustExist : Member 'public AutoMapper.Internal.TypePair AutoMapper.Intern MembersMustExist : Member 'public System.Linq.IQueryable AutoMapper.QueryableExtensions.Extensions.Map(System.Linq.IQueryable, System.Linq.IQueryable, AutoMapper.IConfigurationProvider)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Collections.Generic.IReadOnlyCollection AutoMapper.QueryableExtensions.MemberVisitor.MemberPath.get()' does not exist in the implementation but it does exist in the contract. TypesMustExist : Type 'AutoMapper.QueryableExtensions.Impl.MemberAccessQueryMapperVisitor' does not exist in the implementation but it does exist in the contract. -Total Issues: 33 +Total Issues: 40 diff --git a/src/AutoMapper/Configuration/Conventions/MemberConfiguration.cs b/src/AutoMapper/Configuration/Conventions/MemberConfiguration.cs index 41e5180363..3a6f0593bb 100644 --- a/src/AutoMapper/Configuration/Conventions/MemberConfiguration.cs +++ b/src/AutoMapper/Configuration/Conventions/MemberConfiguration.cs @@ -88,29 +88,26 @@ public bool MapDestinationPropertyToSource(ProfileMap options, TypeDetails sourc { var destinationMemberNamingConvention = isReverseMap ? SourceMemberNamingConvention : DestinationMemberNamingConvention; var sourceMemberNamingConvention = isReverseMap ? DestinationMemberNamingConvention : SourceMemberNamingConvention; - var matches = destinationMemberNamingConvention.SplittingExpression?.Matches(nameToSearch); - if (matches == null || matches.Count < 2) + var matches = destinationMemberNamingConvention.Split(nameToSearch); + var length = matches.Length; + var separator = sourceMemberNamingConvention.SeparatorCharacter; + for (var index = 1; index <= length; index++) { - return false; - } - MemberInfo matchingMemberInfo = null; - for (var index = 1; index <= matches.Count; index++) - { - var first = string.Join(sourceMemberNamingConvention.SeparatorCharacter, matches.Take(index).Select(m=>m.Value)); - matchingMemberInfo = parent.NameMapper.GetMatchingMemberInfo(sourceType, destType, destMemberType, first); + var first = string.Join(separator, matches, 0, index); + var matchingMemberInfo = parent.NameMapper.GetMatchingMemberInfo(sourceType, destType, destMemberType, first); if (matchingMemberInfo != null) { resolvers.Add(matchingMemberInfo); var details = options.CreateTypeDetails(matchingMemberInfo.GetMemberType()); - var second = string.Join(sourceMemberNamingConvention.SeparatorCharacter, matches.Skip(index).Select(m=>m.Value)); - var foundMatch = parent.MapDestinationPropertyToSource(options, details, destType, destMemberType, second, resolvers, isReverseMap); - if (!foundMatch) - resolvers.RemoveAt(resolvers.Count - 1); - else - break; + var second = string.Join(separator, matches, index, length - index); + if (parent.MapDestinationPropertyToSource(options, details, destType, destMemberType, second, resolvers, isReverseMap)) + { + return true; + } + resolvers.RemoveAt(resolvers.Count - 1); } } - return matchingMemberInfo != null; + return false; } } } \ No newline at end of file diff --git a/src/AutoMapper/Configuration/INamingConvention.cs b/src/AutoMapper/Configuration/INamingConvention.cs index c00ecc07bc..3b343ff441 100644 --- a/src/AutoMapper/Configuration/INamingConvention.cs +++ b/src/AutoMapper/Configuration/INamingConvention.cs @@ -1,4 +1,5 @@ -using System.Text.RegularExpressions; +using System; +using System.Collections.Generic; namespace AutoMapper { /// @@ -6,30 +7,46 @@ namespace AutoMapper /// public interface INamingConvention { - /// - /// Regular expression on how to tokenize a member - /// - Regex SplittingExpression { get; } + string[] Split(string input); string SeparatorCharacter { get; } } public class ExactMatchNamingConvention : INamingConvention { public static readonly ExactMatchNamingConvention Instance = new(); - public Regex SplittingExpression { get; } - public string SeparatorCharacter => ""; + public string[] Split(string _) => Array.Empty(); + public string SeparatorCharacter => null; } public class PascalCaseNamingConvention : INamingConvention { - private static readonly Regex PascalCase = new(@"(\p{Lu}+(?=$|\p{Lu}[\p{Ll}0-9])|\p{Lu}?[\p{Ll}0-9]+)"); public static readonly PascalCaseNamingConvention Instance = new(); - public Regex SplittingExpression { get; } = PascalCase; public string SeparatorCharacter => ""; + public string[] Split(string input) + { + List result = null; + int lower = 0; + int index = 1; + while (index < input.Length) + { + if (char.IsUpper(input[index])) + { + result ??= new(); + result.Add(input[lower..index]); + lower = index; + } + index++; + } + if (result == null) + { + return Array.Empty(); + } + result.Add(input[lower..index]); + return result.ToArray(); + } } public class LowerUnderscoreNamingConvention : INamingConvention { - private static readonly Regex LowerUnderscore = new(@"[\p{Ll}\p{Lu}0-9]+(?=_?)"); public static readonly LowerUnderscoreNamingConvention Instance = new(); - public Regex SplittingExpression { get; } = LowerUnderscore; public string SeparatorCharacter => "_"; + public string[] Split(string input) => input.Split('_', StringSplitOptions.RemoveEmptyEntries); } } \ No newline at end of file diff --git a/src/UnitTests/Internal/TypeMapFactorySpecs.cs b/src/UnitTests/Internal/TypeMapFactorySpecs.cs index ccb9e767d3..394fbae2ea 100644 --- a/src/UnitTests/Internal/TypeMapFactorySpecs.cs +++ b/src/UnitTests/Internal/TypeMapFactorySpecs.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; using System.Linq; -using System.Reflection; using System.Text.RegularExpressions; using Xunit; using Shouldly; @@ -11,7 +8,6 @@ namespace AutoMapper.UnitTests.Tests { using AutoMapper.Internal; using System; - using Assembly = System.Reflection.Assembly; public class StubNamingConvention : INamingConvention { @@ -26,6 +22,8 @@ public StubNamingConvention(Func replaceFunc) public Regex SplittingExpression { get; set; } public string SeparatorCharacter { get; set; } + public string[] Split(string input) => SplittingExpression.Matches(input).Select(m=>m.Value).ToArray(); + public string ReplaceValue(Match match) { return _replaceFunc(match); diff --git a/src/UnitTests/ReverseMapping.cs b/src/UnitTests/ReverseMapping.cs index ceb69066d3..37a0ef4e9e 100644 --- a/src/UnitTests/ReverseMapping.cs +++ b/src/UnitTests/ReverseMapping.cs @@ -384,10 +384,7 @@ public class UnderscoreNamingConvention : INamingConvention public Regex SplittingExpression { get; } = new Regex(@"\p{Lu}[a-z0-9]*(?=_?)"); public string SeparatorCharacter => "_"; - public string ReplaceValue(Match match) - { - return match.Value; - } + public string[] Split(string input) => SplittingExpression.Matches(input).Select(m => m.Value).ToArray(); } protected override MapperConfiguration CreateConfiguration() => new(cfg => From 06b07133957f74e4e5d57a2e1b5da940159e6788 Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Mon, 8 Aug 2022 12:25:04 +0300 Subject: [PATCH 13/67] docs --- docs/12.0-Upgrade-Guide.md | 7 ++++++- docs/Configuration.md | 10 +++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/docs/12.0-Upgrade-Guide.md b/docs/12.0-Upgrade-Guide.md index b454ada3f8..988678ed0c 100644 --- a/docs/12.0-Upgrade-Guide.md +++ b/docs/12.0-Upgrade-Guide.md @@ -17,4 +17,9 @@ Another possible occurence is with `ForAllMaps` and `ForAllPropertyMaps` when it You should use `ResolutionContext.Items` to access the items passed in the `Map` call. -Instead of `ServiceCtor` you should use dependency injection or pass the needed objects in the `Map` call. \ No newline at end of file +Instead of `ServiceCtor` you should use dependency injection or pass the needed objects in the `Map` call. + +## Naming conventions + +We've simplified the implementation for performance reasons. If that doesn't work for you, you can write your own naming convention. Rather than address every +peculiarity, we prefer to have a simple and fast implementation that covers most cases. \ No newline at end of file diff --git a/docs/Configuration.md b/docs/Configuration.md index faf54664a4..318890ec64 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -93,23 +93,23 @@ You can set the source and destination naming conventions ```c# var configuration = new MapperConfiguration(cfg => { - cfg.SourceMemberNamingConvention = new LowerUnderscoreNamingConvention(); - cfg.DestinationMemberNamingConvention = new PascalCaseNamingConvention(); + cfg.SourceMemberNamingConvention = LowerUnderscoreNamingConvention.Instance; + cfg.DestinationMemberNamingConvention = PascalCaseNamingConvention.Instance; }); ``` This will map the following properties to each other: ` property_name -> PropertyName ` -You can also set this at a per profile level +You can also set this per profile ```c# public class OrganizationProfile : Profile { public OrganizationProfile() { - SourceMemberNamingConvention = new LowerUnderscoreNamingConvention(); - DestinationMemberNamingConvention = new PascalCaseNamingConvention(); + SourceMemberNamingConvention = LowerUnderscoreNamingConvention.Instance; + DestinationMemberNamingConvention = PascalCaseNamingConvention.Instance; //Put your CreateMap... Etc.. here } } From dc7e58f7dcedffb071a262de6cd4afda19acfc7a Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Mon, 8 Aug 2022 13:01:41 +0300 Subject: [PATCH 14/67] cosmetic --- .../Configuration/Conventions/Mappers.cs | 9 +++++---- .../Conventions/MemberConfiguration.cs | 20 +++++++++---------- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/AutoMapper/Configuration/Conventions/Mappers.cs b/src/AutoMapper/Configuration/Conventions/Mappers.cs index bd04abd715..31b0662a08 100644 --- a/src/AutoMapper/Configuration/Conventions/Mappers.cs +++ b/src/AutoMapper/Configuration/Conventions/Mappers.cs @@ -23,14 +23,15 @@ public class ParentSourceToDestinationNameMapper : IParentSourceToDestinationNam public List NamedMappers { get; } = new(){ new DefaultName() }; public MemberInfo GetMatchingMemberInfo(TypeDetails sourceTypeDetails, Type destType, Type destMemberType, string nameToSearch) { - MemberInfo memberInfo = null; foreach (var namedMapper in NamedMappers) { - memberInfo = namedMapper.GetMatchingMemberInfo(sourceTypeDetails, destType, destMemberType, nameToSearch); + var memberInfo = namedMapper.GetMatchingMemberInfo(sourceTypeDetails, destType, destMemberType, nameToSearch); if (memberInfo != null) - break; + { + return memberInfo; + } } - return memberInfo; + return null; } } public class PrePostfixName : ISourceToDestinationNameMapper diff --git a/src/AutoMapper/Configuration/Conventions/MemberConfiguration.cs b/src/AutoMapper/Configuration/Conventions/MemberConfiguration.cs index 3a6f0593bb..95ecf7edb0 100644 --- a/src/AutoMapper/Configuration/Conventions/MemberConfiguration.cs +++ b/src/AutoMapper/Configuration/Conventions/MemberConfiguration.cs @@ -41,18 +41,11 @@ public class MemberConfiguration : IMemberConfiguration { public IParentSourceToDestinationNameMapper NameMapper { get; set; } public List MemberMappers { get; } = new(); - public IMemberConfiguration AddMember(Action setupAction = null) where TMemberMapper : IChildMemberConfiguration, new() - { + public IMemberConfiguration AddMember(Action setupAction = null) where TMemberMapper : IChildMemberConfiguration, new() => GetOrAdd(MemberMappers, setupAction); - return this; - } - public IMemberConfiguration AddName(Action setupAction = null) - where TNameMapper : ISourceToDestinationNameMapper, new() - { + public IMemberConfiguration AddName(Action setupAction = null) where TNameMapper : ISourceToDestinationNameMapper, new() => GetOrAdd(NameMapper.NamedMappers, setupAction); - return this; - } - private void GetOrAdd(IList list, Action setupAction = null) where TMemberMapper : new() + private IMemberConfiguration GetOrAdd(IList list, Action setupAction = null) where TMemberMapper : new() { var child = list.OfType().FirstOrDefault(); if (child == null) @@ -61,6 +54,7 @@ public IMemberConfiguration AddName(Action setupAction list.Add(child); } setupAction?.Invoke(child); + return this; } public MemberConfiguration() { @@ -87,9 +81,13 @@ public class NameSplitMember : IChildMemberConfiguration public bool MapDestinationPropertyToSource(ProfileMap options, TypeDetails sourceType, Type destType, Type destMemberType, string nameToSearch, List resolvers, IMemberConfiguration parent, bool isReverseMap) { var destinationMemberNamingConvention = isReverseMap ? SourceMemberNamingConvention : DestinationMemberNamingConvention; - var sourceMemberNamingConvention = isReverseMap ? DestinationMemberNamingConvention : SourceMemberNamingConvention; var matches = destinationMemberNamingConvention.Split(nameToSearch); var length = matches.Length; + if (length < 2) + { + return false; + } + var sourceMemberNamingConvention = isReverseMap ? DestinationMemberNamingConvention : SourceMemberNamingConvention; var separator = sourceMemberNamingConvention.SeparatorCharacter; for (var index = 1; index <= length; index++) { From 93563888b8e4d934cc89e351fe5d2ae3e88c05da Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Mon, 8 Aug 2022 15:50:01 +0300 Subject: [PATCH 15/67] less allocations --- src/AutoMapper/Configuration/MapperConfiguration.cs | 3 ++- src/AutoMapper/ProfileMap.cs | 12 ++++++------ src/AutoMapper/TypeMap.cs | 6 +++--- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/AutoMapper/Configuration/MapperConfiguration.cs b/src/AutoMapper/Configuration/MapperConfiguration.cs index a90e931c72..b4e659aeab 100644 --- a/src/AutoMapper/Configuration/MapperConfiguration.cs +++ b/src/AutoMapper/Configuration/MapperConfiguration.cs @@ -115,9 +115,10 @@ public MapperConfiguration(MapperConfigurationExpression configurationExpression return; void Seal() { + var sourceMembers = new List(); foreach (var profile in Profiles) { - profile.Register(this); + profile.Register(this, sourceMembers); } foreach (var profile in Profiles) { diff --git a/src/AutoMapper/ProfileMap.cs b/src/AutoMapper/ProfileMap.cs index c2fcac9398..abd4ac520b 100644 --- a/src/AutoMapper/ProfileMap.cs +++ b/src/AutoMapper/ProfileMap.cs @@ -132,14 +132,14 @@ public TypeDetails CreateTypeDetails(Type type) return typeDetails; } private TypeDetails TypeDetailsFactory(Type type) => new(type, this); - public void Register(IGlobalConfiguration configurationProvider) - { + public void Register(IGlobalConfiguration configurationProvider, List sourceMembers) + { foreach (var config in _typeMapConfigs) { - BuildTypeMap(configurationProvider, config); + BuildTypeMap(configurationProvider, config, sourceMembers); if (config.ReverseTypeMap != null) { - BuildTypeMap(configurationProvider, config.ReverseTypeMap); + BuildTypeMap(configurationProvider, config.ReverseTypeMap, sourceMembers); } } } @@ -154,9 +154,9 @@ public void Configure(IGlobalConfiguration configurationProvider) } } } - private void BuildTypeMap(IGlobalConfiguration configurationProvider, ITypeMapConfiguration config) + private void BuildTypeMap(IGlobalConfiguration configurationProvider, ITypeMapConfiguration config, List sourceMembers) { - var typeMap = new TypeMap(config.SourceType, config.DestinationType, this, config); + var typeMap = new TypeMap(config.SourceType, config.DestinationType, this, config, sourceMembers); config.Configure(typeMap); configurationProvider.RegisterTypeMap(typeMap); } diff --git a/src/AutoMapper/TypeMap.cs b/src/AutoMapper/TypeMap.cs index 7a8a56d9c7..00a164194c 100644 --- a/src/AutoMapper/TypeMap.cs +++ b/src/AutoMapper/TypeMap.cs @@ -24,7 +24,7 @@ public class TypeMap private TypeMapDetails _details; private Dictionary _propertyMaps; private bool _sealed; - public TypeMap(Type sourceType, Type destinationType, ProfileMap profile, ITypeMapConfiguration typeMapConfiguration = null) + public TypeMap(Type sourceType, Type destinationType, ProfileMap profile, ITypeMapConfiguration typeMapConfiguration = null, List sourceMembers = null) { Types = new(sourceType, destinationType); Profile = profile; @@ -34,7 +34,7 @@ public TypeMap(Type sourceType, Type destinationType, ProfileMap profile, ITypeM } SourceTypeDetails = profile.CreateTypeDetails(sourceType); DestinationTypeDetails = profile.CreateTypeDetails(destinationType); - var sourceMembers = new List(); + sourceMembers ??= new List(); foreach (var destinationProperty in DestinationTypeDetails.WriteAccessors) { var destinationName = destinationProperty.Name; @@ -149,7 +149,7 @@ public Type MakeGenericType(Type type) => type.IsGenericTypeDefinition ? public IEnumerable GetAllIncludedMembers() => IncludedMembersNames.Length == 0 || SourceType.ContainsGenericParameters ? IncludedMembers : IncludedMembers.Concat(IncludedMembersNames.Select(name => MemberAccessLambda(SourceType, name))); public bool ConstructorParameterMatches(string destinationPropertyName) => ConstructorMapping && ConstructorMap[destinationPropertyName] != null; - private void AddPropertyMap(MemberInfo destProperty, Type destinationPropertyType, IEnumerable sourceMembers) + private void AddPropertyMap(MemberInfo destProperty, Type destinationPropertyType, List sourceMembers) { var propertyMap = new PropertyMap(destProperty, destinationPropertyType, this); propertyMap.MapByConvention(sourceMembers.ToArray()); From 39fccd9580e1dc70661993e77dad6f87790fb0f9 Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Tue, 9 Aug 2022 07:52:24 +0300 Subject: [PATCH 16/67] cosmetic --- src/AutoMapper/Configuration/INamingConvention.cs | 6 ++---- src/AutoMapper/Configuration/Profile.cs | 8 ++++---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/AutoMapper/Configuration/INamingConvention.cs b/src/AutoMapper/Configuration/INamingConvention.cs index 3b343ff441..c724fd107d 100644 --- a/src/AutoMapper/Configuration/INamingConvention.cs +++ b/src/AutoMapper/Configuration/INamingConvention.cs @@ -24,8 +24,7 @@ public string[] Split(string input) { List result = null; int lower = 0; - int index = 1; - while (index < input.Length) + for(int index = 1; index < input.Length; index++) { if (char.IsUpper(input[index])) { @@ -33,13 +32,12 @@ public string[] Split(string input) result.Add(input[lower..index]); lower = index; } - index++; } if (result == null) { return Array.Empty(); } - result.Add(input[lower..index]); + result.Add(input[lower..]); return result.ToArray(); } } diff --git a/src/AutoMapper/Configuration/Profile.cs b/src/AutoMapper/Configuration/Profile.cs index 187772cdbc..f5b10d3eb8 100644 --- a/src/AutoMapper/Configuration/Profile.cs +++ b/src/AutoMapper/Configuration/Profile.cs @@ -63,9 +63,9 @@ public interface IProfileConfiguration /// public abstract class Profile : IProfileExpressionInternal, IProfileConfiguration { - private readonly List _typeMapConfigs = new List(); - private readonly PrePostfixName _prePostfixName = new PrePostfixName(); - private readonly List _memberConfigurations = new List(); + private readonly List _typeMapConfigs = new(); + private readonly PrePostfixName _prePostfixName = new(); + private readonly List _memberConfigurations = new(); private List> _allPropertyMapActions; private List> _allTypeMapActions; private List _globalIgnores; @@ -186,7 +186,7 @@ public void IncludeSourceExtensionMethods(Type type) { _sourceExtensionMethods ??= new(); _sourceExtensionMethods.AddRange( - type.GetMethods(TypeExtensions.StaticFlags).Where(m => m.GetParameters().Length == 1 && m.Has())); + type.GetMethods(TypeExtensions.StaticFlags).Where(m => m.Has() && m.GetParameters().Length == 1)); } } } \ No newline at end of file From a3ae96455a11cb76564cca98357a9c1b3aff2b1b Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Tue, 9 Aug 2022 12:48:35 +0300 Subject: [PATCH 17/67] less allocations --- docs/12.0-Upgrade-Guide.md | 2 +- src/AutoMapper/ApiCompatBaseline.txt | 3 ++- .../Configuration/MapperConfiguration.cs | 6 ++++-- .../Configuration/MappingExpressionBase.cs | 10 +++++----- src/AutoMapper/Internal/InternalApi.cs | 2 ++ src/AutoMapper/ProfileMap.cs | 17 +++++++++-------- src/AutoMapper/TypeMap.cs | 2 +- 7 files changed, 24 insertions(+), 18 deletions(-) diff --git a/docs/12.0-Upgrade-Guide.md b/docs/12.0-Upgrade-Guide.md index 988678ed0c..580e213d93 100644 --- a/docs/12.0-Upgrade-Guide.md +++ b/docs/12.0-Upgrade-Guide.md @@ -17,7 +17,7 @@ Another possible occurence is with `ForAllMaps` and `ForAllPropertyMaps` when it You should use `ResolutionContext.Items` to access the items passed in the `Map` call. -Instead of `ServiceCtor` you should use dependency injection or pass the needed objects in the `Map` call. +Instead of `ServiceCtor`, you should use dependency injection or pass the needed objects in the `Map` call. ## Naming conventions diff --git a/src/AutoMapper/ApiCompatBaseline.txt b/src/AutoMapper/ApiCompatBaseline.txt index 2ad5a15987..f5433ce3ab 100644 --- a/src/AutoMapper/ApiCompatBaseline.txt +++ b/src/AutoMapper/ApiCompatBaseline.txt @@ -19,6 +19,7 @@ MembersMustExist : Member 'public AutoMapper.IMappingOperationOptions AutoMapper TypesMustExist : Type 'AutoMapper.ValueResolverConfiguration' does not exist in the implementation but it does exist in the contract. InterfacesShouldHaveSameMembers : Default interface member 'public System.Boolean AutoMapper.Configuration.IPropertyMapConfiguration.Ignored' is present in the implementation but not in the contract. InterfacesShouldHaveSameMembers : Default interface member 'public System.Boolean AutoMapper.Configuration.IPropertyMapConfiguration.Ignored.get()' is present in the implementation but not in the contract. +MembersMustExist : Member 'public void AutoMapper.Configuration.MappingExpressionBase.Configure(AutoMapper.TypeMap)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public void AutoMapper.Configuration.MappingExpressionBase.AsProxy()' does not exist in the implementation but it does exist in the contract. CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'AutoMapper.Configuration.Annotations.IgnoreAttribute' changed from '[AttributeUsageAttribute(384)]' in the contract to '[AttributeUsageAttribute(AttributeTargets.Field | AttributeTargets.Property)]' in the implementation. CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'AutoMapper.Configuration.Annotations.MapAtRuntimeAttribute' changed from '[AttributeUsageAttribute(384)]' in the contract to '[AttributeUsageAttribute(AttributeTargets.Field | AttributeTargets.Property)]' in the implementation. @@ -39,4 +40,4 @@ MembersMustExist : Member 'public AutoMapper.Internal.TypePair AutoMapper.Intern MembersMustExist : Member 'public System.Linq.IQueryable AutoMapper.QueryableExtensions.Extensions.Map(System.Linq.IQueryable, System.Linq.IQueryable, AutoMapper.IConfigurationProvider)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Collections.Generic.IReadOnlyCollection AutoMapper.QueryableExtensions.MemberVisitor.MemberPath.get()' does not exist in the implementation but it does exist in the contract. TypesMustExist : Type 'AutoMapper.QueryableExtensions.Impl.MemberAccessQueryMapperVisitor' does not exist in the implementation but it does exist in the contract. -Total Issues: 40 +Total Issues: 41 diff --git a/src/AutoMapper/Configuration/MapperConfiguration.cs b/src/AutoMapper/Configuration/MapperConfiguration.cs index b4e659aeab..2a24a9006b 100644 --- a/src/AutoMapper/Configuration/MapperConfiguration.cs +++ b/src/AutoMapper/Configuration/MapperConfiguration.cs @@ -56,6 +56,7 @@ public class MapperConfiguration : IGlobalConfiguration private readonly Dictionary _configuredMaps; private readonly Dictionary _resolvedMaps; private HashSet _typeMapsPath = new(); + private List _sourceMembers = new(); private readonly LockingConcurrentDictionary _runtimeMaps; private readonly ProjectionBuilder _projectionBuilder; private readonly LockingConcurrentDictionary _executionPlans; @@ -111,14 +112,14 @@ public MapperConfiguration(MapperConfigurationExpression configurationExpression profile.Clear(); } _typeMapsPath = null; + _sourceMembers = null; _sealed = true; return; void Seal() { - var sourceMembers = new List(); foreach (var profile in Profiles) { - profile.Register(this, sourceMembers); + profile.Register(this); } foreach (var profile in Profiles) { @@ -257,6 +258,7 @@ static MapperConfigurationExpression Build(Action _recursiveQueriesMaxDepth; Features IGlobalConfiguration.Features => _features; + List IGlobalConfiguration.SourceMembers => _sourceMembers; Func IGlobalConfiguration.GetExecutionPlan(in MapRequest mapRequest) => (Func)GetExecutionPlan(mapRequest); private Delegate GetExecutionPlan(in MapRequest mapRequest) => _executionPlans.GetOrAdd(mapRequest); diff --git a/src/AutoMapper/Configuration/MappingExpressionBase.cs b/src/AutoMapper/Configuration/MappingExpressionBase.cs index a89c14d592..f1fa0f83d8 100644 --- a/src/AutoMapper/Configuration/MappingExpressionBase.cs +++ b/src/AutoMapper/Configuration/MappingExpressionBase.cs @@ -13,7 +13,7 @@ namespace AutoMapper.Configuration [EditorBrowsable(EditorBrowsableState.Never)] public interface ITypeMapConfiguration { - void Configure(TypeMap typeMap); + void Configure(TypeMap typeMap, List sourceMembers); Type SourceType { get; } Type DestinationType { get; } bool IsReverseMap { get; } @@ -56,7 +56,7 @@ protected MappingExpressionBase(MemberList memberList, TypePair types) protected List MemberConfigurations => _memberConfigurations ??= new(); protected List SourceMemberConfigurations => _sourceMemberConfigurations ??= new(); protected List CtorParamConfigurations => _ctorParamConfigurations ??= new(); - public void Configure(TypeMap typeMap) + public void Configure(TypeMap typeMap, List sourceMembers) { TypeMap = typeMap; typeMap.Projection = Projection; @@ -67,7 +67,7 @@ public void Configure(TypeMap typeMap) } if (typeMap.ConstructorMap == null && typeMap.CanConstructorMap()) { - MapDestinationCtorToSource(typeMap); + MapDestinationCtorToSource(typeMap, sourceMembers); } if (_memberConfigurations != null) { @@ -147,9 +147,9 @@ private void ConfigureReverseMap(TypeMap typeMap) ReverseIncludedMembers(typeMap); } - private void MapDestinationCtorToSource(TypeMap typeMap) + private void MapDestinationCtorToSource(TypeMap typeMap, List sourceMembers) { - var sourceMembers = new List(); + sourceMembers ??= new(); ConstructorMap ctorMap = new(); typeMap.ConstructorMap = ctorMap; foreach (var destCtor in typeMap.DestinationConstructors) diff --git a/src/AutoMapper/Internal/InternalApi.cs b/src/AutoMapper/Internal/InternalApi.cs index 4c5bed334a..8a0bd0ea3d 100644 --- a/src/AutoMapper/Internal/InternalApi.cs +++ b/src/AutoMapper/Internal/InternalApi.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.ComponentModel; using System.Linq.Expressions; +using System.Reflection; using AutoMapper.Configuration; using AutoMapper.Configuration.Conventions; using AutoMapper.Features; @@ -154,6 +155,7 @@ public interface IGlobalConfiguration : IConfigurationProvider TypeMap GetIncludedTypeMap(Type sourceType, Type destinationType); TypeMap[] GetIncludedTypeMaps(IReadOnlyCollection includedTypes); void Seal(TypeMap typeMap); + List SourceMembers { get; } } [EditorBrowsable(EditorBrowsableState.Never)] public interface IProfileExpressionInternal : IProfileExpression diff --git a/src/AutoMapper/ProfileMap.cs b/src/AutoMapper/ProfileMap.cs index abd4ac520b..c3f8e586b9 100644 --- a/src/AutoMapper/ProfileMap.cs +++ b/src/AutoMapper/ProfileMap.cs @@ -132,14 +132,14 @@ public TypeDetails CreateTypeDetails(Type type) return typeDetails; } private TypeDetails TypeDetailsFactory(Type type) => new(type, this); - public void Register(IGlobalConfiguration configurationProvider, List sourceMembers) + public void Register(IGlobalConfiguration configurationProvider) { foreach (var config in _typeMapConfigs) { - BuildTypeMap(configurationProvider, config, sourceMembers); + BuildTypeMap(configurationProvider, config); if (config.ReverseTypeMap != null) { - BuildTypeMap(configurationProvider, config.ReverseTypeMap, sourceMembers); + BuildTypeMap(configurationProvider, config.ReverseTypeMap); } } } @@ -154,10 +154,11 @@ public void Configure(IGlobalConfiguration configurationProvider) } } } - private void BuildTypeMap(IGlobalConfiguration configurationProvider, ITypeMapConfiguration config, List sourceMembers) - { + private void BuildTypeMap(IGlobalConfiguration configurationProvider, ITypeMapConfiguration config) + { + var sourceMembers = configurationProvider.SourceMembers; var typeMap = new TypeMap(config.SourceType, config.DestinationType, this, config, sourceMembers); - config.Configure(typeMap); + config.Configure(typeMap, sourceMembers); configurationProvider.RegisterTypeMap(typeMap); } private void Configure(ITypeMapConfiguration typeMapConfiguration, IGlobalConfiguration configurationProvider) @@ -185,7 +186,7 @@ private void Configure(TypeMap typeMap, IGlobalConfiguration configurationProvid { var expression = new MappingExpression(typeMap.Types, typeMap.ConfiguredMemberList); action(typeMap, expression); - expression.Configure(typeMap); + expression.Configure(typeMap, configurationProvider.SourceMembers); } foreach (var action in AllPropertyMapActions) { @@ -207,7 +208,7 @@ public TypeMap CreateClosedGenericTypeMap(ITypeMapConfiguration openMapConfig, T { closedMap = new TypeMap(closedTypes.SourceType, closedTypes.DestinationType, this, openMapConfig); } - openMapConfig.Configure(closedMap); + openMapConfig.Configure(closedMap, configurationProvider.SourceMembers); Configure(closedMap, configurationProvider); closedMap.CloseGenerics(openMapConfig, closedTypes); return closedMap; diff --git a/src/AutoMapper/TypeMap.cs b/src/AutoMapper/TypeMap.cs index 00a164194c..2f23d676da 100644 --- a/src/AutoMapper/TypeMap.cs +++ b/src/AutoMapper/TypeMap.cs @@ -34,7 +34,7 @@ public TypeMap(Type sourceType, Type destinationType, ProfileMap profile, ITypeM } SourceTypeDetails = profile.CreateTypeDetails(sourceType); DestinationTypeDetails = profile.CreateTypeDetails(destinationType); - sourceMembers ??= new List(); + sourceMembers ??= new(); foreach (var destinationProperty in DestinationTypeDetails.WriteAccessors) { var destinationName = destinationProperty.Name; From 00d29ee6605f57a080ee20ff40eccb39a4da8026 Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Thu, 11 Aug 2022 16:09:27 +0300 Subject: [PATCH 18/67] we don't need to create As type maps --- .../Configuration/MapperConfiguration.cs | 20 ++-------- .../Configuration/MappingExpressionBase.cs | 21 +++++----- src/AutoMapper/Internal/InternalApi.cs | 1 + src/AutoMapper/ProfileMap.cs | 38 ++++++++++++------- src/AutoMapper/TypeMap.cs | 23 +---------- 5 files changed, 42 insertions(+), 61 deletions(-) diff --git a/src/AutoMapper/Configuration/MapperConfiguration.cs b/src/AutoMapper/Configuration/MapperConfiguration.cs index 2a24a9006b..9d7297eb5f 100644 --- a/src/AutoMapper/Configuration/MapperConfiguration.cs +++ b/src/AutoMapper/Configuration/MapperConfiguration.cs @@ -18,20 +18,17 @@ public interface IConfigurationProvider /// Dry run all configured type maps and throw for each problem /// void AssertConfigurationIsValid(); - /// /// Create a mapper instance based on this configuration. Mapper instances are lightweight and can be created as needed. /// /// The mapper instance IMapper CreateMapper(); - /// /// Create a mapper instance with the specified service constructor to be used for resolvers and type converters. /// /// Service factory to create services /// The mapper instance IMapper CreateMapper(Func serviceCtor); - /// /// Builds the execution plan used to map the source to destination. /// Useful to understand what exactly is happening during mapping. @@ -41,7 +38,6 @@ public interface IConfigurationProvider /// the runtime type of the destination object /// the execution plan LambdaExpression BuildExecutionPlan(Type sourceType, Type destinationType); - /// /// Compile all underlying mapping expressions to cached delegates. /// Use if you want AutoMapper to compile all mappings up front instead of deferring expression compilation for each first map. @@ -51,7 +47,6 @@ public interface IConfigurationProvider public class MapperConfiguration : IGlobalConfiguration { private static readonly MethodInfo MappingError = typeof(MapperConfiguration).GetMethod(nameof(GetMappingError)); - private readonly IObjectMapper[] _mappers; private readonly Dictionary _configuredMaps; private readonly Dictionary _resolvedMaps; @@ -68,7 +63,6 @@ public class MapperConfiguration : IGlobalConfiguration private readonly Func _serviceCtor; private readonly bool _sealed; private readonly bool _hasOpenMaps; - public MapperConfiguration(MapperConfigurationExpression configurationExpression) { var configuration = (IGlobalConfigurationExpression)configurationExpression; @@ -129,15 +123,7 @@ void Seal() var derivedMaps = new List(); foreach (var typeMap in _configuredMaps.Values) { - if (typeMap.DestinationTypeOverride != null) - { - var derivedMap = globalConfiguration.GetIncludedTypeMap(typeMap.AsPair()); - _resolvedMaps[typeMap.Types] = derivedMap; - } - else - { - _resolvedMaps[typeMap.Types] = typeMap; - } + _resolvedMaps[typeMap.Types] = typeMap; derivedMaps.Clear(); GetDerivedTypeMaps(typeMap, derivedMaps); foreach (var derivedMap in derivedMaps) @@ -387,7 +373,7 @@ TypeMap FindClosedGenericMap(TypePair typePair) ProfileMap profile; TypeMap cachedMap; TypePair closedTypes; - if (userMap != null && userMap.DestinationTypeOverride == null) + if (userMap != null) { genericMapConfig = userMap.Profile.GetGenericMap(userMap.Types); profile = userMap.Profile; @@ -475,5 +461,7 @@ void IGlobalConfiguration.AssertConfigurationIsValid(string profileName) } void IGlobalConfiguration.AssertConfigurationIsValid() => this.Internal().AssertConfigurationIsValid(typeof(TProfile).FullName); void IGlobalConfiguration.Seal(TypeMap typeMap) => typeMap.Seal(this, _typeMapsPath); + void IGlobalConfiguration.RegisterAsMap(ITypeMapConfiguration typeMapConfiguration) => + _resolvedMaps[typeMapConfiguration.Types] = GetIncludedTypeMap(new(typeMapConfiguration.SourceType, typeMapConfiguration.DestinationTypeOverride)); } } \ No newline at end of file diff --git a/src/AutoMapper/Configuration/MappingExpressionBase.cs b/src/AutoMapper/Configuration/MappingExpressionBase.cs index f1fa0f83d8..560e7b16c8 100644 --- a/src/AutoMapper/Configuration/MappingExpressionBase.cs +++ b/src/AutoMapper/Configuration/MappingExpressionBase.cs @@ -16,6 +16,7 @@ public interface ITypeMapConfiguration void Configure(TypeMap typeMap, List sourceMembers); Type SourceType { get; } Type DestinationType { get; } + Type DestinationTypeOverride { get; } bool IsReverseMap { get; } TypePair Types { get; } ITypeMapConfiguration ReverseTypeMap { get; } @@ -41,6 +42,7 @@ protected MappingExpressionBase(MemberList memberList, TypePair types) _memberList = memberList; _types = types; } + public Type DestinationTypeOverride { get; private set; } protected bool Projection { get; set; } public TypePair Types => _types; public bool IsReverseMap { get; set; } @@ -56,6 +58,15 @@ protected MappingExpressionBase(MemberList memberList, TypePair types) protected List MemberConfigurations => _memberConfigurations ??= new(); protected List SourceMemberConfigurations => _sourceMemberConfigurations ??= new(); protected List CtorParamConfigurations => _ctorParamConfigurations ??= new(); + public void As(Type typeOverride) + { + if (typeOverride == DestinationType) + { + throw new InvalidOperationException("As must specify a derived type, not " + DestinationType); + } + typeOverride.CheckIsDerivedFrom(DestinationType); + DestinationTypeOverride = typeOverride; + } public void Configure(TypeMap typeMap, List sourceMembers) { TypeMap = typeMap; @@ -369,16 +380,6 @@ public TMappingExpression ForSourceMember(string sourceMemberName, Action tm.DestinationTypeOverride = typeOverride); - } - public TMappingExpression ConstructUsing(Expression> ctor) => ConstructUsingCore(ctor); private TMappingExpression ConstructUsingCore(LambdaExpression ctor) diff --git a/src/AutoMapper/Internal/InternalApi.cs b/src/AutoMapper/Internal/InternalApi.cs index 8a0bd0ea3d..98d2e962ef 100644 --- a/src/AutoMapper/Internal/InternalApi.cs +++ b/src/AutoMapper/Internal/InternalApi.cs @@ -155,6 +155,7 @@ public interface IGlobalConfiguration : IConfigurationProvider TypeMap GetIncludedTypeMap(Type sourceType, Type destinationType); TypeMap[] GetIncludedTypeMaps(IReadOnlyCollection includedTypes); void Seal(TypeMap typeMap); + void RegisterAsMap(ITypeMapConfiguration typeMapConfiguration); List SourceMembers { get; } } [EditorBrowsable(EditorBrowsableState.Never)] diff --git a/src/AutoMapper/ProfileMap.cs b/src/AutoMapper/ProfileMap.cs index c3f8e586b9..8ca5a24bcc 100644 --- a/src/AutoMapper/ProfileMap.cs +++ b/src/AutoMapper/ProfileMap.cs @@ -135,32 +135,42 @@ public TypeDetails CreateTypeDetails(Type type) public void Register(IGlobalConfiguration configurationProvider) { foreach (var config in _typeMapConfigs) - { - BuildTypeMap(configurationProvider, config); - if (config.ReverseTypeMap != null) + { + if (config.DestinationTypeOverride == null) { - BuildTypeMap(configurationProvider, config.ReverseTypeMap); + BuildTypeMap(configurationProvider, config); + if (config.ReverseTypeMap != null) + { + BuildTypeMap(configurationProvider, config.ReverseTypeMap); + } } } } + private void BuildTypeMap(IGlobalConfiguration configurationProvider, ITypeMapConfiguration config) + { + var sourceMembers = configurationProvider.SourceMembers; + var typeMap = new TypeMap(config.SourceType, config.DestinationType, this, config, sourceMembers); + config.Configure(typeMap, sourceMembers); + configurationProvider.RegisterTypeMap(typeMap); + } public void Configure(IGlobalConfiguration configurationProvider) { foreach (var typeMapConfiguration in _typeMapConfigs) { - Configure(typeMapConfiguration, configurationProvider); - if (typeMapConfiguration.ReverseTypeMap != null) + if (typeMapConfiguration.DestinationTypeOverride == null) { - Configure(typeMapConfiguration.ReverseTypeMap, configurationProvider); + Configure(typeMapConfiguration, configurationProvider); + if (typeMapConfiguration.ReverseTypeMap != null) + { + Configure(typeMapConfiguration.ReverseTypeMap, configurationProvider); + } + } + else + { + configurationProvider.RegisterAsMap(typeMapConfiguration); } } } - private void BuildTypeMap(IGlobalConfiguration configurationProvider, ITypeMapConfiguration config) - { - var sourceMembers = configurationProvider.SourceMembers; - var typeMap = new TypeMap(config.SourceType, config.DestinationType, this, config, sourceMembers); - config.Configure(typeMap, sourceMembers); - configurationProvider.RegisterTypeMap(typeMap); - } private void Configure(ITypeMapConfiguration typeMapConfiguration, IGlobalConfiguration configurationProvider) { var typeMap = typeMapConfiguration.TypeMap; diff --git a/src/AutoMapper/TypeMap.cs b/src/AutoMapper/TypeMap.cs index 2f23d676da..dbfbe35935 100644 --- a/src/AutoMapper/TypeMap.cs +++ b/src/AutoMapper/TypeMap.cs @@ -80,15 +80,6 @@ internal bool CanConstructorMap() => Profile.ConstructorMappingEnabled && !Desti public LambdaExpression CustomMapExpression => TypeConverter?.ProjectToExpression; public LambdaExpression CustomCtorFunction { get => _details?.CustomCtorFunction; set => Details.CustomCtorFunction = value; } public LambdaExpression CustomCtorExpression => CustomCtorFunction?.Parameters.Count == 1 ? CustomCtorFunction : null; - public Type DestinationTypeOverride - { - get => _details?.DestinationTypeOverride; - set - { - Details.DestinationTypeOverride = value; - _sealed = true; - } - } public bool IncludeAllDerivedTypes { get => (_details?.IncludeAllDerivedTypes).GetValueOrDefault(); set => Details.IncludeAllDerivedTypes = value; } public MemberList ConfiguredMemberList { @@ -138,7 +129,7 @@ public IEnumerable MemberMaps public bool CustomConstruction => CustomCtorFunction != null; public bool HasTypeConverter => TypeConverter != null; public TypeConverter TypeConverter { get; set; } - public bool ShouldCheckForValid => !HasTypeConverter && DestinationTypeOverride == null && ConfiguredMemberList != MemberList.None; + public bool ShouldCheckForValid => ConfiguredMemberList != MemberList.None && !HasTypeConverter; public LambdaExpression[] IncludedMembers { get => _details?.IncludedMembers ?? Array.Empty(); set => Details.IncludedMembers = value; } public string[] IncludedMembersNames { get => _details?.IncludedMembersNames ?? Array.Empty(); set => Details.IncludedMembersNames = value; } public IReadOnlyCollection IncludedMembersTypeMaps => (_details?.IncludedMembersTypeMaps).NullCheck(); @@ -196,7 +187,6 @@ public PropertyMap FindOrCreatePropertyMapFor(MemberInfo destinationProperty, Ty AddPropertyMap(propertyMap); return propertyMap; } - public TypePair AsPair() => new(SourceType, DestinationTypeOverride); private void CheckDifferent(TypePair types) { if (types == Types) @@ -280,15 +270,7 @@ internal void CopyInheritedMapsTo(TypeMap typeMap) } _details.CopyInheritedMapsTo(typeMap); } - public void CloseGenerics(ITypeMapConfiguration openMapConfig, TypePair closedTypes) - { - TypeConverter?.CloseGenerics(openMapConfig, closedTypes); - if (DestinationTypeOverride is { IsGenericTypeDefinition: true }) - { - var neededParameters = DestinationTypeOverride.GenericParametersCount(); - DestinationTypeOverride = DestinationTypeOverride.MakeGenericType(closedTypes.DestinationType.GenericTypeArguments.Take(neededParameters).ToArray()); - } - } + public void CloseGenerics(ITypeMapConfiguration openMapConfig, TypePair closedTypes) => TypeConverter?.CloseGenerics(openMapConfig, closedTypes); public bool AddMemberMap(IncludedMember includedMember) => Details.AddMemberMap(includedMember); public PathMap FindOrCreatePathMapFor(LambdaExpression destinationExpression, MemberPath path, TypeMap typeMap) => Details.FindOrCreatePathMapFor(destinationExpression, path, typeMap); @@ -305,7 +287,6 @@ class TypeMapDetails public bool IncludeAllDerivedTypes; public LambdaExpression CustomCtorFunction; public MemberList ConfiguredMemberList; - public Type DestinationTypeOverride; public HashSet AfterMapActions { get; private set; } public HashSet BeforeMapActions { get; private set; } public HashSet IncludedDerivedTypes { get; private set; } From c9bceefb7a71425b6931429720598036857612f7 Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Thu, 11 Aug 2022 16:28:37 +0300 Subject: [PATCH 19/67] remove ITypeMapConfiguration --- src/AutoMapper/ApiCompatBaseline.txt | 13 +- .../Configuration/MapperConfiguration.cs | 4 +- .../Configuration/MappingExpression.cs | 70 ++-------- src/AutoMapper/Configuration/Profile.cs | 12 +- ...ressionBase.cs => TypeMapConfiguration.cs} | 130 +++--------------- .../Execution/TypeMapPlanBuilder.cs | 4 +- src/AutoMapper/Internal/InternalApi.cs | 2 +- src/AutoMapper/ProfileMap.cs | 14 +- src/AutoMapper/TypeMap.cs | 4 +- 9 files changed, 60 insertions(+), 193 deletions(-) rename src/AutoMapper/Configuration/{MappingExpressionBase.cs => TypeMapConfiguration.cs} (90%) diff --git a/src/AutoMapper/ApiCompatBaseline.txt b/src/AutoMapper/ApiCompatBaseline.txt index f5433ce3ab..e7886b6737 100644 --- a/src/AutoMapper/ApiCompatBaseline.txt +++ b/src/AutoMapper/ApiCompatBaseline.txt @@ -11,6 +11,12 @@ MembersMustExist : Member 'public System.String AutoMapper.INamingConvention.Rep InterfacesShouldHaveSameMembers : Interface member 'public System.String[] AutoMapper.INamingConvention.Split(System.String)' is present in the implementation but not in the contract. InterfacesShouldHaveSameMembers : Interface member 'public System.Text.RegularExpressions.Regex AutoMapper.INamingConvention.SplittingExpression.get()' is present in the contract but not in the implementation. MembersMustExist : Member 'public System.Text.RegularExpressions.Regex AutoMapper.INamingConvention.SplittingExpression.get()' does not exist in the implementation but it does exist in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public System.Collections.Generic.IReadOnlyCollection AutoMapper.IProfileConfiguration.OpenTypeMapConfigs.get()' is present in the implementation but not in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public System.Collections.Generic.IReadOnlyCollection AutoMapper.IProfileConfiguration.OpenTypeMapConfigs.get()' is present in the contract but not in the implementation. +MembersMustExist : Member 'public System.Collections.Generic.IReadOnlyCollection AutoMapper.IProfileConfiguration.OpenTypeMapConfigs.get()' does not exist in the implementation but it does exist in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public System.Collections.Generic.IReadOnlyCollection AutoMapper.IProfileConfiguration.TypeMapConfigs.get()' is present in the implementation but not in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public System.Collections.Generic.IReadOnlyCollection AutoMapper.IProfileConfiguration.TypeMapConfigs.get()' is present in the contract but not in the implementation. +MembersMustExist : Member 'public System.Collections.Generic.IReadOnlyCollection AutoMapper.IProfileConfiguration.TypeMapConfigs.get()' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.String AutoMapper.LowerUnderscoreNamingConvention.ReplaceValue(System.Text.RegularExpressions.Match)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Text.RegularExpressions.Regex AutoMapper.LowerUnderscoreNamingConvention.SplittingExpression.get()' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.String AutoMapper.PascalCaseNamingConvention.ReplaceValue(System.Text.RegularExpressions.Match)' does not exist in the implementation but it does exist in the contract. @@ -19,7 +25,10 @@ MembersMustExist : Member 'public AutoMapper.IMappingOperationOptions AutoMapper TypesMustExist : Type 'AutoMapper.ValueResolverConfiguration' does not exist in the implementation but it does exist in the contract. InterfacesShouldHaveSameMembers : Default interface member 'public System.Boolean AutoMapper.Configuration.IPropertyMapConfiguration.Ignored' is present in the implementation but not in the contract. InterfacesShouldHaveSameMembers : Default interface member 'public System.Boolean AutoMapper.Configuration.IPropertyMapConfiguration.Ignored.get()' is present in the implementation but not in the contract. -MembersMustExist : Member 'public void AutoMapper.Configuration.MappingExpressionBase.Configure(AutoMapper.TypeMap)' does not exist in the implementation but it does exist in the contract. +CannotRemoveBaseTypeOrInterface : Type 'AutoMapper.Configuration.MappingExpression' does not inherit from base type 'AutoMapper.Configuration.MappingExpressionBase' in the implementation but it does in the contract. +CannotRemoveBaseTypeOrInterface : Type 'AutoMapper.Configuration.MappingExpression' does not inherit from base type 'AutoMapper.Configuration.MappingExpressionBase' in the implementation but it does in the contract. +TypesMustExist : Type 'AutoMapper.Configuration.MappingExpressionBase' does not exist in the implementation but it does exist in the contract. +CannotRemoveBaseTypeOrInterface : Type 'AutoMapper.Configuration.MappingExpressionBase' does not inherit from base type 'AutoMapper.Configuration.MappingExpressionBase' in the implementation but it does in the contract. MembersMustExist : Member 'public void AutoMapper.Configuration.MappingExpressionBase.AsProxy()' does not exist in the implementation but it does exist in the contract. CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'AutoMapper.Configuration.Annotations.IgnoreAttribute' changed from '[AttributeUsageAttribute(384)]' in the contract to '[AttributeUsageAttribute(AttributeTargets.Field | AttributeTargets.Property)]' in the implementation. CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'AutoMapper.Configuration.Annotations.MapAtRuntimeAttribute' changed from '[AttributeUsageAttribute(384)]' in the contract to '[AttributeUsageAttribute(AttributeTargets.Field | AttributeTargets.Property)]' in the implementation. @@ -40,4 +49,4 @@ MembersMustExist : Member 'public AutoMapper.Internal.TypePair AutoMapper.Intern MembersMustExist : Member 'public System.Linq.IQueryable AutoMapper.QueryableExtensions.Extensions.Map(System.Linq.IQueryable, System.Linq.IQueryable, AutoMapper.IConfigurationProvider)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Collections.Generic.IReadOnlyCollection AutoMapper.QueryableExtensions.MemberVisitor.MemberPath.get()' does not exist in the implementation but it does exist in the contract. TypesMustExist : Type 'AutoMapper.QueryableExtensions.Impl.MemberAccessQueryMapperVisitor' does not exist in the implementation but it does exist in the contract. -Total Issues: 41 +Total Issues: 50 diff --git a/src/AutoMapper/Configuration/MapperConfiguration.cs b/src/AutoMapper/Configuration/MapperConfiguration.cs index 9d7297eb5f..322f0a6247 100644 --- a/src/AutoMapper/Configuration/MapperConfiguration.cs +++ b/src/AutoMapper/Configuration/MapperConfiguration.cs @@ -369,7 +369,7 @@ TypeMap FindClosedGenericMap(TypePair typePair) FindTypeMapFor(genericTypePair.SourceType, typePair.DestinationType) ?? FindTypeMapFor(typePair.SourceType, genericTypePair.DestinationType) ?? FindTypeMapFor(genericTypePair); - ITypeMapConfiguration genericMapConfig; + TypeMapConfiguration genericMapConfig; ProfileMap profile; TypeMap cachedMap; TypePair closedTypes; @@ -461,7 +461,7 @@ void IGlobalConfiguration.AssertConfigurationIsValid(string profileName) } void IGlobalConfiguration.AssertConfigurationIsValid() => this.Internal().AssertConfigurationIsValid(typeof(TProfile).FullName); void IGlobalConfiguration.Seal(TypeMap typeMap) => typeMap.Seal(this, _typeMapsPath); - void IGlobalConfiguration.RegisterAsMap(ITypeMapConfiguration typeMapConfiguration) => + void IGlobalConfiguration.RegisterAsMap(TypeMapConfiguration typeMapConfiguration) => _resolvedMaps[typeMapConfiguration.Types] = GetIncludedTypeMap(new(typeMapConfiguration.SourceType, typeMapConfiguration.DestinationTypeOverride)); } } \ No newline at end of file diff --git a/src/AutoMapper/Configuration/MappingExpression.cs b/src/AutoMapper/Configuration/MappingExpression.cs index a15efd1d83..c86ec898be 100644 --- a/src/AutoMapper/Configuration/MappingExpression.cs +++ b/src/AutoMapper/Configuration/MappingExpression.cs @@ -3,18 +3,13 @@ using System.Linq.Expressions; using System.Reflection; using AutoMapper.Internal; - namespace AutoMapper.Configuration { using Execution; public class MappingExpression : MappingExpressionBase, IMappingExpression { - public MappingExpression(TypePair types, MemberList memberList) : base(memberList, types) - { - } - + public MappingExpression(TypePair types, MemberList memberList) : base(memberList, types){} public string[] IncludedMembersNames { get; internal set; } = Array.Empty(); - public IMappingExpression ReverseMap() { var reversedTypes = new TypePair(DestinationType, SourceType); @@ -30,7 +25,6 @@ public IMappingExpression ReverseMap() } return reverseMap; } - public IMappingExpression IncludeMembers(params string[] memberNames) { IncludedMembersNames = memberNames; @@ -41,7 +35,6 @@ public IMappingExpression IncludeMembers(params string[] memberNames) TypeMapActions.Add(tm => tm.IncludedMembersNames = memberNames); return this; } - public void ForAllMembers(Action memberOptions) { TypeMapActions.Add(typeMap => @@ -52,32 +45,23 @@ public void ForAllMembers(Action memberOptions) } }); } - public IMappingExpression ForMember(string name, Action memberOptions) { var member = DestinationType.GetFieldOrProperty(name); ForMember(member, memberOptions); return this; } - protected override void IgnoreDestinationMember(MemberInfo property, bool ignorePaths = true) => ForMember(property, o=>o.Ignore()); - internal MemberConfigurationExpression ForMember(MemberInfo destinationProperty, Action memberOptions) { var expression = new MemberConfigurationExpression(destinationProperty, SourceType); - MemberConfigurations.Add(expression); - memberOptions(expression); - return expression; } - public class MemberConfigurationExpression : MemberConfigurationExpression, IMemberConfigurationExpression { - public MemberConfigurationExpression(MemberInfo destinationMember, Type sourceType) : base(destinationMember, sourceType) - { - } + public MemberConfigurationExpression(MemberInfo destinationMember, Type sourceType) : base(destinationMember, sourceType){} public void MapFrom(Type valueResolverType) => MapFromCore(new(valueResolverType, valueResolverType.GetGenericInterface(typeof(IValueResolver<,,>)))); public void MapFrom(Type valueResolverType, string sourceMemberName) => MapFromCore(new(valueResolverType, valueResolverType.GetGenericInterface(typeof(IMemberValueResolver<,,,>))) @@ -103,15 +87,10 @@ private void ConvertUsingCore(Type valueConverterType, string sourceMemberName = }); } } - - public class MappingExpression : - MappingExpressionBase>, + public class MappingExpression : MappingExpressionBase>, IMappingExpression, IProjectionExpression { - public MappingExpression(MemberList memberList, bool projection = false) : base(memberList) - { - Projection = projection; - } + public MappingExpression(MemberList memberList, bool projection = false) : base(memberList) => Projection = projection; public MappingExpression(MemberList memberList, Type sourceType, Type destinationType) : base(memberList, sourceType, destinationType) { } public IMappingExpression ForPath(Expression> destinationMember, Action> memberOptions) @@ -131,15 +110,12 @@ public IMappingExpression ForPath(Expression ForMember(Expression> destinationMember, Action> memberOptions) { var memberInfo = ReflectionHelper.FindProperty(destinationMember); return ForDestinationMember(memberInfo, memberOptions); } - private void IncludeMembersCore(LambdaExpression[] memberExpressions) => TypeMapActions.Add(tm => tm.IncludedMembers = memberExpressions); - public IMappingExpression IncludeMembers(params Expression>[] memberExpressions) { var memberExpressionsWithoutCastToObject = Array.ConvertAll( @@ -149,17 +125,14 @@ public IMappingExpression IncludeMembers(params Expressio var bodyIsCastToObject = e.Body.NodeType == ExpressionType.Convert && e.Body.Type == typeof(object); return bodyIsCastToObject ? Expression.Lambda(((UnaryExpression)e.Body).Operand, e.Parameters) : e; }); - IncludeMembersCore(memberExpressionsWithoutCastToObject); return this; } - public IMappingExpression ForMember(string name, Action> memberOptions) { var member = DestinationType.GetFieldOrProperty(name); return ForDestinationMember(member, memberOptions); } - public void ForAllMembers(Action> memberOptions) { TypeMapActions.Add(typeMap => @@ -170,68 +143,43 @@ public void ForAllMembers(Action Include() - where TOtherSource : TSource - where TOtherDestination : TDestination + public IMappingExpression Include() where TOtherSource : TSource where TOtherDestination : TDestination { IncludeCore(typeof(TOtherSource), typeof(TOtherDestination)); - return this; } - - public IMappingExpression IncludeBase() - => IncludeBase(typeof(TSourceBase), typeof(TDestinationBase)); - + public IMappingExpression IncludeBase() => IncludeBase(typeof(TSourceBase), typeof(TDestinationBase)); public IMappingExpression ForSourceMember(Expression> sourceMember, Action memberOptions) { var memberInfo = ReflectionHelper.FindProperty(sourceMember); - var srcConfig = new SourceMappingExpression(memberInfo); - memberOptions(srcConfig); - SourceMemberConfigurations.Add(srcConfig); - return this; } - public void As() where T : TDestination => As(typeof(T)); - public IMappingExpression AddTransform(Expression> transformer) { var config = new ValueTransformerConfiguration(typeof(TValue), transformer); - ValueTransformers.Add(config); - return this; } - public IMappingExpression ReverseMap() { - var reverseMap = new MappingExpression(MemberList.None, DestinationType, SourceType) - { - IsReverseMap = true - }; + var reverseMap = new MappingExpression(MemberList.None, DestinationType, SourceType){ IsReverseMap = true }; ReverseMapCore(reverseMap); reverseMap.IncludeMembersCore(MapToSourceMembers().Select(m => m.GetDestinationExpression()).ToArray()); return reverseMap; } - private IMappingExpression ForDestinationMember(MemberInfo destinationProperty, Action> memberOptions) { var expression = new MemberConfigurationExpression(destinationProperty, SourceType); - MemberConfigurations.Add(expression); - memberOptions(expression); - return this; } - - protected override void IgnoreDestinationMember(MemberInfo property, bool ignorePaths = true) - => ForDestinationMember(property, options => options.Ignore(ignorePaths)); - + protected override void IgnoreDestinationMember(MemberInfo property, bool ignorePaths = true) => + ForDestinationMember(property, options => options.Ignore(ignorePaths)); IProjectionExpression IProjectionExpression.ForMember(Expression> destinationMember, Action> memberOptions) => (IProjectionExpression)ForMember(destinationMember, memberOptions); diff --git a/src/AutoMapper/Configuration/Profile.cs b/src/AutoMapper/Configuration/Profile.cs index f5b10d3eb8..901fa060cf 100644 --- a/src/AutoMapper/Configuration/Profile.cs +++ b/src/AutoMapper/Configuration/Profile.cs @@ -54,8 +54,8 @@ public interface IProfileConfiguration IReadOnlyCollection GlobalIgnores { get; } INamingConvention SourceMemberNamingConvention { get; } INamingConvention DestinationMemberNamingConvention { get; } - IReadOnlyCollection TypeMapConfigs { get; } - IReadOnlyCollection OpenTypeMapConfigs { get; } + IReadOnlyCollection TypeMapConfigs { get; } + IReadOnlyCollection OpenTypeMapConfigs { get; } IReadOnlyCollection ValueTransformers { get; } } /// @@ -63,13 +63,13 @@ public interface IProfileConfiguration /// public abstract class Profile : IProfileExpressionInternal, IProfileConfiguration { - private readonly List _typeMapConfigs = new(); + private readonly List _typeMapConfigs = new(); private readonly PrePostfixName _prePostfixName = new(); private readonly List _memberConfigurations = new(); private List> _allPropertyMapActions; private List> _allTypeMapActions; private List _globalIgnores; - private List _openTypeMapConfigs; + private List _openTypeMapConfigs; private List _sourceExtensionMethods; private List _valueTransformerConfigs; private bool? _constructorMappingEnabled; @@ -102,8 +102,8 @@ IReadOnlyCollection> IProfil IReadOnlyCollection IProfileConfiguration.GlobalIgnores => _globalIgnores.NullCheck(); IReadOnlyCollection IProfileConfiguration.MemberConfigurations => _memberConfigurations; IReadOnlyCollection IProfileConfiguration.SourceExtensionMethods => _sourceExtensionMethods.NullCheck(); - IReadOnlyCollection IProfileConfiguration.TypeMapConfigs => _typeMapConfigs; - IReadOnlyCollection IProfileConfiguration.OpenTypeMapConfigs => _openTypeMapConfigs.NullCheck(); + IReadOnlyCollection IProfileConfiguration.TypeMapConfigs => _typeMapConfigs; + IReadOnlyCollection IProfileConfiguration.OpenTypeMapConfigs => _openTypeMapConfigs.NullCheck(); IReadOnlyCollection IProfileConfiguration.ValueTransformers => _valueTransformerConfigs.NullCheck(); public virtual string ProfileName { get; } diff --git a/src/AutoMapper/Configuration/MappingExpressionBase.cs b/src/AutoMapper/Configuration/TypeMapConfiguration.cs similarity index 90% rename from src/AutoMapper/Configuration/MappingExpressionBase.cs rename to src/AutoMapper/Configuration/TypeMapConfiguration.cs index 560e7b16c8..0f24ed674e 100644 --- a/src/AutoMapper/Configuration/MappingExpressionBase.cs +++ b/src/AutoMapper/Configuration/TypeMapConfiguration.cs @@ -11,20 +11,7 @@ namespace AutoMapper.Configuration using static Expression; using Execution; [EditorBrowsable(EditorBrowsableState.Never)] - public interface ITypeMapConfiguration - { - void Configure(TypeMap typeMap, List sourceMembers); - Type SourceType { get; } - Type DestinationType { get; } - Type DestinationTypeOverride { get; } - bool IsReverseMap { get; } - TypePair Types { get; } - ITypeMapConfiguration ReverseTypeMap { get; } - TypeMap TypeMap { get; } - bool HasTypeConverter { get; } - IPropertyMapConfiguration GetDestinationMemberConfiguration(MemberInfo destinationMember); - } - public abstract class MappingExpressionBase : ITypeMapConfiguration + public abstract class TypeMapConfiguration { private List _valueTransformers; private Features _features; @@ -33,16 +20,15 @@ public abstract class MappingExpressionBase : ITypeMapConfiguration private List _memberConfigurations; private readonly MemberList _memberList; private readonly TypePair _types; - - protected MappingExpressionBase(MemberList memberList, Type sourceType, Type destinationType) : this(memberList, new TypePair(sourceType, destinationType)) + protected TypeMapConfiguration(MemberList memberList, Type sourceType, Type destinationType) : this(memberList, new TypePair(sourceType, destinationType)) { } - protected MappingExpressionBase(MemberList memberList, TypePair types) + protected TypeMapConfiguration(MemberList memberList, TypePair types) { _memberList = memberList; _types = types; } - public Type DestinationTypeOverride { get; private set; } + public Type DestinationTypeOverride { get; protected set; } protected bool Projection { get; set; } public TypePair Types => _types; public bool IsReverseMap { get; set; } @@ -51,22 +37,13 @@ protected MappingExpressionBase(MemberList memberList, TypePair types) public Type SourceType => _types.SourceType; public Type DestinationType => _types.DestinationType; public Features Features => _features ??= new(); - public ITypeMapConfiguration ReverseTypeMap => ReverseMapExpression; + public TypeMapConfiguration ReverseTypeMap => ReverseMapExpression; public List ValueTransformers => _valueTransformers ??= new(); - protected MappingExpressionBase ReverseMapExpression { get; set; } + protected TypeMapConfiguration ReverseMapExpression { get; set; } protected List> TypeMapActions { get; } = new List>(); protected List MemberConfigurations => _memberConfigurations ??= new(); protected List SourceMemberConfigurations => _sourceMemberConfigurations ??= new(); protected List CtorParamConfigurations => _ctorParamConfigurations ??= new(); - public void As(Type typeOverride) - { - if (typeOverride == DestinationType) - { - throw new InvalidOperationException("As must specify a derived type, not " + DestinationType); - } - typeOverride.CheckIsDerivedFrom(DestinationType); - DestinationTypeOverride = typeOverride; - } public void Configure(TypeMap typeMap, List sourceMembers) { TypeMap = typeMap; @@ -105,8 +82,7 @@ public void Configure(TypeMap typeMap, List sourceMembers) ConfigureReverseMap(typeMap); } } - - protected void ReverseMapCore(MappingExpressionBase reverseMap) + protected void ReverseMapCore(TypeMapConfiguration reverseMap) { ReverseMapExpression = reverseMap; if (_memberConfigurations != null) @@ -115,7 +91,6 @@ protected void ReverseMapCore(MappingExpressionBase reverseMap) } _features?.ReverseTo(reverseMap.Features); } - private void AddCtorParamConfigurations(TypeMap typeMap) { foreach (var paramConfig in _ctorParamConfigurations) @@ -123,7 +98,6 @@ private void AddCtorParamConfigurations(TypeMap typeMap) paramConfig.Configure(typeMap); } } - private void AddSourceMembersConfigurations(TypeMap typeMap) { foreach (var memberConfig in _sourceMemberConfigurations) @@ -131,7 +105,6 @@ private void AddSourceMembersConfigurations(TypeMap typeMap) memberConfig.Configure(typeMap); } } - private void AddValueTransformers(TypeMap typeMap) { foreach (var valueTransformer in _valueTransformers) @@ -139,7 +112,6 @@ private void AddValueTransformers(TypeMap typeMap) typeMap.AddValueTransformation(valueTransformer); } } - private void ConfigureReverseMap(TypeMap typeMap) { ReverseSourceMembers(typeMap); @@ -157,7 +129,6 @@ private void ConfigureReverseMap(TypeMap typeMap) } ReverseIncludedMembers(typeMap); } - private void MapDestinationCtorToSource(TypeMap typeMap, List sourceMembers) { sourceMembers ??= new(); @@ -187,10 +158,8 @@ private void MapDestinationCtorToSource(TypeMap typeMap, List source return; bool IsConfigured(ParameterInfo parameter) => _ctorParamConfigurations?.Any(c => c.CtorParamName == parameter.Name) is true; } - protected IEnumerable MapToSourceMembers() => _memberConfigurations?.Where(m => m.SourceExpression != null && m.SourceExpression.Body == m.SourceExpression.Parameters[0]) ?? Array.Empty(); - private void ReverseIncludedMembers(TypeMap typeMap) { Stack chain = null; @@ -202,7 +171,6 @@ private void ReverseIncludedMembers(TypeMap typeMap) ReverseSourceMembers(memberPath, customExpression); } } - private void ReverseSourceMembers(TypeMap typeMap) { foreach (var propertyMap in typeMap.PropertyMaps.Where(p => p.SourceMembers.Length > 1 && !p.SourceMembers.Any(s => s is MethodInfo))) @@ -212,7 +180,6 @@ private void ReverseSourceMembers(TypeMap typeMap) ReverseSourceMembers(memberPath, customExpression); } } - private void ReverseSourceMembers(MemberPath memberPath, LambdaExpression customExpression) { ReverseMapExpression.TypeMapActions.Add(reverseTypeMap => @@ -226,124 +193,95 @@ private void ReverseSourceMembers(MemberPath memberPath, LambdaExpression custom pathMap.SetResolver(customExpression); }); } - protected void ForSourceMemberCore(string sourceMemberName, Action memberOptions) { var memberInfo = SourceType.GetFieldOrProperty(sourceMemberName); - ForSourceMemberCore(memberInfo, memberOptions); } - protected void ForSourceMemberCore(MemberInfo memberInfo, Action memberOptions) { var srcConfig = new SourceMappingExpression(memberInfo); - memberOptions(srcConfig); - SourceMemberConfigurations.Add(srcConfig); } - protected void IncludeCore(Type derivedSourceType, Type derivedDestinationType) { var derivedTypes = new TypePair(derivedSourceType, derivedDestinationType); derivedTypes.CheckIsDerivedFrom(_types); TypeMapActions.Add(tm => tm.IncludeDerivedTypes(derivedTypes)); } - - protected void IncludeBaseCore(Type sourceBase, Type destinationBase) { var baseTypes = new TypePair(sourceBase, destinationBase); _types.CheckIsDerivedFrom(baseTypes); TypeMapActions.Add(tm => tm.IncludeBaseTypes(baseTypes)); } - public IPropertyMapConfiguration GetDestinationMemberConfiguration(MemberInfo destinationMember) => _memberConfigurations?.Find(m => m.DestinationMember == destinationMember); - protected abstract void IgnoreDestinationMember(MemberInfo property, bool ignorePaths = true); } - - public abstract class MappingExpressionBase - : MappingExpressionBase, IMappingExpressionBase + public abstract class MappingExpressionBase : TypeMapConfiguration, IMappingExpressionBase where TMappingExpression : class, IMappingExpressionBase { - - protected MappingExpressionBase(MemberList memberList) - : base(memberList, typeof(TSource), typeof(TDestination)) - { - } - - protected MappingExpressionBase(MemberList memberList, Type sourceType, Type destinationType) - : base(memberList, sourceType, destinationType) - { - } - - protected MappingExpressionBase(MemberList memberList, TypePair types) - : base(memberList, types) + protected MappingExpressionBase(MemberList memberList) : base(memberList, typeof(TSource), typeof(TDestination)){ } + protected MappingExpressionBase(MemberList memberList, Type sourceType, Type destinationType) : base(memberList, sourceType, destinationType){} + protected MappingExpressionBase(MemberList memberList, TypePair types) : base(memberList, types){} + public void As(Type typeOverride) { + if (typeOverride == DestinationType) + { + throw new InvalidOperationException("As must specify a derived type, not " + DestinationType); + } + typeOverride.CheckIsDerivedFrom(DestinationType); + DestinationTypeOverride = typeOverride; } - public TMappingExpression MaxDepth(int depth) { TypeMapActions.Add(tm => tm.MaxDepth = depth); return this as TMappingExpression; } - public TMappingExpression ConstructUsingServiceLocator() { TypeMapActions.Add(tm => tm.ConstructUsingServiceLocator()); return this as TMappingExpression; } - public TMappingExpression BeforeMap(Action beforeFunction) => BeforeMapCore((src, dest, ctxt) => beforeFunction(src, dest)); - private TMappingExpression BeforeMapCore(Expression> expr) { TypeMapActions.Add(tm => tm.AddBeforeMapAction(expr)); return this as TMappingExpression; } - public TMappingExpression BeforeMap(Action beforeFunction) => BeforeMapCore((src, dest, ctxt) => beforeFunction(src, dest, ctxt)); - public TMappingExpression BeforeMap() where TMappingAction : IMappingAction => BeforeMap(CallMapAction); public TMappingExpression AfterMap() where TMappingAction : IMappingAction => AfterMap(CallMapAction); private static void CallMapAction(TSource source, TDestination destination, ResolutionContext context) => ((IMappingAction)context.CreateInstance(typeof(TMappingAction))).Process(source, destination, context); - public TMappingExpression AfterMap(Action afterFunction) => AfterMapCore((src, dest, ctxt) => afterFunction(src, dest)); - private TMappingExpression AfterMapCore(Expression> expr) { TypeMapActions.Add(tm => tm.AddAfterMapAction(expr)); return this as TMappingExpression; } - public TMappingExpression AfterMap(Action afterFunction) => AfterMapCore((src, dest, ctxt) => afterFunction(src, dest, ctxt)); - public TMappingExpression PreserveReferences() { TypeMapActions.Add(tm => tm.PreserveReferences = true); - return this as TMappingExpression; } - public TMappingExpression DisableCtorValidation() { TypeMapActions.Add(tm => { tm.DisableConstructorValidation = true; }); - return this as TMappingExpression; } - public TMappingExpression ValidateMemberList(MemberList memberList) { TypeMapActions.Add(tm => @@ -352,84 +290,60 @@ public TMappingExpression ValidateMemberList(MemberList memberList) }); return this as TMappingExpression; } - public TMappingExpression IncludeAllDerived() { TypeMapActions.Add(tm => tm.IncludeAllDerivedTypes = true); return this as TMappingExpression; } - public TMappingExpression Include(Type otherSourceType, Type otherDestinationType) { IncludeCore(otherSourceType, otherDestinationType); - return this as TMappingExpression; } - public TMappingExpression IncludeBase(Type sourceBase, Type destinationBase) { IncludeBaseCore(sourceBase, destinationBase); - return this as TMappingExpression; } - public TMappingExpression ForSourceMember(string sourceMemberName, Action memberOptions) { ForSourceMemberCore(sourceMemberName, memberOptions); - return this as TMappingExpression; } - public TMappingExpression ConstructUsing(Expression> ctor) => ConstructUsingCore(ctor); - private TMappingExpression ConstructUsingCore(LambdaExpression ctor) { TypeMapActions.Add(tm => tm.CustomCtorFunction = ctor); return this as TMappingExpression; } - public TMappingExpression ConstructUsing(Func ctor) { Expression> expr = (src, ctxt) => ctor(src, ctxt); return ConstructUsingCore(expr); } - public void ConvertUsing(Type typeConverterType) { HasTypeConverter = true; TypeMapActions.Add(tm => tm.TypeConverter = new ClassTypeConverter(typeConverterType, tm.Types.ITypeConverter())); } - public void ConvertUsing(Func mappingFunction) => ConvertUsingCore((src, dest, ctxt) => mappingFunction(src, dest)); - - private void ConvertUsingCore(Expression> expr) => - SetTypeConverter(new LambdaTypeConverter(expr)); - + private void ConvertUsingCore(Expression> expr) => SetTypeConverter(new LambdaTypeConverter(expr)); private void SetTypeConverter(TypeConverter typeConverter) { HasTypeConverter = true; TypeMapActions.Add(tm => tm.TypeConverter = typeConverter); } - - public void ConvertUsing(Func mappingFunction) => - ConvertUsingCore((src, dest, ctxt) => mappingFunction(src, dest, ctxt)); - + public void ConvertUsing(Func mappingFunction) => ConvertUsingCore((src, dest, ctxt) => mappingFunction(src, dest, ctxt)); public void ConvertUsing(ITypeConverter converter) => ConvertUsing(converter.Convert); - public void ConvertUsing() where TTypeConverter : ITypeConverter => SetTypeConverter(new ClassTypeConverter(typeof(TTypeConverter), typeof(ITypeConverter))); - public TMappingExpression ForCtorParam(string ctorParamName, Action> paramOptions) { var ctorParamExpression = new CtorParamConfigurationExpression(ctorParamName, SourceType); - paramOptions(ctorParamExpression); - CtorParamConfigurations.Add(ctorParamExpression); - return this as TMappingExpression; } - public TMappingExpression IgnoreAllPropertiesWithAnInaccessibleSetter() { foreach(var property in PropertiesWithAnInaccessibleSetter(DestinationType)) @@ -438,7 +352,6 @@ public TMappingExpression IgnoreAllPropertiesWithAnInaccessibleSetter() } return this as TMappingExpression; } - public TMappingExpression IgnoreAllSourcePropertiesWithAnInaccessibleSetter() { foreach (var property in PropertiesWithAnInaccessibleSetter(SourceType)) @@ -447,11 +360,8 @@ public TMappingExpression IgnoreAllSourcePropertiesWithAnInaccessibleSetter() } return this as TMappingExpression; } - private static IEnumerable PropertiesWithAnInaccessibleSetter(Type type) => type.GetRuntimeProperties().Where(p => p.GetSetMethod() == null); - public void ConvertUsing(Expression> mappingFunction) => SetTypeConverter(new ExpressionTypeConverter(mappingFunction)); - public TMappingExpression AsProxy() { if (!DestinationType.IsInterface) diff --git a/src/AutoMapper/Execution/TypeMapPlanBuilder.cs b/src/AutoMapper/Execution/TypeMapPlanBuilder.cs index 0ad2539366..32f1b36f83 100644 --- a/src/AutoMapper/Execution/TypeMapPlanBuilder.cs +++ b/src/AutoMapper/Execution/TypeMapPlanBuilder.cs @@ -496,7 +496,7 @@ public Expression GetExpression(MemberMap memberMap, Expression source, Expressi public abstract class TypeConverter { public abstract Expression GetExpression(ParameterExpression[] parameters); - public virtual void CloseGenerics(ITypeMapConfiguration openMapConfig, TypePair closedTypes) { } + public virtual void CloseGenerics(TypeMapConfiguration openMapConfig, TypePair closedTypes) { } public virtual LambdaExpression ProjectToExpression => null; } public class LambdaTypeConverter : TypeConverter @@ -521,7 +521,7 @@ public ClassTypeConverter(Type converterType, Type converterInterface) public Type ConverterInterface { get; } public override Expression GetExpression(ParameterExpression[] parameters) => Call(ToType(ServiceLocator(ConverterType), ConverterInterface), "Convert", parameters); - public override void CloseGenerics(ITypeMapConfiguration openMapConfig, TypePair closedTypes) + public override void CloseGenerics(TypeMapConfiguration openMapConfig, TypePair closedTypes) { var typeParams = (openMapConfig.SourceType.IsGenericTypeDefinition ? closedTypes.SourceType.GenericTypeArguments : Type.EmptyTypes) .Concat(openMapConfig.DestinationType.IsGenericTypeDefinition ? closedTypes.DestinationType.GenericTypeArguments : Type.EmptyTypes); diff --git a/src/AutoMapper/Internal/InternalApi.cs b/src/AutoMapper/Internal/InternalApi.cs index 98d2e962ef..2858576c1c 100644 --- a/src/AutoMapper/Internal/InternalApi.cs +++ b/src/AutoMapper/Internal/InternalApi.cs @@ -155,7 +155,7 @@ public interface IGlobalConfiguration : IConfigurationProvider TypeMap GetIncludedTypeMap(Type sourceType, Type destinationType); TypeMap[] GetIncludedTypeMaps(IReadOnlyCollection includedTypes); void Seal(TypeMap typeMap); - void RegisterAsMap(ITypeMapConfiguration typeMapConfiguration); + void RegisterAsMap(TypeMapConfiguration typeMapConfiguration); List SourceMembers { get; } } [EditorBrowsable(EditorBrowsableState.Never)] diff --git a/src/AutoMapper/ProfileMap.cs b/src/AutoMapper/ProfileMap.cs index 8ca5a24bcc..5146e40b5c 100644 --- a/src/AutoMapper/ProfileMap.cs +++ b/src/AutoMapper/ProfileMap.cs @@ -18,8 +18,8 @@ namespace AutoMapper public class ProfileMap { private static readonly HashSet EmptyHashSet = new(); - private ITypeMapConfiguration[] _typeMapConfigs; - private Dictionary _openTypeMapConfigs; + private TypeMapConfiguration[] _typeMapConfigs; + private Dictionary _openTypeMapConfigs; private Dictionary _typeDetails; private ConcurrentDictionaryWrapper _runtimeTypeDetails; private readonly IMemberConfiguration[] _memberConfigurations; @@ -63,7 +63,7 @@ public ProfileMap(IProfileConfiguration profile, IGlobalConfigurationExpression return; void SetTypeMapConfigs() { - _typeMapConfigs = new ITypeMapConfiguration[profile.TypeMapConfigs.Count]; + _typeMapConfigs = new TypeMapConfiguration[profile.TypeMapConfigs.Count]; var index = 0; var reverseMapsCount = 0; foreach (var typeMapConfig in profile.TypeMapConfigs) @@ -146,7 +146,7 @@ public void Register(IGlobalConfiguration configurationProvider) } } } - private void BuildTypeMap(IGlobalConfiguration configurationProvider, ITypeMapConfiguration config) + private void BuildTypeMap(IGlobalConfiguration configurationProvider, TypeMapConfiguration config) { var sourceMembers = configurationProvider.SourceMembers; var typeMap = new TypeMap(config.SourceType, config.DestinationType, this, config, sourceMembers); @@ -171,7 +171,7 @@ public void Configure(IGlobalConfiguration configurationProvider) } } } - private void Configure(ITypeMapConfiguration typeMapConfiguration, IGlobalConfiguration configurationProvider) + private void Configure(TypeMapConfiguration typeMapConfiguration, IGlobalConfiguration configurationProvider) { var typeMap = typeMapConfiguration.TypeMap; if (typeMap.IncludeAllDerivedTypes) @@ -211,7 +211,7 @@ private void Configure(TypeMap typeMap, IGlobalConfiguration configurationProvid ApplyDerivedMaps(typeMap, typeMap, configurationProvider); ApplyMemberMaps(typeMap, configurationProvider); } - public TypeMap CreateClosedGenericTypeMap(ITypeMapConfiguration openMapConfig, TypePair closedTypes, IGlobalConfiguration configurationProvider) + public TypeMap CreateClosedGenericTypeMap(TypeMapConfiguration openMapConfig, TypePair closedTypes, IGlobalConfiguration configurationProvider) { TypeMap closedMap; lock (configurationProvider) @@ -223,7 +223,7 @@ public TypeMap CreateClosedGenericTypeMap(ITypeMapConfiguration openMapConfig, T closedMap.CloseGenerics(openMapConfig, closedTypes); return closedMap; } - public ITypeMapConfiguration GetGenericMap(TypePair genericPair) => _openTypeMapConfigs.GetValueOrDefault(genericPair); + public TypeMapConfiguration GetGenericMap(TypePair genericPair) => _openTypeMapConfigs.GetValueOrDefault(genericPair); private void ApplyBaseMaps(TypeMap derivedMap, TypeMap currentMap, IGlobalConfiguration configurationProvider) { foreach (var baseMap in configurationProvider.GetIncludedTypeMaps(currentMap.IncludedBaseTypes)) diff --git a/src/AutoMapper/TypeMap.cs b/src/AutoMapper/TypeMap.cs index dbfbe35935..e5790b0e20 100644 --- a/src/AutoMapper/TypeMap.cs +++ b/src/AutoMapper/TypeMap.cs @@ -24,7 +24,7 @@ public class TypeMap private TypeMapDetails _details; private Dictionary _propertyMaps; private bool _sealed; - public TypeMap(Type sourceType, Type destinationType, ProfileMap profile, ITypeMapConfiguration typeMapConfiguration = null, List sourceMembers = null) + public TypeMap(Type sourceType, Type destinationType, ProfileMap profile, TypeMapConfiguration typeMapConfiguration = null, List sourceMembers = null) { Types = new(sourceType, destinationType); Profile = profile; @@ -270,7 +270,7 @@ internal void CopyInheritedMapsTo(TypeMap typeMap) } _details.CopyInheritedMapsTo(typeMap); } - public void CloseGenerics(ITypeMapConfiguration openMapConfig, TypePair closedTypes) => TypeConverter?.CloseGenerics(openMapConfig, closedTypes); + public void CloseGenerics(TypeMapConfiguration openMapConfig, TypePair closedTypes) => TypeConverter?.CloseGenerics(openMapConfig, closedTypes); public bool AddMemberMap(IncludedMember includedMember) => Details.AddMemberMap(includedMember); public PathMap FindOrCreatePathMapFor(LambdaExpression destinationExpression, MemberPath path, TypeMap typeMap) => Details.FindOrCreatePathMapFor(destinationExpression, path, typeMap); From a0988d724ce55d44437de3ad3faa4a95ed341431 Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Thu, 11 Aug 2022 17:58:42 +0300 Subject: [PATCH 20/67] cosmetic --- src/AutoMapper/Mappers/CollectionMapper.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/AutoMapper/Mappers/CollectionMapper.cs b/src/AutoMapper/Mappers/CollectionMapper.cs index 5ecbe12d56..dba7c215cd 100644 --- a/src/AutoMapper/Mappers/CollectionMapper.cs +++ b/src/AutoMapper/Mappers/CollectionMapper.cs @@ -199,8 +199,7 @@ Expression MapFromArray() { sourceElementType = sourceType.GetElementType(); createDestination = Assign(destination, NewArrayBounds(destinationElementType, ArrayLength(sourceExpression))); - if (!destinationElementType.IsAssignableFrom(sourceElementType) || - configurationProvider.FindTypeMapFor(sourceElementType, destinationElementType) != null) + if (MustMap(sourceElementType, destinationElementType)) { return null; } @@ -212,13 +211,14 @@ Expression MapFromArray() Expression MapFromIEnumerable() { var iEnumerableType = sourceType.GetIEnumerableType(); - if (iEnumerableType == null || (sourceElementType = iEnumerableType.GenericTypeArguments[0]) != destinationElementType || - configurationProvider.FindTypeMapFor(sourceElementType, destinationElementType) != null) + if (iEnumerableType == null || MustMap(sourceElementType = iEnumerableType.GenericTypeArguments[0], destinationElementType)) { return null; } return Call(ToArrayMethod.MakeGenericMethod(sourceElementType), sourceExpression); } + bool MustMap(Type sourceType, Type destinationType) => !destinationType.IsAssignableFrom(sourceType) || + configurationProvider.FindTypeMapFor(sourceType, destinationType) != null; } } } From 0b9cf8c603c9f8ceb90b9ddc3155c6c6fc0f7af2 Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Thu, 11 Aug 2022 18:43:11 +0300 Subject: [PATCH 21/67] try to show a better error message when mapping records through constructors --- docs/Construction.md | 6 +++--- .../CtorParamConfigurationExpression.cs | 5 ++++- src/UnitTests/Constructors.cs | 15 ++++++++++++--- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/docs/Construction.md b/docs/Construction.md index 282e109f3d..40286cdb16 100644 --- a/docs/Construction.md +++ b/docs/Construction.md @@ -50,6 +50,6 @@ var configuration = new MapperConfiguration(cfg => cfg.DisableConstructorMapping You can configure which constructors are considered for the destination object: ```c# -// don't map private constructors -var configuration = new MapperConfiguration(cfg => cfg.ShouldUseConstructor = ci => !ci.IsPrivate); -``` +// use only public constructors +var configuration = new MapperConfiguration(cfg => cfg.ShouldUseConstructor = constructor => constructor.IsPublic); +``` \ No newline at end of file diff --git a/src/AutoMapper/Configuration/CtorParamConfigurationExpression.cs b/src/AutoMapper/Configuration/CtorParamConfigurationExpression.cs index 5a9aeb6799..3a5145ec03 100644 --- a/src/AutoMapper/Configuration/CtorParamConfigurationExpression.cs +++ b/src/AutoMapper/Configuration/CtorParamConfigurationExpression.cs @@ -76,12 +76,15 @@ public void Configure(TypeMap typeMap) var parameter = ctorMap[CtorParamName]; if (parameter == null) { - throw new AutoMapperConfigurationException($"{typeMap.DestinationType.Name} does not have a matching constructor with a parameter named '{CtorParamName}'.\n{typeMap.DestinationType.FullName}"); + throw new AutoMapperConfigurationException($"{typeMap.DestinationType.Name} does not have a matching constructor with a parameter named '{CtorParamName}'.\n{typeMap.DestinationType.FullName}.{CheckRecord()}"); } foreach (var action in _ctorParamActions) { action(parameter); } + return; + string CheckRecord() => ctorMap.Ctor.IsFamily && ctorMap.Ctor.DeclaringType.GetMethod("$") != null ? + " When mapping to records, consider excluding non-public constructors. See https://docs.automapper.org/en/latest/Construction.html." : null; } } } \ No newline at end of file diff --git a/src/UnitTests/Constructors.cs b/src/UnitTests/Constructors.cs index 866272da5f..f5630741b6 100644 --- a/src/UnitTests/Constructors.cs +++ b/src/UnitTests/Constructors.cs @@ -4,11 +4,20 @@ using Xunit; using Shouldly; using System.Collections.Generic; -using System.Diagnostics; -using AutoMapper; - namespace AutoMapper.UnitTests.Constructors { + public class RecordConstructorValidation : AutoMapperSpecBase + { + class Source + { + } + record Destination(int Value, int Other){} + protected override MapperConfiguration CreateConfiguration() => new(c => + c.CreateMap().ForCtorParam(nameof(Destination.Value), o => o.MapFrom(s => 0))); + [Fact] + public void Validate() => new Action(AssertConfigurationIsValid).ShouldThrow().Message. + ShouldContainWithoutWhitespace("When mapping to records, consider excluding non-public constructors."); + } public class ConstructorValidation : AutoMapperSpecBase { class Source From b9699dd95fa453bf58d98bc84ab89d4033f7f9de Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Sat, 13 Aug 2022 13:16:33 +0300 Subject: [PATCH 22/67] less allocations --- src/AutoMapper/ApiCompatBaseline.txt | 2 +- .../Conventions/MemberConfiguration.cs | 58 ++++++++++++++----- .../Configuration/INamingConvention.cs | 19 +++--- src/UnitTests/Internal/TypeMapFactorySpecs.cs | 25 ++------ src/UnitTests/ReverseMapping.cs | 24 ++++---- 5 files changed, 75 insertions(+), 53 deletions(-) diff --git a/src/AutoMapper/ApiCompatBaseline.txt b/src/AutoMapper/ApiCompatBaseline.txt index e7886b6737..3445e66426 100644 --- a/src/AutoMapper/ApiCompatBaseline.txt +++ b/src/AutoMapper/ApiCompatBaseline.txt @@ -8,7 +8,7 @@ MembersMustExist : Member 'public void AutoMapper.IMappingExpressionBase> AutoMapper.INamingConvention.Split(System.String)' is present in the implementation but not in the contract. InterfacesShouldHaveSameMembers : Interface member 'public System.Text.RegularExpressions.Regex AutoMapper.INamingConvention.SplittingExpression.get()' is present in the contract but not in the implementation. MembersMustExist : Member 'public System.Text.RegularExpressions.Regex AutoMapper.INamingConvention.SplittingExpression.get()' does not exist in the implementation but it does exist in the contract. InterfacesShouldHaveSameMembers : Interface member 'public System.Collections.Generic.IReadOnlyCollection AutoMapper.IProfileConfiguration.OpenTypeMapConfigs.get()' is present in the implementation but not in the contract. diff --git a/src/AutoMapper/Configuration/Conventions/MemberConfiguration.cs b/src/AutoMapper/Configuration/Conventions/MemberConfiguration.cs index 95ecf7edb0..22cfa2be00 100644 --- a/src/AutoMapper/Configuration/Conventions/MemberConfiguration.cs +++ b/src/AutoMapper/Configuration/Conventions/MemberConfiguration.cs @@ -3,6 +3,7 @@ using System.Collections; using System.Collections.Generic; using System.ComponentModel; +using System.Diagnostics; using System.Linq; using System.Reflection; namespace AutoMapper.Configuration.Conventions @@ -82,30 +83,61 @@ public bool MapDestinationPropertyToSource(ProfileMap options, TypeDetails sourc { var destinationMemberNamingConvention = isReverseMap ? SourceMemberNamingConvention : DestinationMemberNamingConvention; var matches = destinationMemberNamingConvention.Split(nameToSearch); - var length = matches.Length; - if (length < 2) + if (matches == null) { return false; } var sourceMemberNamingConvention = isReverseMap ? DestinationMemberNamingConvention : SourceMemberNamingConvention; var separator = sourceMemberNamingConvention.SeparatorCharacter; - for (var index = 1; index <= length; index++) + var length = matches.Count - 1; + for (var index = 0; index <= length; index++) { - var first = string.Join(separator, matches, 0, index); + var first = Join(separator, matches, 0, index); var matchingMemberInfo = parent.NameMapper.GetMatchingMemberInfo(sourceType, destType, destMemberType, first); - if (matchingMemberInfo != null) + if (matchingMemberInfo == null) { - resolvers.Add(matchingMemberInfo); - var details = options.CreateTypeDetails(matchingMemberInfo.GetMemberType()); - var second = string.Join(separator, matches, index, length - index); - if (parent.MapDestinationPropertyToSource(options, details, destType, destMemberType, second, resolvers, isReverseMap)) - { - return true; - } - resolvers.RemoveAt(resolvers.Count - 1); + continue; + } + resolvers.Add(matchingMemberInfo); + if (index == length) + { + return true; + } + var details = options.CreateTypeDetails(matchingMemberInfo.GetMemberType()); + var second = Join(separator, matches, index + 1, length); + if (parent.MapDestinationPropertyToSource(options, details, destType, destMemberType, second, resolvers, isReverseMap)) + { + return true; } + resolvers.RemoveAt(resolvers.Count - 1); } return false; + static string Join(string separator, List> matches, int startIndex, int endIndex) + { + Debug.Assert(startIndex <= endIndex); + int resultLength = 0; + var separatorLength = separator.Length; + for (int index = startIndex; index <= endIndex; index++) + { + resultLength += matches[index].Length + separatorLength; + } + resultLength -= separatorLength; + return string.Create(resultLength, (matches, startIndex, endIndex, separator), static (span, state) => + { + var separatorSpan = state.separator.AsSpan(); + for (int index = state.startIndex, destinationIndex = 0; index <= state.endIndex; index++) + { + var match = state.matches[index].Span; + match.CopyTo(span[destinationIndex..]); + destinationIndex += match.Length; + if (index != state.endIndex) + { + separatorSpan.CopyTo(span[destinationIndex..]); + destinationIndex += separatorSpan.Length; + } + } + }); + } } } } \ No newline at end of file diff --git a/src/AutoMapper/Configuration/INamingConvention.cs b/src/AutoMapper/Configuration/INamingConvention.cs index c724fd107d..5da4d3a4a5 100644 --- a/src/AutoMapper/Configuration/INamingConvention.cs +++ b/src/AutoMapper/Configuration/INamingConvention.cs @@ -2,49 +2,50 @@ using System.Collections.Generic; namespace AutoMapper { + using StringChars = ReadOnlyMemory; /// /// Defines a naming convention strategy /// public interface INamingConvention { - string[] Split(string input); + List Split(string input); string SeparatorCharacter { get; } } public class ExactMatchNamingConvention : INamingConvention { public static readonly ExactMatchNamingConvention Instance = new(); - public string[] Split(string _) => Array.Empty(); + public List Split(string _) => null; public string SeparatorCharacter => null; } public class PascalCaseNamingConvention : INamingConvention { public static readonly PascalCaseNamingConvention Instance = new(); public string SeparatorCharacter => ""; - public string[] Split(string input) + public List Split(string input) { - List result = null; + List result = null; int lower = 0; for(int index = 1; index < input.Length; index++) { if (char.IsUpper(input[index])) { result ??= new(); - result.Add(input[lower..index]); + result.Add(input.AsMemory(lower, index - lower)); lower = index; } } if (result == null) { - return Array.Empty(); + return null; } - result.Add(input[lower..]); - return result.ToArray(); + result.Add(input.AsMemory(lower)); + return result; } } public class LowerUnderscoreNamingConvention : INamingConvention { public static readonly LowerUnderscoreNamingConvention Instance = new(); public string SeparatorCharacter => "_"; - public string[] Split(string input) => input.Split('_', StringSplitOptions.RemoveEmptyEntries); + public List Split(string input) => new(Array.ConvertAll(input.Split('_', StringSplitOptions.RemoveEmptyEntries), MemoryExtensions.AsMemory)); } } \ No newline at end of file diff --git a/src/UnitTests/Internal/TypeMapFactorySpecs.cs b/src/UnitTests/Internal/TypeMapFactorySpecs.cs index 394fbae2ea..72aafe9274 100644 --- a/src/UnitTests/Internal/TypeMapFactorySpecs.cs +++ b/src/UnitTests/Internal/TypeMapFactorySpecs.cs @@ -8,26 +8,13 @@ namespace AutoMapper.UnitTests.Tests { using AutoMapper.Internal; using System; + using System.Collections.Generic; public class StubNamingConvention : INamingConvention { - private readonly Func _replaceFunc; - - public StubNamingConvention(Func replaceFunc) - { - _replaceFunc = replaceFunc; - SeparatorCharacter = ""; - } - public Regex SplittingExpression { get; set; } public string SeparatorCharacter { get; set; } - - public string[] Split(string input) => SplittingExpression.Matches(input).Select(m=>m.Value).ToArray(); - - public string ReplaceValue(Match match) - { - return _replaceFunc(match); - } + public List> Split(string input) => SplittingExpression.Matches(input).Select(m => m.Value.AsMemory()).ToList(); } public class When_constructing_type_maps_with_matching_property_names : SpecBase @@ -69,7 +56,7 @@ public class When_using_a_custom_source_naming_convention : SpecBase { private TypeMap _map; private ProfileMap _mappingOptions; - + private class Source { public SubSource some__source { get; set; } @@ -91,7 +78,7 @@ private class TestProfile : Profile } protected override void Establish_context() { - var namingConvention = new StubNamingConvention(s => s.Value.ToLower()){SeparatorCharacter = "__", SplittingExpression = new Regex(@"[\p{Ll}\p{Lu}0-9]+(?=__?)")}; + var namingConvention = new StubNamingConvention{ SeparatorCharacter = "__", SplittingExpression = new Regex(@"[\p{Ll}\p{Lu}0-9]+(?=__?)") }; var profile = new TestProfile(); profile.Internal().AddMemberConfiguration().AddMember(_ => @@ -141,7 +128,7 @@ private class TestProfile : Profile protected override void Establish_context() { - var namingConvention = new StubNamingConvention(s => s.Value.ToLower()) { SeparatorCharacter = "__", SplittingExpression = new Regex(@"[\p{Ll}\p{Lu}0-9]+(?=__?)") }; + var namingConvention = new StubNamingConvention{ SeparatorCharacter = "__", SplittingExpression = new Regex(@"[\p{Ll}\p{Lu}0-9]+(?=__?)") }; var profile = new TestProfile(); profile.Internal().AddMemberConfiguration().AddMember(_ => @@ -192,7 +179,7 @@ public void Should_map_properties_with_different_names() }); var mapper = config.CreateMapper(); - var dest = mapper.Map(new Source {Ävíator = 3, SubAirlinaFlight = 4, Value = 5}); + var dest = mapper.Map(new Source { Ävíator = 3, SubAirlinaFlight = 4, Value = 5 }); dest.Aviator.ShouldBe(3); dest.SubAirlineFlight.ShouldBe(4); dest.Value.ShouldBe(5); diff --git a/src/UnitTests/ReverseMapping.cs b/src/UnitTests/ReverseMapping.cs index 37a0ef4e9e..f4437e8f5d 100644 --- a/src/UnitTests/ReverseMapping.cs +++ b/src/UnitTests/ReverseMapping.cs @@ -3,8 +3,8 @@ using System.Linq; using System; using System.Text.RegularExpressions; -using System.Reflection; using AutoMapper.Internal; +using System.Collections.Generic; namespace AutoMapper.UnitTests { @@ -18,7 +18,7 @@ class Destination { public Guid Id { get; set; } } - protected override MapperConfiguration CreateConfiguration() => new(c=> + protected override MapperConfiguration CreateConfiguration() => new(c => c.CreateMap().ForMember(src => src.Id, opt => opt.MapFrom(_ => Guid.Empty)).ReverseMap()); [Fact] public void Validate() => AssertConfigurationIsValid(); @@ -45,7 +45,7 @@ public class Three2 { } - protected override MapperConfiguration CreateConfiguration() => new(cfg=> + protected override MapperConfiguration CreateConfiguration() => new(cfg => { cfg.CreateMap() .ForMember(d => d.Name, o => o.MapFrom(s => "name")) @@ -118,7 +118,7 @@ class OrderDto public int OrderItemsCount { get; set; } } - protected override MapperConfiguration CreateConfiguration() => new(c=> + protected override MapperConfiguration CreateConfiguration() => new(c => { c.CreateMap().ReverseMap(); }); @@ -165,10 +165,12 @@ public class OrderDto [Fact] public void Should_flatten() { - var model = new Order { - CustomerHolder = new CustomerHolder { - Customer = new Customer { Name = "George Costanza", Total = 74.85m } - } + var model = new Order + { + CustomerHolder = new CustomerHolder + { + Customer = new Customer { Name = "George Costanza", Total = 74.85m } + } }; var dto = Mapper.Map(model); dto.CustomerName.ShouldBe("George Costanza"); @@ -306,8 +308,8 @@ public class OrderDto { cfg.CreateMap() .ReverseMap() - .ForMember(d=>d.Customerholder, o=>o.Ignore()) - .ForPath(d=>d.Customerholder.Customer.Total, o=>o.MapFrom(s=>s.CustomerholderCustomerTotal)); + .ForMember(d => d.Customerholder, o => o.Ignore()) + .ForPath(d => d.Customerholder.Customer.Total, o => o.MapFrom(s => s.CustomerholderCustomerTotal)); }); [Fact] @@ -384,7 +386,7 @@ public class UnderscoreNamingConvention : INamingConvention public Regex SplittingExpression { get; } = new Regex(@"\p{Lu}[a-z0-9]*(?=_?)"); public string SeparatorCharacter => "_"; - public string[] Split(string input) => SplittingExpression.Matches(input).Select(m => m.Value).ToArray(); + public List> Split(string input) => SplittingExpression.Matches(input).Select(m => m.Value.AsMemory()).ToList(); } protected override MapperConfiguration CreateConfiguration() => new(cfg => From ed9097fd24be6158c53ccd318690d4e89581685c Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Sat, 13 Aug 2022 16:38:54 +0300 Subject: [PATCH 23/67] special case the defaults for naming conventions --- src/AutoMapper/ApiCompatBaseline.txt | 2 +- .../Conventions/MemberConfiguration.cs | 105 +++++++++++------- .../Configuration/INamingConvention.cs | 19 ++-- src/AutoMapper/ProfileMap.cs | 6 +- src/UnitTests/Internal/TypeMapFactorySpecs.cs | 88 ++++----------- src/UnitTests/ReverseMapping.cs | 24 ++-- 6 files changed, 111 insertions(+), 133 deletions(-) diff --git a/src/AutoMapper/ApiCompatBaseline.txt b/src/AutoMapper/ApiCompatBaseline.txt index 3445e66426..e7886b6737 100644 --- a/src/AutoMapper/ApiCompatBaseline.txt +++ b/src/AutoMapper/ApiCompatBaseline.txt @@ -8,7 +8,7 @@ MembersMustExist : Member 'public void AutoMapper.IMappingExpressionBase> AutoMapper.INamingConvention.Split(System.String)' is present in the implementation but not in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public System.String[] AutoMapper.INamingConvention.Split(System.String)' is present in the implementation but not in the contract. InterfacesShouldHaveSameMembers : Interface member 'public System.Text.RegularExpressions.Regex AutoMapper.INamingConvention.SplittingExpression.get()' is present in the contract but not in the implementation. MembersMustExist : Member 'public System.Text.RegularExpressions.Regex AutoMapper.INamingConvention.SplittingExpression.get()' does not exist in the implementation but it does exist in the contract. InterfacesShouldHaveSameMembers : Interface member 'public System.Collections.Generic.IReadOnlyCollection AutoMapper.IProfileConfiguration.OpenTypeMapConfigs.get()' is present in the implementation but not in the contract. diff --git a/src/AutoMapper/Configuration/Conventions/MemberConfiguration.cs b/src/AutoMapper/Configuration/Conventions/MemberConfiguration.cs index 22cfa2be00..56c6b7fa2f 100644 --- a/src/AutoMapper/Configuration/Conventions/MemberConfiguration.cs +++ b/src/AutoMapper/Configuration/Conventions/MemberConfiguration.cs @@ -3,7 +3,6 @@ using System.Collections; using System.Collections.Generic; using System.ComponentModel; -using System.Diagnostics; using System.Linq; using System.Reflection; namespace AutoMapper.Configuration.Conventions @@ -77,66 +76,92 @@ public bool MapDestinationPropertyToSource(ProfileMap options, TypeDetails sourc [EditorBrowsable(EditorBrowsableState.Never)] public class NameSplitMember : IChildMemberConfiguration { + bool _default = true; public INamingConvention SourceMemberNamingConvention { get; set; } public INamingConvention DestinationMemberNamingConvention { get; set; } - public bool MapDestinationPropertyToSource(ProfileMap options, TypeDetails sourceType, Type destType, Type destMemberType, string nameToSearch, List resolvers, IMemberConfiguration parent, bool isReverseMap) + public bool MapDestinationPropertyToSource(ProfileMap options, TypeDetails sourceType, Type destType, Type destMemberType, string nameToSearch, List resolvers, IMemberConfiguration parent, bool isReverseMap) => + _default ? + Default(options, sourceType, destType, destMemberType, nameToSearch, resolvers, parent, isReverseMap) : + Conventions(options, sourceType, destType, destMemberType, nameToSearch, resolvers, parent, isReverseMap); + bool Default(ProfileMap options, TypeDetails sourceType, Type destType, Type destMemberType, string nameToSearch, List resolvers, IMemberConfiguration parent, bool isReverseMap) { - var destinationMemberNamingConvention = isReverseMap ? SourceMemberNamingConvention : DestinationMemberNamingConvention; - var matches = destinationMemberNamingConvention.Split(nameToSearch); - if (matches == null) + MemberInfo matchingMemberInfo = null; + int index = 1; + for (; index < nameToSearch.Length; index++) { - return false; + if (char.IsUpper(nameToSearch[index]) && Found()) + { + return true; + } } - var sourceMemberNamingConvention = isReverseMap ? DestinationMemberNamingConvention : SourceMemberNamingConvention; - var separator = sourceMemberNamingConvention.SeparatorCharacter; - var length = matches.Count - 1; - for (var index = 0; index <= length; index++) + return matchingMemberInfo != null && Found(); + bool Found() { - var first = Join(separator, matches, 0, index); - var matchingMemberInfo = parent.NameMapper.GetMatchingMemberInfo(sourceType, destType, destMemberType, first); + var first = nameToSearch[..index]; + matchingMemberInfo = parent.NameMapper.GetMatchingMemberInfo(sourceType, destType, destMemberType, first); if (matchingMemberInfo == null) { - continue; + return false; } resolvers.Add(matchingMemberInfo); - if (index == length) - { - return true; - } + var second = nameToSearch[index..]; var details = options.CreateTypeDetails(matchingMemberInfo.GetMemberType()); - var second = Join(separator, matches, index + 1, length); if (parent.MapDestinationPropertyToSource(options, details, destType, destMemberType, second, resolvers, isReverseMap)) { return true; } resolvers.RemoveAt(resolvers.Count - 1); + return false; } - return false; - static string Join(string separator, List> matches, int startIndex, int endIndex) + } + bool Conventions(ProfileMap options, TypeDetails sourceType, Type destType, Type destMemberType, string nameToSearch, List resolvers, IMemberConfiguration parent, bool isReverseMap) + { + var destinationMemberNamingConvention = isReverseMap ? SourceMemberNamingConvention : DestinationMemberNamingConvention; + var matches = destinationMemberNamingConvention.Split(nameToSearch); + var length = matches.Length; + if (length < 2) { - Debug.Assert(startIndex <= endIndex); - int resultLength = 0; - var separatorLength = separator.Length; - for (int index = startIndex; index <= endIndex; index++) - { - resultLength += matches[index].Length + separatorLength; - } - resultLength -= separatorLength; - return string.Create(resultLength, (matches, startIndex, endIndex, separator), static (span, state) => + return false; + } + var sourceMemberNamingConvention = isReverseMap ? DestinationMemberNamingConvention : SourceMemberNamingConvention; + var separator = sourceMemberNamingConvention.SeparatorCharacter; + for (var index = 1; index <= length; index++) + { + var first = string.Join(separator, matches, 0, index); + var matchingMemberInfo = parent.NameMapper.GetMatchingMemberInfo(sourceType, destType, destMemberType, first); + if (matchingMemberInfo != null) { - var separatorSpan = state.separator.AsSpan(); - for (int index = state.startIndex, destinationIndex = 0; index <= state.endIndex; index++) + resolvers.Add(matchingMemberInfo); + var details = options.CreateTypeDetails(matchingMemberInfo.GetMemberType()); + var second = string.Join(separator, matches, index, length - index); + if (parent.MapDestinationPropertyToSource(options, details, destType, destMemberType, second, resolvers, isReverseMap)) { - var match = state.matches[index].Span; - match.CopyTo(span[destinationIndex..]); - destinationIndex += match.Length; - if (index != state.endIndex) - { - separatorSpan.CopyTo(span[destinationIndex..]); - destinationIndex += separatorSpan.Length; - } + return true; } - }); + resolvers.RemoveAt(resolvers.Count - 1); + } + } + return false; + } + internal void Set(INamingConvention source, INamingConvention destination) + { + if (source == null) + { + SourceMemberNamingConvention = PascalCaseNamingConvention.Instance; + } + else + { + SourceMemberNamingConvention = source; + _default = false; + } + if (destination == null) + { + DestinationMemberNamingConvention = PascalCaseNamingConvention.Instance; + } + else + { + DestinationMemberNamingConvention = destination; + _default = false; } } } diff --git a/src/AutoMapper/Configuration/INamingConvention.cs b/src/AutoMapper/Configuration/INamingConvention.cs index 5da4d3a4a5..c724fd107d 100644 --- a/src/AutoMapper/Configuration/INamingConvention.cs +++ b/src/AutoMapper/Configuration/INamingConvention.cs @@ -2,50 +2,49 @@ using System.Collections.Generic; namespace AutoMapper { - using StringChars = ReadOnlyMemory; /// /// Defines a naming convention strategy /// public interface INamingConvention { - List Split(string input); + string[] Split(string input); string SeparatorCharacter { get; } } public class ExactMatchNamingConvention : INamingConvention { public static readonly ExactMatchNamingConvention Instance = new(); - public List Split(string _) => null; + public string[] Split(string _) => Array.Empty(); public string SeparatorCharacter => null; } public class PascalCaseNamingConvention : INamingConvention { public static readonly PascalCaseNamingConvention Instance = new(); public string SeparatorCharacter => ""; - public List Split(string input) + public string[] Split(string input) { - List result = null; + List result = null; int lower = 0; for(int index = 1; index < input.Length; index++) { if (char.IsUpper(input[index])) { result ??= new(); - result.Add(input.AsMemory(lower, index - lower)); + result.Add(input[lower..index]); lower = index; } } if (result == null) { - return null; + return Array.Empty(); } - result.Add(input.AsMemory(lower)); - return result; + result.Add(input[lower..]); + return result.ToArray(); } } public class LowerUnderscoreNamingConvention : INamingConvention { public static readonly LowerUnderscoreNamingConvention Instance = new(); public string SeparatorCharacter => "_"; - public List Split(string input) => new(Array.ConvertAll(input.Split('_', StringSplitOptions.RemoveEmptyEntries), MemoryExtensions.AsMemory)); + public string[] Split(string input) => input.Split('_', StringSplitOptions.RemoveEmptyEntries); } } \ No newline at end of file diff --git a/src/AutoMapper/ProfileMap.cs b/src/AutoMapper/ProfileMap.cs index 5146e40b5c..cb6170c61b 100644 --- a/src/AutoMapper/ProfileMap.cs +++ b/src/AutoMapper/ProfileMap.cs @@ -40,11 +40,7 @@ public ProfileMap(IProfileConfiguration profile, IGlobalConfigurationExpression ValueTransformers = profile.ValueTransformers.Concat(configuration?.ValueTransformers).ToArray(); _memberConfigurations = profile.MemberConfigurations.Concat(globalProfile?.MemberConfigurations).ToArray(); var nameSplitMember = (NameSplitMember)_memberConfigurations[0].MemberMappers.Find(m => m is NameSplitMember); - if (nameSplitMember != null) - { - nameSplitMember.SourceMemberNamingConvention = profile.SourceMemberNamingConvention ?? PascalCaseNamingConvention.Instance; - nameSplitMember.DestinationMemberNamingConvention = profile.DestinationMemberNamingConvention ?? PascalCaseNamingConvention.Instance; - } + nameSplitMember?.Set(profile.SourceMemberNamingConvention, profile.DestinationMemberNamingConvention); var globalIgnores = profile.GlobalIgnores.Concat(globalProfile?.GlobalIgnores); GlobalIgnores = globalIgnores == Array.Empty() ? EmptyHashSet : new HashSet(globalIgnores); SourceExtensionMethods = profile.SourceExtensionMethods.Concat(globalProfile?.SourceExtensionMethods).ToArray(); diff --git a/src/UnitTests/Internal/TypeMapFactorySpecs.cs b/src/UnitTests/Internal/TypeMapFactorySpecs.cs index 72aafe9274..3cb169c4ec 100644 --- a/src/UnitTests/Internal/TypeMapFactorySpecs.cs +++ b/src/UnitTests/Internal/TypeMapFactorySpecs.cs @@ -8,13 +8,12 @@ namespace AutoMapper.UnitTests.Tests { using AutoMapper.Internal; using System; - using System.Collections.Generic; public class StubNamingConvention : INamingConvention { public Regex SplittingExpression { get; set; } public string SeparatorCharacter { get; set; } - public List> Split(string input) => SplittingExpression.Matches(input).Select(m => m.Value.AsMemory()).ToList(); + public string[] Split(string input) => SplittingExpression.Matches(input).Select(m=>m.Value).ToArray(); } public class When_constructing_type_maps_with_matching_property_names : SpecBase @@ -51,104 +50,65 @@ public void Should_map_properties_with_same_name() propertyMaps.Count().ShouldBe(2); } } - - public class When_using_a_custom_source_naming_convention : SpecBase + public class When_using_a_custom_source_naming_convention : AutoMapperSpecBase { - private TypeMap _map; - private ProfileMap _mappingOptions; - private class Source { public SubSource some__source { get; set; } } - private class SubSource { public int value { get; set; } } - private class Destination { public int SomeSourceValue { get; set; } } - private class TestProfile : Profile { - public override string ProfileName => "Test"; - } - protected override void Establish_context() - { - var namingConvention = new StubNamingConvention{ SeparatorCharacter = "__", SplittingExpression = new Regex(@"[\p{Ll}\p{Lu}0-9]+(?=__?)") }; - - var profile = new TestProfile(); - profile.Internal().AddMemberConfiguration().AddMember(_ => + public TestProfile() { - _.SourceMemberNamingConvention = namingConvention; - _.DestinationMemberNamingConvention = new PascalCaseNamingConvention(); - }); - _mappingOptions = new ProfileMap(profile); - } - - protected override void Because_of() - { - _map = new TypeMap(typeof(Source), typeof(Destination), _mappingOptions); + var namingConvention = new StubNamingConvention{ SeparatorCharacter = "__", SplittingExpression = new Regex(@"[\p{Ll}\p{Lu}0-9]+(?=__?)") }; + this.Internal().AddMemberConfiguration().AddMember(_ => + { + _.SourceMemberNamingConvention = namingConvention; + _.DestinationMemberNamingConvention = new PascalCaseNamingConvention(); + }); + } } - + protected override MapperConfiguration CreateConfiguration() => new(c => c.AddProfile()); [Fact] - public void Should_split_using_naming_convention_rules() - { - _map.PropertyMaps.Count().ShouldBe(1); - } + public void Should_split_using_naming_convention_rules() => AssertConfigurationIsValid(); } - - public class When_using_a_custom_destination_naming_convention : SpecBase + public class When_using_a_custom_destination_naming_convention : AutoMapperSpecBase { - private TypeMap _map; - private ProfileMap _mappingOptions; - private class Source { public SubSource SomeSource { get; set; } } - private class SubSource { public int Value { get; set; } } - private class Destination { public int some__source__value { get; set; } } - private class TestProfile : Profile { - public override string ProfileName => "Test"; - } - - protected override void Establish_context() - { - var namingConvention = new StubNamingConvention{ SeparatorCharacter = "__", SplittingExpression = new Regex(@"[\p{Ll}\p{Lu}0-9]+(?=__?)") }; - - var profile = new TestProfile(); - profile.Internal().AddMemberConfiguration().AddMember(_ => + public TestProfile() { - _.SourceMemberNamingConvention = new PascalCaseNamingConvention(); - _.DestinationMemberNamingConvention = namingConvention; - }); - _mappingOptions = new ProfileMap(profile); - } - - protected override void Because_of() - { - _map = new TypeMap(typeof(Source), typeof(Destination), _mappingOptions); + var namingConvention = new StubNamingConvention{ SeparatorCharacter = "__", SplittingExpression = new Regex(@"[\p{Ll}\p{Lu}0-9]+(?=__?)") }; + this.Internal().AddMemberConfiguration().AddMember(_ => + { + _.SourceMemberNamingConvention = new PascalCaseNamingConvention(); + _.DestinationMemberNamingConvention = namingConvention; + }); + } } - + protected override MapperConfiguration CreateConfiguration() => new(c => c.AddProfile()); [Fact] - public void Should_split_using_naming_convention_rules() - { - _map.PropertyMaps.Count().ShouldBe(1); - } + public void Should_split_using_naming_convention_rules() => AssertConfigurationIsValid(); } public class When_using_a_source_member_name_replacer : SpecBase @@ -179,7 +139,7 @@ public void Should_map_properties_with_different_names() }); var mapper = config.CreateMapper(); - var dest = mapper.Map(new Source { Ävíator = 3, SubAirlinaFlight = 4, Value = 5 }); + var dest = mapper.Map(new Source {Ävíator = 3, SubAirlinaFlight = 4, Value = 5}); dest.Aviator.ShouldBe(3); dest.SubAirlineFlight.ShouldBe(4); dest.Value.ShouldBe(5); diff --git a/src/UnitTests/ReverseMapping.cs b/src/UnitTests/ReverseMapping.cs index f4437e8f5d..37a0ef4e9e 100644 --- a/src/UnitTests/ReverseMapping.cs +++ b/src/UnitTests/ReverseMapping.cs @@ -3,8 +3,8 @@ using System.Linq; using System; using System.Text.RegularExpressions; +using System.Reflection; using AutoMapper.Internal; -using System.Collections.Generic; namespace AutoMapper.UnitTests { @@ -18,7 +18,7 @@ class Destination { public Guid Id { get; set; } } - protected override MapperConfiguration CreateConfiguration() => new(c => + protected override MapperConfiguration CreateConfiguration() => new(c=> c.CreateMap().ForMember(src => src.Id, opt => opt.MapFrom(_ => Guid.Empty)).ReverseMap()); [Fact] public void Validate() => AssertConfigurationIsValid(); @@ -45,7 +45,7 @@ public class Three2 { } - protected override MapperConfiguration CreateConfiguration() => new(cfg => + protected override MapperConfiguration CreateConfiguration() => new(cfg=> { cfg.CreateMap() .ForMember(d => d.Name, o => o.MapFrom(s => "name")) @@ -118,7 +118,7 @@ class OrderDto public int OrderItemsCount { get; set; } } - protected override MapperConfiguration CreateConfiguration() => new(c => + protected override MapperConfiguration CreateConfiguration() => new(c=> { c.CreateMap().ReverseMap(); }); @@ -165,12 +165,10 @@ public class OrderDto [Fact] public void Should_flatten() { - var model = new Order - { - CustomerHolder = new CustomerHolder - { - Customer = new Customer { Name = "George Costanza", Total = 74.85m } - } + var model = new Order { + CustomerHolder = new CustomerHolder { + Customer = new Customer { Name = "George Costanza", Total = 74.85m } + } }; var dto = Mapper.Map(model); dto.CustomerName.ShouldBe("George Costanza"); @@ -308,8 +306,8 @@ public class OrderDto { cfg.CreateMap() .ReverseMap() - .ForMember(d => d.Customerholder, o => o.Ignore()) - .ForPath(d => d.Customerholder.Customer.Total, o => o.MapFrom(s => s.CustomerholderCustomerTotal)); + .ForMember(d=>d.Customerholder, o=>o.Ignore()) + .ForPath(d=>d.Customerholder.Customer.Total, o=>o.MapFrom(s=>s.CustomerholderCustomerTotal)); }); [Fact] @@ -386,7 +384,7 @@ public class UnderscoreNamingConvention : INamingConvention public Regex SplittingExpression { get; } = new Regex(@"\p{Lu}[a-z0-9]*(?=_?)"); public string SeparatorCharacter => "_"; - public List> Split(string input) => SplittingExpression.Matches(input).Select(m => m.Value.AsMemory()).ToList(); + public string[] Split(string input) => SplittingExpression.Matches(input).Select(m => m.Value).ToArray(); } protected override MapperConfiguration CreateConfiguration() => new(cfg => From 93576ef4085295361c7b9397c0b07f91f9ca91f3 Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Mon, 15 Aug 2022 10:57:39 +0300 Subject: [PATCH 24/67] make TypeMapPlanBuilder a struct --- Directory.Build.props | 2 +- src/AutoMapper/ApiCompatBaseline.txt | 4 +- .../Execution/TypeMapPlanBuilder.cs | 87 +++++++++---------- 3 files changed, 47 insertions(+), 46 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index a585cc8acf..0472afddaa 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -2,7 +2,7 @@ Jimmy Bogard - latest + preview $(NoWarn);CS1701;CS1702;CS1591 true strict diff --git a/src/AutoMapper/ApiCompatBaseline.txt b/src/AutoMapper/ApiCompatBaseline.txt index e7886b6737..1db2729018 100644 --- a/src/AutoMapper/ApiCompatBaseline.txt +++ b/src/AutoMapper/ApiCompatBaseline.txt @@ -38,6 +38,8 @@ CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'AutoMappe CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'AutoMapper.Configuration.Annotations.UseExistingValueAttribute' changed from '[AttributeUsageAttribute(384)]' in the contract to '[AttributeUsageAttribute(AttributeTargets.Field | AttributeTargets.Property)]' in the implementation. CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'AutoMapper.Configuration.Annotations.ValueConverterAttribute' changed from '[AttributeUsageAttribute(384)]' in the contract to '[AttributeUsageAttribute(AttributeTargets.Field | AttributeTargets.Property)]' in the implementation. CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'AutoMapper.Configuration.Annotations.ValueResolverAttribute' changed from '[AttributeUsageAttribute(384)]' in the contract to '[AttributeUsageAttribute(AttributeTargets.Field | AttributeTargets.Property)]' in the implementation. +CannotSealType : Type 'AutoMapper.Execution.TypeMapPlanBuilder' is actually (has the sealed modifier) sealed in the implementation but not sealed in the contract. +TypeCannotChangeClassification : Type 'AutoMapper.Execution.TypeMapPlanBuilder' is a 'struct' in the implementation but is a 'class' in the contract. CannotRemoveBaseTypeOrInterface : Type 'AutoMapper.Internal.Mappers.CollectionMapper' does not implement interface 'AutoMapper.Internal.Mappers.IObjectMapperInfo' in the implementation but it does in the contract. MembersMustExist : Member 'public AutoMapper.Internal.TypePair AutoMapper.Internal.Mappers.CollectionMapper.GetAssociatedTypes(AutoMapper.Internal.TypePair)' does not exist in the implementation but it does exist in the contract. InterfacesShouldHaveSameMembers : Default interface member 'public System.Nullable AutoMapper.Internal.Mappers.IObjectMapper.GetAssociatedTypes(AutoMapper.Internal.TypePair)' is present in the implementation but not in the contract. @@ -49,4 +51,4 @@ MembersMustExist : Member 'public AutoMapper.Internal.TypePair AutoMapper.Intern MembersMustExist : Member 'public System.Linq.IQueryable AutoMapper.QueryableExtensions.Extensions.Map(System.Linq.IQueryable, System.Linq.IQueryable, AutoMapper.IConfigurationProvider)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Collections.Generic.IReadOnlyCollection AutoMapper.QueryableExtensions.MemberVisitor.MemberPath.get()' does not exist in the implementation but it does exist in the contract. TypesMustExist : Type 'AutoMapper.QueryableExtensions.Impl.MemberAccessQueryMapperVisitor' does not exist in the implementation but it does exist in the contract. -Total Issues: 50 +Total Issues: 52 diff --git a/src/AutoMapper/Execution/TypeMapPlanBuilder.cs b/src/AutoMapper/Execution/TypeMapPlanBuilder.cs index 32f1b36f83..5802866690 100644 --- a/src/AutoMapper/Execution/TypeMapPlanBuilder.cs +++ b/src/AutoMapper/Execution/TypeMapPlanBuilder.cs @@ -9,9 +9,8 @@ namespace AutoMapper.Execution using static Expression; using static ExpressionBuilder; using Internal; - using AutoMapper.Configuration; - - public class TypeMapPlanBuilder + using Configuration; + public struct TypeMapPlanBuilder { private static readonly MethodInfo MappingError = typeof(TypeMapPlanBuilder).GetStaticMethod(nameof(MemberMappingError)); private readonly IGlobalConfiguration _configurationProvider; @@ -71,12 +70,12 @@ static void Clear(ref HashSet typeMapsPath) typeMapsPath.Clear(); } } - void IncludeMembers(ParameterExpression[] parameters, List variables, List statements) - { - variables.AddRange(_typeMap.IncludedMembersTypeMaps.Select(i => i.Variable)); - statements.AddRange(variables.Zip(_typeMap.IncludedMembersTypeMaps, (v, i) => - Assign(v, i.MemberExpression.ReplaceParameters(parameters).NullCheck()))); - } + } + void IncludeMembers(ParameterExpression[] parameters, List variables, List statements) + { + variables.AddRange(_typeMap.IncludedMembersTypeMaps.Select(i => i.Variable)); + statements.AddRange(variables.Zip(_typeMap.IncludedMembersTypeMaps, (v, i) => + Assign(v, i.MemberExpression.ReplaceParameters(parameters).NullCheck()))); } private static void CheckForCycles(IGlobalConfiguration configurationProvider, TypeMap typeMap, HashSet typeMapsPath) { @@ -321,47 +320,47 @@ private Expression CreatePropertyMapFunc(MemberMap memberMap, Expression destina Precondition(memberMap, customSource); } return Block(_propertyMapVariables, _propertyMapExpressions); - Expression DestinationMemberValue(MemberMap memberMap, Expression destinationMemberGetter, bool destinationMemberReadOnly) + } + Expression DestinationMemberValue(MemberMap memberMap, Expression destinationMemberGetter, bool destinationMemberReadOnly) + { + if (memberMap is { UseDestinationValue: true } || (memberMap.UseDestinationValue is null && destinationMemberReadOnly)) { - if (memberMap is { UseDestinationValue: true } || (memberMap.UseDestinationValue is null && destinationMemberReadOnly)) - { - return destinationMemberGetter; - } - else if (DestinationType.IsValueType) - { - return Default(memberMap.DestinationType); - } - else - { - return Condition(ReferenceEqual(_initialDestination, Null), Default(memberMap.DestinationType), destinationMemberGetter); - } + return destinationMemberGetter; + } + else if (DestinationType.IsValueType) + { + return Default(memberMap.DestinationType); } - void Precondition(MemberMap memberMap, Expression customSource) + else { - var preCondition = memberMap.PreCondition.ConvertReplaceParameters(customSource, _destination, ContextParameter); - var ifThen = IfThen(preCondition, Block(_propertyMapExpressions)); - _propertyMapExpressions.Clear(); - _propertyMapExpressions.Add(ifThen); + return Condition(ReferenceEqual(_initialDestination, Null), Default(memberMap.DestinationType), destinationMemberGetter); } - ParameterExpression SetVariables(Expression valueResolver, ParameterExpression resolvedValueVariable, Expression mappedMember) + } + void Precondition(MemberMap memberMap, Expression customSource) + { + var preCondition = memberMap.PreCondition.ConvertReplaceParameters(customSource, _destination, ContextParameter); + var ifThen = IfThen(preCondition, Block(_propertyMapExpressions)); + _propertyMapExpressions.Clear(); + _propertyMapExpressions.Add(ifThen); + } + ParameterExpression SetVariables(Expression valueResolver, ParameterExpression resolvedValueVariable, Expression mappedMember) + { + _propertyMapExpressions.Clear(); + _propertyMapVariables.Clear(); + _propertyMapVariables.Add(resolvedValueVariable); + _propertyMapExpressions.Add(Assign(resolvedValueVariable, valueResolver)); + ParameterExpression mappedMemberVariable; + if (mappedMember == resolvedValueVariable) { - _propertyMapExpressions.Clear(); - _propertyMapVariables.Clear(); - _propertyMapVariables.Add(resolvedValueVariable); - _propertyMapExpressions.Add(Assign(resolvedValueVariable, valueResolver)); - ParameterExpression mappedMemberVariable; - if (mappedMember == resolvedValueVariable) - { - mappedMemberVariable = resolvedValueVariable; - } - else - { - mappedMemberVariable = Variable(mappedMember.Type, "mappedValue"); - _propertyMapVariables.Add(mappedMemberVariable); - _propertyMapExpressions.Add(Assign(mappedMemberVariable, mappedMember)); - } - return mappedMemberVariable; + mappedMemberVariable = resolvedValueVariable; + } + else + { + mappedMemberVariable = Variable(mappedMember.Type, "mappedValue"); + _propertyMapVariables.Add(mappedMemberVariable); + _propertyMapExpressions.Add(Assign(mappedMemberVariable, mappedMember)); } + return mappedMemberVariable; } Expression MapMember(MemberMap memberMap, Expression destinationMemberValue, ParameterExpression resolvedValue) { From 3adb02f5d320771f4c8a91540dbd84a4fbe94141 Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Mon, 15 Aug 2022 11:26:04 +0300 Subject: [PATCH 25/67] use readonly record struct --- Directory.Build.props | 2 +- src/AutoMapper/ApiCompatBaseline.txt | 37 +++++++++++- src/AutoMapper/AssemblyInfo.cs | 7 ++- .../Configuration/ConfigurationValidator.cs | 26 +-------- .../PathConfigurationExpression.cs | 17 +----- src/AutoMapper/Execution/ExpressionBuilder.cs | 13 +---- src/AutoMapper/Execution/ProxyGenerator.cs | 44 ++------------ .../Execution/TypeMapPlanBuilder.cs | 4 +- src/AutoMapper/Internal/MemberPath.cs | 21 +------ src/AutoMapper/Internal/TypeDetails.cs | 10 +--- src/AutoMapper/Internal/TypePair.cs | 30 +--------- .../Mappers/FromStringDictionaryMapper.cs | 23 +++----- src/AutoMapper/MemberMap.cs | 12 +--- .../QueryableExtensions/Extensions.cs | 45 +++++---------- .../QueryableExtensions/ProjectionBuilder.cs | 57 +++++-------------- src/AutoMapper/ResolutionContext.cs | 16 +----- 16 files changed, 100 insertions(+), 264 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 0472afddaa..a585cc8acf 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -2,7 +2,7 @@ Jimmy Bogard - preview + latest $(NoWarn);CS1701;CS1702;CS1591 true strict diff --git a/src/AutoMapper/ApiCompatBaseline.txt b/src/AutoMapper/ApiCompatBaseline.txt index 1db2729018..80c704dfdc 100644 --- a/src/AutoMapper/ApiCompatBaseline.txt +++ b/src/AutoMapper/ApiCompatBaseline.txt @@ -1,5 +1,9 @@ Compat issues with assembly AutoMapper: CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'AutoMapper.AutoMapAttribute' changed from '[AttributeUsageAttribute(1036, AllowMultiple=true)]' in the contract to '[AttributeUsageAttribute(AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Struct, AllowMultiple=true)]' in the implementation. +MembersMustExist : Member 'public System.Object System.Object AutoMapper.ContextCacheKey.Source' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public System.Boolean AutoMapper.ContextCacheKey.Equals(AutoMapper.ContextCacheKey)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public System.Boolean AutoMapper.ContextCacheKey.op_Equality(AutoMapper.ContextCacheKey, AutoMapper.ContextCacheKey)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public System.Boolean AutoMapper.ContextCacheKey.op_Inequality(AutoMapper.ContextCacheKey, AutoMapper.ContextCacheKey)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.String AutoMapper.ExactMatchNamingConvention.ReplaceValue(System.Text.RegularExpressions.Match)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Text.RegularExpressions.Regex AutoMapper.ExactMatchNamingConvention.SplittingExpression.get()' does not exist in the implementation but it does exist in the contract. InterfacesShouldHaveSameMembers : Interface member 'public TMappingExpression AutoMapper.IMappingExpressionBase.AsProxy()' is present in the implementation but not in the contract. @@ -23,6 +27,8 @@ MembersMustExist : Member 'public System.String AutoMapper.PascalCaseNamingConve MembersMustExist : Member 'public System.Text.RegularExpressions.Regex AutoMapper.PascalCaseNamingConvention.SplittingExpression.get()' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public AutoMapper.IMappingOperationOptions AutoMapper.ResolutionContext.Options.get()' does not exist in the implementation but it does exist in the contract. TypesMustExist : Type 'AutoMapper.ValueResolverConfiguration' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public System.Linq.Expressions.LambdaExpression System.Linq.Expressions.LambdaExpression AutoMapper.ValueTransformerConfiguration.TransformerExpression' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public System.Type System.Type AutoMapper.ValueTransformerConfiguration.ValueType' does not exist in the implementation but it does exist in the contract. InterfacesShouldHaveSameMembers : Default interface member 'public System.Boolean AutoMapper.Configuration.IPropertyMapConfiguration.Ignored' is present in the implementation but not in the contract. InterfacesShouldHaveSameMembers : Default interface member 'public System.Boolean AutoMapper.Configuration.IPropertyMapConfiguration.Ignored.get()' is present in the implementation but not in the contract. CannotRemoveBaseTypeOrInterface : Type 'AutoMapper.Configuration.MappingExpression' does not inherit from base type 'AutoMapper.Configuration.MappingExpressionBase' in the implementation but it does in the contract. @@ -30,6 +36,8 @@ CannotRemoveBaseTypeOrInterface : Type 'AutoMapper.Configuration.MappingExpressi TypesMustExist : Type 'AutoMapper.Configuration.MappingExpressionBase' does not exist in the implementation but it does exist in the contract. CannotRemoveBaseTypeOrInterface : Type 'AutoMapper.Configuration.MappingExpressionBase' does not inherit from base type 'AutoMapper.Configuration.MappingExpressionBase' in the implementation but it does in the contract. MembersMustExist : Member 'public void AutoMapper.Configuration.MappingExpressionBase.AsProxy()' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public void AutoMapper.Configuration.ValidationContext..ctor(AutoMapper.Internal.TypePair, AutoMapper.MemberMap, AutoMapper.Internal.Mappers.IObjectMapper)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public void AutoMapper.Configuration.ValidationContext..ctor(AutoMapper.Internal.TypePair, AutoMapper.MemberMap, AutoMapper.TypeMap)' does not exist in the implementation but it does exist in the contract. CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'AutoMapper.Configuration.Annotations.IgnoreAttribute' changed from '[AttributeUsageAttribute(384)]' in the contract to '[AttributeUsageAttribute(AttributeTargets.Field | AttributeTargets.Property)]' in the implementation. CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'AutoMapper.Configuration.Annotations.MapAtRuntimeAttribute' changed from '[AttributeUsageAttribute(384)]' in the contract to '[AttributeUsageAttribute(AttributeTargets.Field | AttributeTargets.Property)]' in the implementation. CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'AutoMapper.Configuration.Annotations.MappingOrderAttribute' changed from '[AttributeUsageAttribute(384)]' in the contract to '[AttributeUsageAttribute(AttributeTargets.Field | AttributeTargets.Property)]' in the implementation. @@ -38,8 +46,35 @@ CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'AutoMappe CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'AutoMapper.Configuration.Annotations.UseExistingValueAttribute' changed from '[AttributeUsageAttribute(384)]' in the contract to '[AttributeUsageAttribute(AttributeTargets.Field | AttributeTargets.Property)]' in the implementation. CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'AutoMapper.Configuration.Annotations.ValueConverterAttribute' changed from '[AttributeUsageAttribute(384)]' in the contract to '[AttributeUsageAttribute(AttributeTargets.Field | AttributeTargets.Property)]' in the implementation. CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'AutoMapper.Configuration.Annotations.ValueResolverAttribute' changed from '[AttributeUsageAttribute(384)]' in the contract to '[AttributeUsageAttribute(AttributeTargets.Field | AttributeTargets.Property)]' in the implementation. +MembersMustExist : Member 'public System.Linq.Expressions.Expression System.Linq.Expressions.Expression AutoMapper.Execution.Member.Expression' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public System.Linq.Expressions.Expression System.Linq.Expressions.Expression AutoMapper.Execution.Member.Target' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public System.Reflection.MemberInfo System.Reflection.MemberInfo AutoMapper.Execution.Member.MemberInfo' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public System.Boolean System.Boolean AutoMapper.Execution.PropertyDescription.CanWrite' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public System.String System.String AutoMapper.Execution.PropertyDescription.Name' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public System.Type System.Type AutoMapper.Execution.PropertyDescription.Type' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public System.Boolean AutoMapper.Execution.PropertyDescription.Equals(AutoMapper.Execution.PropertyDescription)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public System.Boolean AutoMapper.Execution.PropertyDescription.op_Equality(AutoMapper.Execution.PropertyDescription, AutoMapper.Execution.PropertyDescription)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public System.Boolean AutoMapper.Execution.PropertyDescription.op_Inequality(AutoMapper.Execution.PropertyDescription, AutoMapper.Execution.PropertyDescription)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public AutoMapper.Execution.PropertyDescription[] AutoMapper.Execution.PropertyDescription[] AutoMapper.Execution.TypeDescription.AdditionalProperties' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public System.Type System.Type AutoMapper.Execution.TypeDescription.Type' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public void AutoMapper.Execution.TypeDescription..ctor(System.Type)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public void AutoMapper.Execution.TypeDescription..ctor(System.Type, System.Collections.Generic.IEnumerable)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public System.Boolean AutoMapper.Execution.TypeDescription.op_Equality(AutoMapper.Execution.TypeDescription, AutoMapper.Execution.TypeDescription)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public System.Boolean AutoMapper.Execution.TypeDescription.op_Inequality(AutoMapper.Execution.TypeDescription, AutoMapper.Execution.TypeDescription)' does not exist in the implementation but it does exist in the contract. CannotSealType : Type 'AutoMapper.Execution.TypeMapPlanBuilder' is actually (has the sealed modifier) sealed in the implementation but not sealed in the contract. TypeCannotChangeClassification : Type 'AutoMapper.Execution.TypeMapPlanBuilder' is a 'struct' in the implementation but is a 'class' in the contract. +MembersMustExist : Member 'public System.Reflection.ConstructorInfo System.Reflection.ConstructorInfo AutoMapper.Internal.ConstructorParameters.Constructor' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public System.Reflection.ParameterInfo[] System.Reflection.ParameterInfo[] AutoMapper.Internal.ConstructorParameters.Parameters' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public AutoMapper.Internal.TypePair AutoMapper.Internal.TypePair AutoMapper.Internal.MapRequest.RequestedTypes' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public AutoMapper.Internal.TypePair AutoMapper.Internal.TypePair AutoMapper.Internal.MapRequest.RuntimeTypes' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public AutoMapper.MemberMap AutoMapper.MemberMap AutoMapper.Internal.MapRequest.MemberMap' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public System.Boolean AutoMapper.Internal.MapRequest.op_Equality(AutoMapper.Internal.MapRequest, AutoMapper.Internal.MapRequest)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public System.Boolean AutoMapper.Internal.MapRequest.op_Inequality(AutoMapper.Internal.MapRequest, AutoMapper.Internal.MapRequest)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public System.Type System.Type AutoMapper.Internal.TypePair.DestinationType' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public System.Type System.Type AutoMapper.Internal.TypePair.SourceType' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public System.Boolean AutoMapper.Internal.TypePair.Equals(AutoMapper.Internal.TypePair)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public System.Boolean AutoMapper.Internal.TypePair.op_Equality(AutoMapper.Internal.TypePair, AutoMapper.Internal.TypePair)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public System.Boolean AutoMapper.Internal.TypePair.op_Inequality(AutoMapper.Internal.TypePair, AutoMapper.Internal.TypePair)' does not exist in the implementation but it does exist in the contract. CannotRemoveBaseTypeOrInterface : Type 'AutoMapper.Internal.Mappers.CollectionMapper' does not implement interface 'AutoMapper.Internal.Mappers.IObjectMapperInfo' in the implementation but it does in the contract. MembersMustExist : Member 'public AutoMapper.Internal.TypePair AutoMapper.Internal.Mappers.CollectionMapper.GetAssociatedTypes(AutoMapper.Internal.TypePair)' does not exist in the implementation but it does exist in the contract. InterfacesShouldHaveSameMembers : Default interface member 'public System.Nullable AutoMapper.Internal.Mappers.IObjectMapper.GetAssociatedTypes(AutoMapper.Internal.TypePair)' is present in the implementation but not in the contract. @@ -51,4 +86,4 @@ MembersMustExist : Member 'public AutoMapper.Internal.TypePair AutoMapper.Intern MembersMustExist : Member 'public System.Linq.IQueryable AutoMapper.QueryableExtensions.Extensions.Map(System.Linq.IQueryable, System.Linq.IQueryable, AutoMapper.IConfigurationProvider)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Collections.Generic.IReadOnlyCollection AutoMapper.QueryableExtensions.MemberVisitor.MemberPath.get()' does not exist in the implementation but it does exist in the contract. TypesMustExist : Type 'AutoMapper.QueryableExtensions.Impl.MemberAccessQueryMapperVisitor' does not exist in the implementation but it does exist in the contract. -Total Issues: 52 +Total Issues: 87 diff --git a/src/AutoMapper/AssemblyInfo.cs b/src/AutoMapper/AssemblyInfo.cs index c08097dc7e..40bb836e5c 100644 --- a/src/AutoMapper/AssemblyInfo.cs +++ b/src/AutoMapper/AssemblyInfo.cs @@ -4,4 +4,9 @@ [assembly: CLSCompliant(true)] [assembly: ComVisible(false)] -[assembly: NeutralResourcesLanguage("en")] \ No newline at end of file +[assembly: NeutralResourcesLanguage("en")] + +namespace System.Runtime.CompilerServices +{ + static class IsExternalInit { } +} \ No newline at end of file diff --git a/src/AutoMapper/Configuration/ConfigurationValidator.cs b/src/AutoMapper/Configuration/ConfigurationValidator.cs index ad94439bec..69655edde2 100644 --- a/src/AutoMapper/Configuration/ConfigurationValidator.cs +++ b/src/AutoMapper/Configuration/ConfigurationValidator.cs @@ -125,7 +125,7 @@ private void DryRunTypeMap(ICollection typeMapsChecked, TypePair types, { throw new AutoMapperConfigurationException(memberMap.TypeMap.Types) { MemberMap = memberMap }; } - var context = new ValidationContext(types, memberMap, mapperToUse); + var context = new ValidationContext(types, memberMap, ObjectMapper: mapperToUse); Validate(context); if (mapperToUse.GetAssociatedTypes(types) is TypePair newTypes && newTypes != types) { @@ -153,27 +153,5 @@ private void CheckPropertyMaps(ICollection typeMapsChecked, TypeMap typ } } } - public readonly struct ValidationContext - { - public readonly IObjectMapper ObjectMapper { get; } - public readonly MemberMap MemberMap { get; } - public readonly TypeMap TypeMap { get; } - public readonly TypePair Types { get; } - - public ValidationContext(TypePair types, MemberMap memberMap, IObjectMapper objectMapper) : this(types, memberMap, objectMapper, null) - { - } - - public ValidationContext(TypePair types, MemberMap memberMap, TypeMap typeMap) : this(types, memberMap, null, typeMap) - { - } - - private ValidationContext(TypePair types, MemberMap memberMap, IObjectMapper objectMapper, TypeMap typeMap) - { - ObjectMapper = objectMapper; - TypeMap = typeMap; - Types = types; - MemberMap = memberMap; - } - } + public readonly record struct ValidationContext(TypePair Types, MemberMap MemberMap, TypeMap TypeMap = null, IObjectMapper ObjectMapper = null); } \ No newline at end of file diff --git a/src/AutoMapper/Configuration/PathConfigurationExpression.cs b/src/AutoMapper/Configuration/PathConfigurationExpression.cs index 6185cd46c4..7aea462dd3 100644 --- a/src/AutoMapper/Configuration/PathConfigurationExpression.cs +++ b/src/AutoMapper/Configuration/PathConfigurationExpression.cs @@ -27,22 +27,7 @@ public interface IPathConfigurationExpression void Ignore(); void Condition(Func, bool> condition); } - public readonly struct ConditionParameters - { - public readonly TSource Source { get; } - public readonly TDestination Destination { get; } - public readonly TMember SourceMember { get; } - public readonly TMember DestinationMember { get; } - public readonly ResolutionContext Context { get; } - public ConditionParameters(TSource source, TDestination destination, TMember sourceMember, TMember destinationMember, ResolutionContext context) - { - Source = source; - Destination = destination; - SourceMember = sourceMember; - DestinationMember = destinationMember; - Context = context; - } - } + public readonly record struct ConditionParameters(TSource Source, TDestination Destination, TMember SourceMember, TMember DestinationMember, ResolutionContext Context); public class PathConfigurationExpression : IPathConfigurationExpression, IPropertyMapConfiguration { private readonly LambdaExpression _destinationExpression; diff --git a/src/AutoMapper/Execution/ExpressionBuilder.cs b/src/AutoMapper/Execution/ExpressionBuilder.cs index 48674c551d..607a123d2e 100644 --- a/src/AutoMapper/Execution/ExpressionBuilder.cs +++ b/src/AutoMapper/Execution/ExpressionBuilder.cs @@ -416,16 +416,5 @@ class ConvertParameterReplaceVisitor : ParameterReplaceVisitor public override void Replace(Expression oldNode, Expression newNode) => base.Replace(oldNode, ToType(newNode, oldNode.Type)); } } - public readonly struct Member - { - public Member(Expression expression, MemberInfo memberInfo, Expression target) - { - Expression = expression; - MemberInfo = memberInfo; - Target = target; - } - public readonly Expression Expression; - public readonly MemberInfo MemberInfo; - public readonly Expression Target; - } + public readonly record struct Member(Expression Expression, MemberInfo MemberInfo, Expression Target); } \ No newline at end of file diff --git a/src/AutoMapper/Execution/ProxyGenerator.cs b/src/AutoMapper/Execution/ProxyGenerator.cs index 140440052b..5976eac9f9 100644 --- a/src/AutoMapper/Execution/ProxyGenerator.cs +++ b/src/AutoMapper/Execution/ProxyGenerator.cs @@ -119,9 +119,9 @@ void GenerateConstructor() ctorIl.Emit(OpCodes.Ret); } } - public static Type GetProxyType(Type interfaceType) => ProxyTypes.GetOrAdd(new TypeDescription(interfaceType)); + public static Type GetProxyType(Type interfaceType) => ProxyTypes.GetOrAdd(new(interfaceType, Array.Empty())); public static Type GetSimilarType(Type sourceType, IEnumerable additionalProperties) => - ProxyTypes.GetOrAdd(new TypeDescription(sourceType, additionalProperties)); + ProxyTypes.GetOrAdd(new(sourceType, additionalProperties.OrderBy(p=>p.Name).ToArray())); class PropertyEmitter { private static readonly MethodInfo ProxyBaseNotifyPropertyChanged = typeof(ProxyBase).GetInstanceMethod("NotifyPropertyChanged"); @@ -174,20 +174,8 @@ public ProxyBase() { } protected void NotifyPropertyChanged(PropertyChangedEventHandler handler, string method) => handler?.Invoke(this, new PropertyChangedEventArgs(method)); } - public readonly struct TypeDescription : IEquatable + public readonly record struct TypeDescription(Type Type, PropertyDescription[] AdditionalProperties) { - public readonly Type Type; - public readonly PropertyDescription[] AdditionalProperties; - public TypeDescription(Type type) : this(type, Array.Empty()) { } - public TypeDescription(Type type, IEnumerable additionalProperties) - { - Type = type ?? throw new ArgumentNullException(nameof(type)); - if (additionalProperties == null) - { - throw new ArgumentNullException(nameof(additionalProperties)); - } - AdditionalProperties = additionalProperties.OrderBy(p => p.Name).ToArray(); - } public override int GetHashCode() { var hashCode = new HashCode(); @@ -198,33 +186,11 @@ public override int GetHashCode() } return hashCode.ToHashCode(); } - public override bool Equals(object other) => other is TypeDescription description && Equals(description); public bool Equals(TypeDescription other) => Type == other.Type && AdditionalProperties.SequenceEqual(other.AdditionalProperties); - public static bool operator ==(TypeDescription left, TypeDescription right) => left.Equals(right); - public static bool operator !=(TypeDescription left, TypeDescription right) => !left.Equals(right); } [DebuggerDisplay("{Name}-{Type.Name}")] - public readonly struct PropertyDescription : IEquatable + public readonly record struct PropertyDescription(string Name, Type Type, bool CanWrite = true) { - public readonly string Name; - public readonly Type Type; - public readonly bool CanWrite; - public PropertyDescription(string name, Type type, bool canWrite = true) - { - Name = name; - Type = type; - CanWrite = canWrite; - } - public PropertyDescription(PropertyInfo property) - { - Name = property.Name; - Type = property.PropertyType; - CanWrite = property.CanWrite; - } - public override int GetHashCode() => HashCode.Combine(Name, Type, CanWrite); - public override bool Equals(object other) => other is PropertyDescription description && Equals(description); - public bool Equals(PropertyDescription other) => Name == other.Name && Type == other.Type && CanWrite == other.CanWrite; - public static bool operator ==(PropertyDescription left, PropertyDescription right) => left.Equals(right); - public static bool operator !=(PropertyDescription left, PropertyDescription right) => !left.Equals(right); + public PropertyDescription(PropertyInfo property) : this(property.Name, property.PropertyType, property.CanWrite) { } } } \ No newline at end of file diff --git a/src/AutoMapper/Execution/TypeMapPlanBuilder.cs b/src/AutoMapper/Execution/TypeMapPlanBuilder.cs index 5802866690..64e3155b60 100644 --- a/src/AutoMapper/Execution/TypeMapPlanBuilder.cs +++ b/src/AutoMapper/Execution/TypeMapPlanBuilder.cs @@ -17,8 +17,8 @@ public struct TypeMapPlanBuilder private readonly ParameterExpression _destination; private readonly ParameterExpression _initialDestination; private readonly TypeMap _typeMap; - private List _propertyMapVariables; - private List _propertyMapExpressions; + private List _propertyMapVariables = null; + private List _propertyMapExpressions = null; public TypeMapPlanBuilder(IGlobalConfiguration configurationProvider, TypeMap typeMap) { _configurationProvider = configurationProvider; diff --git a/src/AutoMapper/Internal/MemberPath.cs b/src/AutoMapper/Internal/MemberPath.cs index 7ba4d87e10..1ca0e82a2e 100644 --- a/src/AutoMapper/Internal/MemberPath.cs +++ b/src/AutoMapper/Internal/MemberPath.cs @@ -3,30 +3,18 @@ using System.ComponentModel; using System.Linq; using System.Reflection; - namespace AutoMapper.Internal { using Execution; [EditorBrowsable(EditorBrowsableState.Never)] - public readonly struct MemberPath : IEquatable + public readonly record struct MemberPath(MemberInfo[] Members) { public static readonly MemberPath Empty = new(Array.Empty()); - public readonly MemberInfo[] Members; - public MemberPath(Stack members) : this(members.ToMemberInfos()){} - - public MemberPath(MemberInfo[] members) => Members = members; - public MemberInfo Last => Members[^1]; - public MemberInfo First => Members[0]; - public int Length => Members.Length; - public bool Equals(MemberPath other) => Members.SequenceEqual(other.Members); - - public override bool Equals(object obj) => obj is MemberPath path && Equals(path); - public override int GetHashCode() { var hashCode = new HashCode(); @@ -36,13 +24,7 @@ public override int GetHashCode() } return hashCode.ToHashCode(); } - public override string ToString() => string.Join(".", Members.Select(mi => mi.Name)); - - public static bool operator==(MemberPath left, MemberPath right) => left.Equals(right); - - public static bool operator!=(MemberPath left, MemberPath right) => !left.Equals(right); - public bool StartsWith(MemberPath path) { if (path.Length > Length) @@ -58,7 +40,6 @@ public bool StartsWith(MemberPath path) } return true; } - public MemberPath Concat(IEnumerable memberInfos) => new(Members.Concat(memberInfos).ToArray()); } } \ No newline at end of file diff --git a/src/AutoMapper/Internal/TypeDetails.cs b/src/AutoMapper/Internal/TypeDetails.cs index 3932912236..71740b5aca 100644 --- a/src/AutoMapper/Internal/TypeDetails.cs +++ b/src/AutoMapper/Internal/TypeDetails.cs @@ -203,15 +203,9 @@ private IEnumerable GetProperties(Func propert private IEnumerable GetFields(Func fieldAvailableFor) => GetTypeInheritance().SelectMany(type => type.GetFields(TypeExtensions.InstanceFlags).Where(field => fieldAvailableFor(field) && Config.ShouldMapField(field))); } - public readonly struct ConstructorParameters + public readonly record struct ConstructorParameters(ConstructorInfo Constructor, ParameterInfo[] Parameters) { - public readonly ConstructorInfo Constructor; - public readonly ParameterInfo[] Parameters; - public ConstructorParameters(ConstructorInfo constructor) - { - Constructor = constructor; - Parameters = constructor.GetParameters(); - } + public ConstructorParameters(ConstructorInfo constructor) : this(constructor, constructor.GetParameters()){} public int ParametersCount => Parameters.Length; public bool AllParametersOptional() => Parameters.All(p => p.IsOptional); } diff --git a/src/AutoMapper/Internal/TypePair.cs b/src/AutoMapper/Internal/TypePair.cs index 50f9b4c331..4139844da4 100644 --- a/src/AutoMapper/Internal/TypePair.cs +++ b/src/AutoMapper/Internal/TypePair.cs @@ -3,37 +3,15 @@ namespace AutoMapper.Internal { [DebuggerDisplay("{RequestedTypes.SourceType.Name}, {RequestedTypes.DestinationType.Name} : {RuntimeTypes.SourceType.Name}, {RuntimeTypes.DestinationType.Name}")] - public readonly struct MapRequest : IEquatable + public readonly record struct MapRequest(TypePair RequestedTypes, TypePair RuntimeTypes, MemberMap MemberMap) { - public readonly TypePair RequestedTypes; - public readonly TypePair RuntimeTypes; - public readonly MemberMap MemberMap; - public MapRequest(TypePair requestedTypes, TypePair runtimeTypes, MemberMap memberMap) - { - RequestedTypes = requestedTypes; - RuntimeTypes = runtimeTypes; - MemberMap = memberMap; - } public bool Equals(MapRequest other) => RequestedTypes.Equals(other.RequestedTypes) && RuntimeTypes.Equals(other.RuntimeTypes) && (MemberMap == other.MemberMap || MemberMap.MapperEquals(other.MemberMap)); - public override bool Equals(object obj) => obj is MapRequest other && Equals(other); public override int GetHashCode() => HashCode.Combine(RequestedTypes, RuntimeTypes, MemberMap.MapperGetHashCode()); - public static bool operator ==(in MapRequest left, in MapRequest right) => left.Equals(right); - public static bool operator !=(in MapRequest left, in MapRequest right) => !left.Equals(right); } [DebuggerDisplay("{SourceType.Name}, {DestinationType.Name}")] - public readonly struct TypePair : IEquatable + public readonly record struct TypePair(Type SourceType, Type DestinationType) { - public readonly Type SourceType; - public readonly Type DestinationType; - public TypePair(Type sourceType, Type destinationType) - { - SourceType = sourceType; - DestinationType = destinationType; - } - public bool Equals(TypePair other) => SourceType == other.SourceType && DestinationType == other.DestinationType; - public override bool Equals(object other) => other is TypePair otherPair && Equals(otherPair); - public override int GetHashCode() => HashCode.Combine(SourceType, DestinationType); public bool IsConstructedGenericType => SourceType.IsConstructedGenericType || DestinationType.IsConstructedGenericType; public bool IsGenericTypeDefinition => SourceType.IsGenericTypeDefinition || DestinationType.IsGenericTypeDefinition; public bool ContainsGenericParameters => SourceType.ContainsGenericParameters || DestinationType.ContainsGenericParameters; @@ -54,9 +32,7 @@ public TypePair CloseGenericTypes(TypePair closedTypes) return new TypePair(closedSourceType, closedDestinationType); } public Type ITypeConverter() => ContainsGenericParameters ? null : typeof(ITypeConverter<,>).MakeGenericType(SourceType, DestinationType); - public TypePair GetTypeDefinitionIfGeneric() => new TypePair(GetTypeDefinitionIfGeneric(SourceType), GetTypeDefinitionIfGeneric(DestinationType)); + public TypePair GetTypeDefinitionIfGeneric() => new(GetTypeDefinitionIfGeneric(SourceType), GetTypeDefinitionIfGeneric(DestinationType)); private static Type GetTypeDefinitionIfGeneric(Type type) => type.IsGenericType ? type.GetGenericTypeDefinition() : type; - public static bool operator ==(TypePair left, TypePair right) => left.Equals(right); - public static bool operator !=(TypePair left, TypePair right) => !left.Equals(right); } } \ No newline at end of file diff --git a/src/AutoMapper/Mappers/FromStringDictionaryMapper.cs b/src/AutoMapper/Mappers/FromStringDictionaryMapper.cs index 9ccbc3d089..f69992214e 100644 --- a/src/AutoMapper/Mappers/FromStringDictionaryMapper.cs +++ b/src/AutoMapper/Mappers/FromStringDictionaryMapper.cs @@ -15,28 +15,23 @@ public class FromStringDictionaryMapper : IObjectMapper public Expression MapExpression(IGlobalConfiguration configurationProvider, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) => Call(MapDynamicMethod, sourceExpression, destExpression.ToObject(), Constant(destExpression.Type), ContextParameter, Constant(profileMap)); - struct Match - { - public object Value; - public int Count; - } private static object MapDynamic(StringDictionary source, object boxedDestination, Type destinationType, ResolutionContext context, ProfileMap profileMap) { boxedDestination ??= ObjectFactory.CreateInstance(destinationType); int matchedCount = 0; foreach (var member in profileMap.CreateTypeDetails(destinationType).WriteAccessors) { - var match = MatchSource(member.Name); - if (match.Count == 0) + var (value, count) = MatchSource(member.Name); + if (count == 0) { continue; } - if (match.Count > 1) + if (count > 1) { throw new AutoMapperMappingException($"Multiple matching keys were found in the source dictionary for destination member {member}.", null, new TypePair(typeof(StringDictionary), destinationType)); } - var value = context.MapMember(member, match.Value, boxedDestination); - member.SetMemberValue(boxedDestination, value); + var mappedValue = context.MapMember(member, value, boxedDestination); + member.SetMemberValue(boxedDestination, mappedValue); matchedCount++; } if (matchedCount < source.Count) @@ -44,18 +39,18 @@ private static object MapDynamic(StringDictionary source, object boxedDestinatio MapInnerProperties(); } return boxedDestination; - Match MatchSource(string name) + (object Value, int Count) MatchSource(string name) { if (source.TryGetValue(name, out var value)) { - return new Match { Value = value, Count = 1 }; + return (value, 1); } var matches = source.Where(s => s.Key.Trim() == name).Select(s=>s.Value).ToArray(); if (matches.Length == 1) { - return new Match { Value = matches[0], Count = 1 }; + return (matches[0], 1); } - return new Match { Count = matches.Length }; + return (null, matches.Length); } void MapInnerProperties() { diff --git a/src/AutoMapper/MemberMap.cs b/src/AutoMapper/MemberMap.cs index d29db45552..88d08b12af 100644 --- a/src/AutoMapper/MemberMap.cs +++ b/src/AutoMapper/MemberMap.cs @@ -80,17 +80,9 @@ Expression IValueResolver.GetExpression(MemberMap memberMap, Expression source, MemberInfo IValueResolver.GetSourceMember(MemberMap memberMap) => SourceMembers[0]; Type IValueResolver.ResolvedType => SourceMembers[^1].GetMemberType(); } - public readonly struct ValueTransformerConfiguration + public readonly record struct ValueTransformerConfiguration(Type ValueType, LambdaExpression TransformerExpression) { - public readonly Type ValueType; - public readonly LambdaExpression TransformerExpression; - public ValueTransformerConfiguration(Type valueType, LambdaExpression transformerExpression) - { - ValueType = valueType; - TransformerExpression = transformerExpression; - } - public bool IsMatch(MemberMap memberMap) - => ValueType.IsAssignableFrom(memberMap.SourceType) && memberMap.DestinationType.IsAssignableFrom(ValueType); + public bool IsMatch(MemberMap memberMap) => ValueType.IsAssignableFrom(memberMap.SourceType) && memberMap.DestinationType.IsAssignableFrom(ValueType); } public static class ValueTransformerConfigurationExtensions { diff --git a/src/AutoMapper/QueryableExtensions/Extensions.cs b/src/AutoMapper/QueryableExtensions/Extensions.cs index d0f1f9b31b..04aea3022d 100644 --- a/src/AutoMapper/QueryableExtensions/Extensions.cs +++ b/src/AutoMapper/QueryableExtensions/Extensions.cs @@ -5,7 +5,6 @@ using System.Reflection; using AutoMapper.Execution; using AutoMapper.Internal; -using AutoMapper.QueryableExtensions.Impl; namespace AutoMapper.QueryableExtensions { using MemberPaths = IEnumerable; @@ -15,6 +14,9 @@ namespace AutoMapper.QueryableExtensions /// public static class Extensions { + static readonly MethodInfo SelectMethod = typeof(Queryable).StaticGenericMethod("Select", parametersCount: 2); + static IQueryable Select(IQueryable source, LambdaExpression lambda) => source.Provider.CreateQuery( + Expression.Call(SelectMethod.MakeGenericMethod(source.ElementType, lambda.ReturnType), source.Expression, Expression.Quote(lambda))); /// /// Extension method to project from a queryable using the provided mapping engine /// @@ -25,8 +27,8 @@ public static class Extensions /// Optional parameter object for parameterized mapping expressions /// Explicit members to expand /// Expression to project into - public static IQueryable ProjectTo(this IQueryable source, IConfigurationProvider configuration, object parameters, params Expression>[] membersToExpand) => - new ProjectionExpression(source, configuration).To(parameters, membersToExpand); + public static IQueryable ProjectTo(this IQueryable source, IConfigurationProvider configuration, object parameters, params Expression>[] membersToExpand) => + source.ToCore(configuration, parameters, membersToExpand.Select(MemberVisitor.GetMemberPath)); /// /// Extension method to project from a queryable using the provided mapping engine /// @@ -48,8 +50,8 @@ public static IQueryable ProjectTo(this IQueryable s /// Optional parameter object for parameterized mapping expressions /// Explicit members to expand /// Queryable result, use queryable extension methods to project and execute result - public static IQueryable ProjectTo(this IQueryable source, IConfigurationProvider configuration, ParameterBag parameters, params string[] membersToExpand) => - new ProjectionExpression(source, configuration).To(parameters, membersToExpand); + public static IQueryable ProjectTo(this IQueryable source, IConfigurationProvider configuration, ParameterBag parameters, params string[] membersToExpand) => + source.ToCore(configuration, parameters, membersToExpand.Select(memberName => ReflectionHelper.GetMemberPath(typeof(TDestination), memberName))); /// /// Extension method to project from a queryable using the provided mapping engine /// @@ -69,32 +71,13 @@ public static IQueryable ProjectTo(this IQueryable source, Type destinationType, /// Optional parameter object for parameterized mapping expressions /// Explicit members to expand /// Queryable result, use queryable extension methods to project and execute result - public static IQueryable ProjectTo(this IQueryable source, Type destinationType, IConfigurationProvider configuration, ParameterBag parameters, params string[] membersToExpand) => - new ProjectionExpression(source, configuration).To(destinationType, parameters, membersToExpand); - readonly struct ProjectionExpression - { - private static readonly MethodInfo SelectMethod = typeof(Queryable).StaticGenericMethod("Select", parametersCount: 2); - private readonly IQueryable _source; - private readonly IProjectionBuilder _builder; - public ProjectionExpression(IQueryable source, IConfigurationProvider configuration) - { - _source = source; - _builder = configuration.Internal().ProjectionBuilder; - } - public IQueryable To(ParameterBag parameters, string[] membersToExpand) => - ToCore(parameters, membersToExpand.Select(memberName => ReflectionHelper.GetMemberPath(typeof(TResult), memberName))); - public IQueryable To(object parameters, Expression>[] membersToExpand) => - ToCore(parameters, membersToExpand.Select(MemberVisitor.GetMemberPath)); - public IQueryable To(Type destinationType, object parameters, string[] membersToExpand) => - ToCore(destinationType, parameters, membersToExpand.Select(memberName => ReflectionHelper.GetMemberPath(destinationType, memberName))); - private IQueryable ToCore(object parameters, MemberPaths memberPathsToExpand) => - (IQueryable)ToCore(typeof(TResult), parameters, memberPathsToExpand); - private IQueryable ToCore(Type destinationType, object parameters, MemberPaths memberPathsToExpand) => - _builder.GetProjection(_source.ElementType, destinationType, parameters, memberPathsToExpand.Select(m => new MemberPath(m)).ToArray()) - .Chain(_source, Select); - private static IQueryable Select(IQueryable source, LambdaExpression lambda) => source.Provider.CreateQuery( - Expression.Call(SelectMethod.MakeGenericMethod(source.ElementType, lambda.ReturnType), source.Expression, Expression.Quote(lambda))); - } + public static IQueryable ProjectTo(this IQueryable source, Type destinationType, IConfigurationProvider configuration, ParameterBag parameters, params string[] membersToExpand) => + source.ToCore(destinationType, configuration, parameters, membersToExpand.Select(memberName => ReflectionHelper.GetMemberPath(destinationType, memberName))); + static IQueryable ToCore(this IQueryable source, IConfigurationProvider configuration, object parameters, MemberPaths memberPathsToExpand) => + (IQueryable)source.ToCore(typeof(TResult), configuration, parameters, memberPathsToExpand); + static IQueryable ToCore(this IQueryable source, Type destinationType, IConfigurationProvider configuration, object parameters, MemberPaths memberPathsToExpand) => + configuration.Internal().ProjectionBuilder.GetProjection(source.ElementType, destinationType, parameters, memberPathsToExpand.Select(m => new MemberPath(m)).ToArray()) + .Chain(source, Select); } public class MemberVisitor : ExpressionVisitor { diff --git a/src/AutoMapper/QueryableExtensions/ProjectionBuilder.cs b/src/AutoMapper/QueryableExtensions/ProjectionBuilder.cs index d7033602c8..4be7489804 100644 --- a/src/AutoMapper/QueryableExtensions/ProjectionBuilder.cs +++ b/src/AutoMapper/QueryableExtensions/ProjectionBuilder.cs @@ -263,23 +263,15 @@ void ReplaceSubQueries() projection = new ReplaceMemberAccessesVisitor(instanceParameter, secondParameter).Visit(projection); } } - readonly struct SubQueryPath + readonly record struct SubQueryPath(MemberProjection[] Members, LambdaExpression LetExpression, Expression Marker) { - private readonly MemberProjection[] _members; - public readonly Expression Marker; - public readonly LambdaExpression LetExpression; - public SubQueryPath(MemberProjection[] members, LambdaExpression letExpression) - { - _members = members; - Marker = Default(letExpression.Body.Type); - LetExpression = letExpression; - } + public SubQueryPath(MemberProjection[] members, LambdaExpression letExpression) : this(members, letExpression, Default(letExpression.Body.Type)){ } public Expression GetSourceExpression(Expression parameter) { Expression sourceExpression = parameter; - for (int index = 0; index < _members.Length - 1; index++) + for (int index = 0; index < Members.Length - 1; index++) { - var sourceMember = _members[index].Expression; + var sourceMember = Members[index].Expression; if (sourceMember is LambdaExpression lambda) { sourceExpression = lambda.ReplaceParameters(sourceExpression); @@ -295,9 +287,9 @@ public Expression GetSourceExpression(Expression parameter) } return sourceExpression; } - public PropertyDescription GetPropertyDescription() => new("__" + string.Join("#", _members.Select(p => p.MemberMap.DestinationName)), LetExpression.Body.Type); - internal bool IsEquivalentTo(SubQueryPath other) => LetExpression == other.LetExpression && _members.Length == other._members.Length && - _members.Take(_members.Length - 1).Zip(other._members, (left, right) => left.MemberMap == right.MemberMap).All(item => item); + public PropertyDescription GetPropertyDescription() => new("__" + string.Join("#", Members.Select(p => p.MemberMap.DestinationName)), LetExpression.Body.Type); + internal bool IsEquivalentTo(SubQueryPath other) => LetExpression == other.LetExpression && Members.Length == other.Members.Length && + Members.Take(Members.Length - 1).Zip(other.Members, (left, right) => left.MemberMap == right.MemberMap).All(item => item); } class GePropertiesVisitor : ExpressionVisitor { @@ -367,16 +359,9 @@ public virtual QueryExpressions GetSubQueryExpression(ProjectionBuilder builder, => default; } [EditorBrowsable(EditorBrowsableState.Never)] - public readonly struct QueryExpressions + public readonly record struct QueryExpressions(LambdaExpression Projection, LambdaExpression LetClause = null) { - public readonly LambdaExpression LetClause; - public readonly LambdaExpression Projection; public QueryExpressions(Expression projection, ParameterExpression parameter) : this(projection == null ? null : Lambda(projection, parameter)) { } - public QueryExpressions(LambdaExpression projection, LambdaExpression letClause = null) - { - LetClause = letClause; - Projection = projection; - } public bool Empty => Projection == null; public T Chain(T source, Func select) => LetClause == null ? select(source, Projection) : select(select(source, LetClause), Projection); internal QueryExpressions Prepare(bool enableNullPropagationForQueryMapping, object parameters) @@ -440,41 +425,27 @@ class ConstantExpressionReplacementVisitor : ParameterExpressionVisitor } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerDisplay("{SourceType.Name}, {DestinationType.Name}")] - public readonly struct ProjectionRequest : IEquatable + public readonly record struct ProjectionRequest(Type SourceType, Type DestinationType, MemberPath[] MembersToExpand, ICollection PreviousRequests) { - public readonly Type SourceType; - public readonly Type DestinationType; - private readonly MemberPath[] _membersToExpand; - private readonly ICollection _previousRequests; - public ProjectionRequest(Type sourceType, Type destinationType, MemberPath[] membersToExpand, ICollection previousRequests) - { - SourceType = sourceType; - DestinationType = destinationType; - _membersToExpand = membersToExpand; - _previousRequests = previousRequests; - } public ProjectionRequest InnerRequest(Type sourceType, Type destinationType) => - new(sourceType, destinationType, _membersToExpand, new HashSet(_previousRequests) { this }); - public bool AlreadyExists => _previousRequests.Contains(this); + new(sourceType, destinationType, MembersToExpand, new HashSet(PreviousRequests) { this }); + public bool AlreadyExists => PreviousRequests.Contains(this); public bool Equals(ProjectionRequest other) => SourceType == other.SourceType && DestinationType == other.DestinationType && - _membersToExpand.SequenceEqual(other._membersToExpand); - public override bool Equals(object obj) => obj is ProjectionRequest request && Equals(request); + MembersToExpand.SequenceEqual(other.MembersToExpand); public override int GetHashCode() { var hashCode = new HashCode(); hashCode.Add(SourceType); hashCode.Add(DestinationType); - foreach (var member in _membersToExpand) + foreach (var member in MembersToExpand) { hashCode.Add(member); } return hashCode.ToHashCode(); } - public static bool operator ==(in ProjectionRequest left, in ProjectionRequest right) => Equals(left, right); - public static bool operator !=(in ProjectionRequest left, in ProjectionRequest right) => !Equals(left, right); public bool ShouldExpand(MemberPath currentPath) { - foreach (var memberToExpand in _membersToExpand) + foreach (var memberToExpand in MembersToExpand) { if (memberToExpand.StartsWith(currentPath)) { diff --git a/src/AutoMapper/ResolutionContext.cs b/src/AutoMapper/ResolutionContext.cs index 1ccae305be..c84fb52571 100644 --- a/src/AutoMapper/ResolutionContext.cs +++ b/src/AutoMapper/ResolutionContext.cs @@ -109,19 +109,5 @@ private void CheckDefault() } private static void ThrowInvalidMap() => throw new InvalidOperationException("Context.Items are only available when using a Map overload that takes Action!"); } - public readonly struct ContextCacheKey : IEquatable - { - private readonly Type _destinationType; - public readonly object Source; - public ContextCacheKey(object source, Type destinationType) - { - Source = source; - _destinationType = destinationType; - } - public static bool operator ==(ContextCacheKey left, ContextCacheKey right) => left.Equals(right); - public static bool operator !=(ContextCacheKey left, ContextCacheKey right) => !left.Equals(right); - public override int GetHashCode() => HashCode.Combine(Source, _destinationType); - public bool Equals(ContextCacheKey other) => Source == other.Source && _destinationType == other._destinationType; - public override bool Equals(object other) => other is ContextCacheKey otherKey && Equals(otherKey); - } + public readonly record struct ContextCacheKey(object Source, Type DestinationType); } \ No newline at end of file From 7720ac8c9ed5c80e68c96c88f7cc50c3e685a342 Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Mon, 15 Aug 2022 14:48:19 +0300 Subject: [PATCH 26/67] assume that a protected constructor with CompilerGeneratedAttribute means we're mapping to a record --- .../Configuration/CtorParamConfigurationExpression.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/AutoMapper/Configuration/CtorParamConfigurationExpression.cs b/src/AutoMapper/Configuration/CtorParamConfigurationExpression.cs index 3a5145ec03..544aedde98 100644 --- a/src/AutoMapper/Configuration/CtorParamConfigurationExpression.cs +++ b/src/AutoMapper/Configuration/CtorParamConfigurationExpression.cs @@ -3,9 +3,9 @@ using System; using System.Collections.Generic; using System.ComponentModel; -using System.Linq; using System.Linq.Expressions; - +using System.Reflection; +using System.Runtime.CompilerServices; namespace AutoMapper.Configuration { public interface ICtorParamConfigurationExpression @@ -76,14 +76,14 @@ public void Configure(TypeMap typeMap) var parameter = ctorMap[CtorParamName]; if (parameter == null) { - throw new AutoMapperConfigurationException($"{typeMap.DestinationType.Name} does not have a matching constructor with a parameter named '{CtorParamName}'.\n{typeMap.DestinationType.FullName}.{CheckRecord()}"); + throw new AutoMapperConfigurationException($"{typeMap.DestinationType.Name} does not have a matching constructor with a parameter named '{CtorParamName}'.\n{typeMap.DestinationType.FullName}.{CheckRecord(ctorMap.Ctor)}"); } foreach (var action in _ctorParamActions) { action(parameter); } return; - string CheckRecord() => ctorMap.Ctor.IsFamily && ctorMap.Ctor.DeclaringType.GetMethod("$") != null ? + static string CheckRecord(ConstructorInfo ctor) => ctor.IsFamily && ctor.Has() ? " When mapping to records, consider excluding non-public constructors. See https://docs.automapper.org/en/latest/Construction.html." : null; } } From 4e1117f67080d7ec2f94d121607f16e6ecc75dce Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Mon, 15 Aug 2022 20:41:49 +0300 Subject: [PATCH 27/67] less allocations --- src/AutoMapper/ApiCompatBaseline.txt | 4 +- .../Configuration/MapperConfiguration.cs | 25 +++- src/AutoMapper/Execution/ExpressionBuilder.cs | 52 ++++---- .../Execution/TypeMapPlanBuilder.cs | 113 ++++++++++-------- src/AutoMapper/Internal/InternalApi.cs | 6 +- src/AutoMapper/Internal/PrimitiveHelper.cs | 13 +- src/AutoMapper/Internal/TypeExtensions.cs | 19 +-- src/AutoMapper/Mappers/CollectionMapper.cs | 71 +++++++---- src/AutoMapper/TypeMap.cs | 14 +-- src/Benchmark/BenchEngine.cs | 16 +-- src/Benchmark/FlatteningMapper.cs | 8 +- src/Benchmark/Program.cs | 4 +- 12 files changed, 212 insertions(+), 133 deletions(-) diff --git a/src/AutoMapper/ApiCompatBaseline.txt b/src/AutoMapper/ApiCompatBaseline.txt index 80c704dfdc..2513596469 100644 --- a/src/AutoMapper/ApiCompatBaseline.txt +++ b/src/AutoMapper/ApiCompatBaseline.txt @@ -63,6 +63,7 @@ MembersMustExist : Member 'public System.Boolean AutoMapper.Execution.TypeDescri MembersMustExist : Member 'public System.Boolean AutoMapper.Execution.TypeDescription.op_Inequality(AutoMapper.Execution.TypeDescription, AutoMapper.Execution.TypeDescription)' does not exist in the implementation but it does exist in the contract. CannotSealType : Type 'AutoMapper.Execution.TypeMapPlanBuilder' is actually (has the sealed modifier) sealed in the implementation but not sealed in the contract. TypeCannotChangeClassification : Type 'AutoMapper.Execution.TypeMapPlanBuilder' is a 'struct' in the implementation but is a 'class' in the contract. +MembersMustExist : Member 'public System.Linq.Expressions.LambdaExpression AutoMapper.Execution.TypeMapPlanBuilder.CreateMapperLambda(System.Collections.Generic.HashSet)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Reflection.ConstructorInfo System.Reflection.ConstructorInfo AutoMapper.Internal.ConstructorParameters.Constructor' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Reflection.ParameterInfo[] System.Reflection.ParameterInfo[] AutoMapper.Internal.ConstructorParameters.Parameters' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public AutoMapper.Internal.TypePair AutoMapper.Internal.TypePair AutoMapper.Internal.MapRequest.RequestedTypes' does not exist in the implementation but it does exist in the contract. @@ -70,6 +71,7 @@ MembersMustExist : Member 'public AutoMapper.Internal.TypePair AutoMapper.Intern MembersMustExist : Member 'public AutoMapper.MemberMap AutoMapper.MemberMap AutoMapper.Internal.MapRequest.MemberMap' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Boolean AutoMapper.Internal.MapRequest.op_Equality(AutoMapper.Internal.MapRequest, AutoMapper.Internal.MapRequest)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Boolean AutoMapper.Internal.MapRequest.op_Inequality(AutoMapper.Internal.MapRequest, AutoMapper.Internal.MapRequest)' does not exist in the implementation but it does exist in the contract. +CannotChangeAttribute : Attribute 'System.Runtime.CompilerServices.IteratorStateMachineAttribute' on 'AutoMapper.Internal.TypeExtensions.GetTypeInheritance(System.Type)' changed from '[IteratorStateMachineAttribute(typeof(TypeExtensions.d__19))]' in the contract to '[IteratorStateMachineAttribute(typeof(TypeExtensions.d__22))]' in the implementation. MembersMustExist : Member 'public System.Type System.Type AutoMapper.Internal.TypePair.DestinationType' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Type System.Type AutoMapper.Internal.TypePair.SourceType' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Boolean AutoMapper.Internal.TypePair.Equals(AutoMapper.Internal.TypePair)' does not exist in the implementation but it does exist in the contract. @@ -86,4 +88,4 @@ MembersMustExist : Member 'public AutoMapper.Internal.TypePair AutoMapper.Intern MembersMustExist : Member 'public System.Linq.IQueryable AutoMapper.QueryableExtensions.Extensions.Map(System.Linq.IQueryable, System.Linq.IQueryable, AutoMapper.IConfigurationProvider)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Collections.Generic.IReadOnlyCollection AutoMapper.QueryableExtensions.MemberVisitor.MemberPath.get()' does not exist in the implementation but it does exist in the contract. TypesMustExist : Type 'AutoMapper.QueryableExtensions.Impl.MemberAccessQueryMapperVisitor' does not exist in the implementation but it does exist in the contract. -Total Issues: 87 +Total Issues: 89 diff --git a/src/AutoMapper/Configuration/MapperConfiguration.cs b/src/AutoMapper/Configuration/MapperConfiguration.cs index 322f0a6247..3d4d4e0c90 100644 --- a/src/AutoMapper/Configuration/MapperConfiguration.cs +++ b/src/AutoMapper/Configuration/MapperConfiguration.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Linq.Expressions; using System.Reflection; +using System.Security.Cryptography; using AutoMapper.Configuration; using AutoMapper.Features; using AutoMapper.Internal; @@ -50,8 +51,6 @@ public class MapperConfiguration : IGlobalConfiguration private readonly IObjectMapper[] _mappers; private readonly Dictionary _configuredMaps; private readonly Dictionary _resolvedMaps; - private HashSet _typeMapsPath = new(); - private List _sourceMembers = new(); private readonly LockingConcurrentDictionary _runtimeMaps; private readonly ProjectionBuilder _projectionBuilder; private readonly LockingConcurrentDictionary _executionPlans; @@ -63,6 +62,12 @@ public class MapperConfiguration : IGlobalConfiguration private readonly Func _serviceCtor; private readonly bool _sealed; private readonly bool _hasOpenMaps; + private readonly HashSet _typeMapsPath = new(); + private readonly List _sourceMembers = new(); + private readonly List _variables = new(); + private readonly ParameterExpression[] _parameters = new ParameterExpression[] { null, null, ContextParameter }; + private readonly CatchBlock[] _catches = new CatchBlock[1]; + private readonly List _expressions = new(); public MapperConfiguration(MapperConfigurationExpression configurationExpression) { var configuration = (IGlobalConfigurationExpression)configurationExpression; @@ -107,6 +112,10 @@ public MapperConfiguration(MapperConfigurationExpression configurationExpression } _typeMapsPath = null; _sourceMembers = null; + _expressions = null; + _variables = null; + _parameters = null; + _catches = null; _sealed = true; return; void Seal() @@ -134,7 +143,7 @@ void Seal() } foreach (var typeMap in _configuredMaps.Values) { - typeMap.Seal(this, _typeMapsPath); + typeMap.Seal(this); } _features.Seal(this); } @@ -245,6 +254,11 @@ static MapperConfigurationExpression Build(Action _recursiveQueriesMaxDepth; Features IGlobalConfiguration.Features => _features; List IGlobalConfiguration.SourceMembers => _sourceMembers; + List IGlobalConfiguration.Variables => _variables; + List IGlobalConfiguration.Expressions => _expressions; + HashSet IGlobalConfiguration.TypeMapsPath => _typeMapsPath; + ParameterExpression[] IGlobalConfiguration.Parameters => _parameters; + CatchBlock[] IGlobalConfiguration.Catches => _catches; Func IGlobalConfiguration.GetExecutionPlan(in MapRequest mapRequest) => (Func)GetExecutionPlan(mapRequest); private Delegate GetExecutionPlan(in MapRequest mapRequest) => _executionPlans.GetOrAdd(mapRequest); @@ -285,7 +299,7 @@ TypeMap ResolveTypeMap(TypePair typePair) { lock (typeMap) { - typeMap.Seal(this, null); + typeMap.Seal(this); } } } @@ -295,7 +309,7 @@ TypeMap ResolveTypeMap(TypePair typePair) _resolvedMaps.Add(typePair, typeMap); if (typeMap != null && typeMap.MapExpression == null) { - typeMap.Seal(this, _typeMapsPath); + typeMap.Seal(this); } } return typeMap; @@ -460,7 +474,6 @@ void IGlobalConfiguration.AssertConfigurationIsValid(string profileName) _validator.AssertConfigurationIsValid(_configuredMaps.Values.Where(typeMap => typeMap.Profile.Name == profileName)); } void IGlobalConfiguration.AssertConfigurationIsValid() => this.Internal().AssertConfigurationIsValid(typeof(TProfile).FullName); - void IGlobalConfiguration.Seal(TypeMap typeMap) => typeMap.Seal(this, _typeMapsPath); void IGlobalConfiguration.RegisterAsMap(TypeMapConfiguration typeMapConfiguration) => _resolvedMaps[typeMapConfiguration.Types] = GetIncludedTypeMap(new(typeMapConfiguration.SourceType, typeMapConfiguration.DestinationTypeOverride)); } diff --git a/src/AutoMapper/Execution/ExpressionBuilder.cs b/src/AutoMapper/Execution/ExpressionBuilder.cs index 607a123d2e..40a8d96d28 100644 --- a/src/AutoMapper/Execution/ExpressionBuilder.cs +++ b/src/AutoMapper/Execution/ExpressionBuilder.cs @@ -39,6 +39,7 @@ public static class ExpressionBuilder private static readonly ParameterExpression[] DisposableArray = new[] { Disposable }; private static readonly Expression DisposeCall = IfNullElse(Disposable, Empty, Expression.Call(Disposable, DisposeMethod)); private static readonly ParameterExpression Index = Variable(typeof(int), "sourceArrayIndex"); + private static readonly ParameterExpression[] Indexes = new[] { Index }; private static readonly BinaryExpression ResetIndex = Assign(Index, Zero); private static readonly UnaryExpression IncrementIndex = PostIncrementAssign(Index); @@ -55,7 +56,7 @@ public static Expression MapExpression(this IGlobalConfiguration configurationPr nullCheck = !typeMap.HasTypeConverter && allowNull.HasValue && allowNull != profileMap.AllowNullDestinationValues; if (!typeMap.HasDerivedTypesToInclude) { - configurationProvider.Seal(typeMap); + typeMap.Seal(configurationProvider); if (typeMap.MapExpression != null) { mapExpression = typeMap.Invoke(source, destination); @@ -254,18 +255,19 @@ public static bool IsMemberPath(this LambdaExpression lambda, out Stack return currentExpression == lambda.Body; } public static LambdaExpression MemberAccessLambda(Type type, string memberPath) => GetMemberPath(type, memberPath).Lambda(); - public static Expression ForEach(ParameterExpression loopVar, Expression collection, Expression loopContent) + public static Expression ForEach(List variables, List statements, ParameterExpression loopVar, Expression collection, Expression loopContent) { if (collection.Type.IsArray) { - return ForEachArrayItem(loopVar, collection, loopContent); + return ForEachArrayItem(variables, statements, loopVar, collection, loopContent); } var getEnumeratorCall = Call(collection, "GetEnumerator"); var enumeratorVar = Variable(getEnumeratorCall.Type, "enumerator"); var breakLabel = Label("LoopBreak"); - var loop = Block(new[] { enumeratorVar, loopVar }, - Assign(enumeratorVar, getEnumeratorCall), - Using(enumeratorVar, + variables.Add(enumeratorVar); + variables.Add(loopVar); + statements.Add(Assign(enumeratorVar, getEnumeratorCall)); + statements.Add(Using(enumeratorVar, Loop( IfThenElse( Call(enumeratorVar, "MoveNext"), @@ -273,20 +275,21 @@ public static Expression ForEach(ParameterExpression loopVar, Expression collect Break(breakLabel) ), breakLabel))); - return loop; - static Expression ForEachArrayItem(ParameterExpression loopVar, Expression array, Expression loopContent) + return Block(variables, statements); + static Expression ForEachArrayItem(List variables, List statements, ParameterExpression loopVar, Expression array, Expression loopContent) { var breakLabel = Label("LoopBreak"); - var loop = Block(new[] { Index, loopVar }, - ResetIndex, - Loop( + variables.Add(Index); + variables.Add(loopVar); + statements.Add(ResetIndex); + statements.Add(Loop( IfThenElse( LessThan(Index, ArrayLength(array)), - Block(Assign(loopVar, ArrayAccess(array, Index)), loopContent, IncrementIndex), + Block(Assign(loopVar, ArrayAccess(array, Indexes)), loopContent, IncrementIndex), Break(breakLabel) ), breakLabel)); - return loop; + return Block(variables, statements); } static Expression Using(Expression target, Expression body) { @@ -315,21 +318,26 @@ public static MethodCallExpression Call(Expression target, string name, params E Expression.Call(target, target.Type.GetInheritedMethod(name), arguments); public static Expression ToObject(this Expression expression) => expression.Type.IsValueType ? Convert(expression, typeof(object)) : expression; public static Expression ToType(Expression expression, Type type) => expression.Type == type ? expression : Convert(expression, type); - public static Expression ReplaceParameters(this LambdaExpression initialLambda, params Expression[] newParameters) => + public static Expression ReplaceParameters(this LambdaExpression initialLambda, Expression newParameter) => + new ParameterReplaceVisitor().Replace(initialLambda, newParameter); + public static Expression ReplaceParameters(this LambdaExpression initialLambda, Expression[] newParameters) => new ParameterReplaceVisitor().Replace(initialLambda, newParameters); - public static Expression ConvertReplaceParameters(this LambdaExpression initialLambda, params Expression[] newParameters) => + public static Expression ConvertReplaceParameters(this LambdaExpression initialLambda, Expression newParameter) => + new ConvertParameterReplaceVisitor().Replace(initialLambda, newParameter); + public static Expression ConvertReplaceParameters(this LambdaExpression initialLambda, Expression[] newParameters) => new ConvertParameterReplaceVisitor().Replace(initialLambda, newParameters); - private static Expression Replace(this ParameterReplaceVisitor visitor, LambdaExpression initialLambda, params Expression[] newParameters) + private static Expression Replace(this ParameterReplaceVisitor visitor, LambdaExpression initialLambda, Expression newParameter) => + visitor.Replace(initialLambda.Body, initialLambda.Parameters[0], newParameter); + private static Expression Replace(this ParameterReplaceVisitor visitor, LambdaExpression initialLambda, Expression[] newParameters) { var newLambda = initialLambda.Body; for (var i = 0; i < Math.Min(newParameters.Length, initialLambda.Parameters.Count); i++) { - visitor.Replace(initialLambda.Parameters[i], newParameters[i]); - newLambda = visitor.Visit(newLambda); + newLambda = visitor.Replace(newLambda, initialLambda.Parameters[i], newParameters[i]); } return newLambda; } - public static Expression Replace(this Expression exp, Expression old, Expression replace) => new ReplaceVisitor(old, replace).Visit(exp); + public static Expression Replace(this Expression exp, Expression old, Expression replace) => new ReplaceVisitor().Replace(exp, old, replace); public static Expression NullCheck(this Expression expression, MemberMap memberMap = null, Expression defaultValue = null) { var chain = expression.GetChain(); @@ -396,15 +404,15 @@ class ReplaceVisitorBase : ExpressionVisitor { protected Expression _oldNode; protected Expression _newNode; - public virtual void Replace(Expression oldNode, Expression newNode) + public virtual Expression Replace(Expression target, Expression oldNode, Expression newNode) { _oldNode = oldNode; _newNode = newNode; + return base.Visit(target); } } class ReplaceVisitor : ReplaceVisitorBase { - public ReplaceVisitor(Expression oldNode, Expression newNode) => Replace(oldNode, newNode); public override Expression Visit(Expression node) => _oldNode == node ? _newNode : base.Visit(node); } class ParameterReplaceVisitor : ReplaceVisitorBase @@ -413,7 +421,7 @@ class ParameterReplaceVisitor : ReplaceVisitorBase } class ConvertParameterReplaceVisitor : ParameterReplaceVisitor { - public override void Replace(Expression oldNode, Expression newNode) => base.Replace(oldNode, ToType(newNode, oldNode.Type)); + public override Expression Replace(Expression target, Expression oldNode, Expression newNode) => base.Replace(target, oldNode, ToType(newNode, oldNode.Type)); } } public readonly record struct Member(Expression Expression, MemberInfo MemberInfo, Expression Target); diff --git a/src/AutoMapper/Execution/TypeMapPlanBuilder.cs b/src/AutoMapper/Execution/TypeMapPlanBuilder.cs index 64e3155b60..8dd5e6277b 100644 --- a/src/AutoMapper/Execution/TypeMapPlanBuilder.cs +++ b/src/AutoMapper/Execution/TypeMapPlanBuilder.cs @@ -17,8 +17,9 @@ public struct TypeMapPlanBuilder private readonly ParameterExpression _destination; private readonly ParameterExpression _initialDestination; private readonly TypeMap _typeMap; - private List _propertyMapVariables = null; - private List _propertyMapExpressions = null; + private List _variables; + private List _expressions; + private CatchBlock[] _catches; public TypeMapPlanBuilder(IGlobalConfiguration configurationProvider, TypeMap typeMap) { _configurationProvider = configurationProvider; @@ -26,39 +27,51 @@ public TypeMapPlanBuilder(IGlobalConfiguration configurationProvider, TypeMap ty Source = Parameter(typeMap.SourceType, "source"); _initialDestination = Parameter(typeMap.DestinationType, "destination"); _destination = Variable(_initialDestination.Type, "typeMapDestination"); + _variables = configurationProvider.Variables; + _expressions = configurationProvider.Expressions; + _catches = configurationProvider.Catches; } public Type DestinationType => _destination.Type; public ParameterExpression Source { get; } private static AutoMapperMappingException MemberMappingError(Exception innerException, MemberMap memberMap) => new("Error mapping types.", innerException, memberMap); - public LambdaExpression CreateMapperLambda(HashSet typeMapsPath) + ParameterExpression[] GetParameters(ParameterExpression source = null, ParameterExpression destination = null) { - var parameters = new[] { Source, _initialDestination, ContextParameter }; + var parameters = _configurationProvider.Parameters ?? new ParameterExpression[] { null, null, ContextParameter }; + parameters[0] = source ?? Source; + parameters[1] = destination ?? _destination; + return parameters; + } + public LambdaExpression CreateMapperLambda() + { + var parameters = GetParameters(destination: _initialDestination); var customExpression = _typeMap.TypeConverter?.GetExpression(parameters); if (customExpression != null) { return Lambda(customExpression, parameters); } - _propertyMapVariables = new(capacity: 2); - _propertyMapExpressions = new(capacity: 3); + _variables ??= new(); + _expressions ??= new(); + _catches ??= new CatchBlock[1]; + var typeMapsPath = _configurationProvider.TypeMapsPath; Clear(ref typeMapsPath); CheckForCycles(_configurationProvider, _typeMap, typeMapsPath); - var variables = new List(); - var statements = new List(); - if (_typeMap.IncludedMembersTypeMaps.Count > 0) - { - IncludeMembers(parameters, variables, statements); - } var createDestinationFunc = CreateDestinationFunc(); var assignmentFunc = CreateAssignmentFunc(createDestinationFunc); var mapperFunc = CreateMapperFunc(assignmentFunc); + _variables.Clear(); + _expressions.Clear(); + if (_typeMap.IncludedMembersTypeMaps.Count > 0) + { + IncludeMembers(); + } var checkContext = CheckContext(_typeMap); if (checkContext != null) { - statements.Add(checkContext); + _expressions.Add(checkContext); } - statements.Add(mapperFunc); - variables.Add(_destination); - return Lambda(Block(variables, statements), parameters); + _expressions.Add(mapperFunc); + _variables.Add(_destination); + return Lambda(Block(_variables, _expressions), GetParameters(destination: _initialDestination)); static void Clear(ref HashSet typeMapsPath) { if (typeMapsPath == null) @@ -71,11 +84,12 @@ static void Clear(ref HashSet typeMapsPath) } } } - void IncludeMembers(ParameterExpression[] parameters, List variables, List statements) + void IncludeMembers() { - variables.AddRange(_typeMap.IncludedMembersTypeMaps.Select(i => i.Variable)); - statements.AddRange(variables.Zip(_typeMap.IncludedMembersTypeMaps, (v, i) => - Assign(v, i.MemberExpression.ReplaceParameters(parameters).NullCheck()))); + var source = Source; + _variables.AddRange(_typeMap.IncludedMembersTypeMaps.Select(i => i.Variable)); + _expressions.AddRange(_variables.Zip(_typeMap.IncludedMembersTypeMaps, (v, i) => + Assign(v, i.MemberExpression.ReplaceParameters(source).NullCheck()))); } private static void CheckForCycles(IGlobalConfiguration configurationProvider, TypeMap typeMap, HashSet typeMapsPath) { @@ -157,7 +171,7 @@ private Expression CreateDestinationFunc() } private Expression CreateAssignmentFunc(Expression createDestination) { - var actions = new List { createDestination }; + List actions = new() { createDestination }; Expression typeMapExpression = null; var hasMaxDepth = _typeMap.MaxDepth > 0; if (hasMaxDepth) @@ -167,7 +181,7 @@ private Expression CreateAssignmentFunc(Expression createDestination) } foreach (var beforeMapAction in _typeMap.BeforeMapActions) { - actions.Add(beforeMapAction.ReplaceParameters(Source, _destination, ContextParameter)); + actions.Add(beforeMapAction.ReplaceParameters(GetParameters())); } foreach (var propertyMap in _typeMap.OrderedPropertyMaps()) { @@ -190,7 +204,7 @@ private Expression CreateAssignmentFunc(Expression createDestination) } foreach (var afterMapAction in _typeMap.AfterMapActions) { - actions.Add(afterMapAction.ReplaceParameters(Source, _destination, ContextParameter)); + actions.Add(afterMapAction.ReplaceParameters(GetParameters())); } if (hasMaxDepth) { @@ -247,7 +261,7 @@ private Expression CheckReferencesCache(Expression valueBuilder) } private Expression CreateNewDestinationFunc() => _typeMap switch { - { CustomCtorFunction: LambdaExpression constructUsingFunc } => constructUsingFunc.ReplaceParameters(Source, ContextParameter), + { CustomCtorFunction: LambdaExpression constructUsingFunc } => constructUsingFunc.ReplaceParameters(new[] { Source, ContextParameter }), { ConstructorMap: { CanResolve: true } constructorMap } => ConstructorMapping(constructorMap), { DestinationType: { IsInterface: true } interfaceType } => Throw(Constant(new AutoMapperMappingException("Cannot create interface "+interfaceType, null, _typeMap)), interfaceType), _ => ObjectFactory.GenerateConstructorExpression(DestinationType) @@ -276,10 +290,11 @@ private Expression TryPropertyMap(PropertyMap propertyMap) var propertyMapExpression = CreatePropertyMapFunc(propertyMap, _destination, propertyMap.DestinationMember); return TryMemberMap(propertyMap, propertyMapExpression); } - private static Expression TryMemberMap(MemberMap memberMap, Expression memberMapExpression) + private Expression TryMemberMap(MemberMap memberMap, Expression memberMapExpression) { var newException = Call(MappingError, ExceptionParameter, Constant(memberMap)); - return TryCatch(memberMapExpression, Catch(ExceptionParameter, Throw(newException, memberMapExpression.Type))); + _catches[0] = Catch(ExceptionParameter, Throw(newException, memberMapExpression.Type)); + return TryCatch(memberMapExpression, _catches); } private Expression CreatePropertyMapFunc(MemberMap memberMap, Expression destination, MemberInfo destinationMember) { @@ -307,48 +322,42 @@ private Expression CreatePropertyMapFunc(MemberMap memberMap, Expression destina var mapperExpr = destinationMemberReadOnly ? (Expression)mappedMemberVariable : Assign(destinationMemberAccess, mappedMemberVariable); if (memberMap.Condition != null) { - _propertyMapExpressions.Add(IfThen( - memberMap.Condition.ConvertReplaceParameters(customSource, _destination, mappedMemberVariable, destinationMemberGetter, ContextParameter), + _expressions.Add(IfThen( + memberMap.Condition.ConvertReplaceParameters(new[] { customSource, _destination, mappedMemberVariable, destinationMemberGetter, ContextParameter }), mapperExpr)); } else if (!destinationMemberReadOnly) { - _propertyMapExpressions.Add(mapperExpr); + _expressions.Add(mapperExpr); } if (memberMap.PreCondition != null) { Precondition(memberMap, customSource); } - return Block(_propertyMapVariables, _propertyMapExpressions); + return Block(_variables, _expressions); } Expression DestinationMemberValue(MemberMap memberMap, Expression destinationMemberGetter, bool destinationMemberReadOnly) { - if (memberMap is { UseDestinationValue: true } || (memberMap.UseDestinationValue is null && destinationMemberReadOnly)) + if (destinationMemberReadOnly || memberMap.UseDestinationValue is true) { return destinationMemberGetter; } - else if (DestinationType.IsValueType) - { - return Default(memberMap.DestinationType); - } - else - { - return Condition(ReferenceEqual(_initialDestination, Null), Default(memberMap.DestinationType), destinationMemberGetter); - } + var defaultValue = Default(memberMap.DestinationType); + return DestinationType.IsValueType ? defaultValue : Condition(ReferenceEqual(_initialDestination, Null), defaultValue, destinationMemberGetter); } - void Precondition(MemberMap memberMap, Expression customSource) + void Precondition(MemberMap memberMap, ParameterExpression customSource) { - var preCondition = memberMap.PreCondition.ConvertReplaceParameters(customSource, _destination, ContextParameter); - var ifThen = IfThen(preCondition, Block(_propertyMapExpressions)); - _propertyMapExpressions.Clear(); - _propertyMapExpressions.Add(ifThen); + var preCondition = memberMap.PreCondition.ConvertReplaceParameters(GetParameters(source: customSource)); + var ifThen = IfThen(preCondition, Block(_expressions)); + _expressions.Clear(); + _expressions.Add(ifThen); } ParameterExpression SetVariables(Expression valueResolver, ParameterExpression resolvedValueVariable, Expression mappedMember) { - _propertyMapExpressions.Clear(); - _propertyMapVariables.Clear(); - _propertyMapVariables.Add(resolvedValueVariable); - _propertyMapExpressions.Add(Assign(resolvedValueVariable, valueResolver)); + _expressions.Clear(); + _variables.Clear(); + _variables.Add(resolvedValueVariable); + _expressions.Add(Assign(resolvedValueVariable, valueResolver)); ParameterExpression mappedMemberVariable; if (mappedMember == resolvedValueVariable) { @@ -357,8 +366,8 @@ ParameterExpression SetVariables(Expression valueResolver, ParameterExpression r else { mappedMemberVariable = Variable(mappedMember.Type, "mappedValue"); - _propertyMapVariables.Add(mappedMemberVariable); - _propertyMapExpressions.Add(Assign(mappedMemberVariable, mappedMember)); + _variables.Add(mappedMemberVariable); + _expressions.Add(Assign(mappedMemberVariable, mappedMember)); } return mappedMemberVariable; } @@ -387,7 +396,7 @@ private Expression BuildValueResolverFunc(MemberMap memberMap, Expression custom } return valueResolverFunc; } - private Expression GetCustomSource(MemberMap memberMap) => memberMap.IncludedMember?.Variable ?? Source; + private ParameterExpression GetCustomSource(MemberMap memberMap) => memberMap.IncludedMember?.Variable ?? Source; } public interface IValueResolver { @@ -407,7 +416,7 @@ public class FuncResolver : LambdaValueResolver, IValueResolver { public FuncResolver(LambdaExpression lambda) : base(lambda) { } public Expression GetExpression(MemberMap memberMap, Expression source, Expression destination, Expression destinationMember) => - Lambda.ConvertReplaceParameters(source, destination, destinationMember, ContextParameter); + Lambda.ConvertReplaceParameters(new[] { source, destination, destinationMember, ContextParameter }); public MemberInfo GetSourceMember(MemberMap _) => null; } public class ExpressionResolver : LambdaValueResolver, IValueResolver diff --git a/src/AutoMapper/Internal/InternalApi.cs b/src/AutoMapper/Internal/InternalApi.cs index 2858576c1c..dc98a77db2 100644 --- a/src/AutoMapper/Internal/InternalApi.cs +++ b/src/AutoMapper/Internal/InternalApi.cs @@ -154,9 +154,13 @@ public interface IGlobalConfiguration : IConfigurationProvider TypeMap GetIncludedTypeMap(TypePair typePair); TypeMap GetIncludedTypeMap(Type sourceType, Type destinationType); TypeMap[] GetIncludedTypeMaps(IReadOnlyCollection includedTypes); - void Seal(TypeMap typeMap); void RegisterAsMap(TypeMapConfiguration typeMapConfiguration); + ParameterExpression[] Parameters { get; } List SourceMembers { get; } + List Variables { get; } + List Expressions { get; } + HashSet TypeMapsPath { get; } + CatchBlock[] Catches { get; } } [EditorBrowsable(EditorBrowsableState.Never)] public interface IProfileExpressionInternal : IProfileExpression diff --git a/src/AutoMapper/Internal/PrimitiveHelper.cs b/src/AutoMapper/Internal/PrimitiveHelper.cs index e6f030444c..8f2a4603eb 100644 --- a/src/AutoMapper/Internal/PrimitiveHelper.cs +++ b/src/AutoMapper/Internal/PrimitiveHelper.cs @@ -1,13 +1,24 @@ using System; +using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Linq; - namespace AutoMapper.Internal { [EditorBrowsable(EditorBrowsableState.Never)] public static class PrimitiveHelper { + public static void Clear(ref T collection) where T : IList, new() + { + if (collection == null) + { + collection = new(); + } + else + { + collection.Clear(); + } + } public static IReadOnlyCollection NullCheck(this IReadOnlyCollection source) => source ?? Array.Empty(); public static IEnumerable Concat(this IReadOnlyCollection collection, IReadOnlyCollection otherCollection) { diff --git a/src/AutoMapper/Internal/TypeExtensions.cs b/src/AutoMapper/Internal/TypeExtensions.cs index 4ac254b435..0371aee592 100644 --- a/src/AutoMapper/Internal/TypeExtensions.cs +++ b/src/AutoMapper/Internal/TypeExtensions.cs @@ -46,15 +46,16 @@ public static IEnumerable BaseClassesAndInterfaces(this Type type) } } - public static PropertyInfo GetInheritedProperty(this Type type, string name) => type.GetProperty(name, InstanceFlags) ?? + public static PropertyInfo GetInheritedProperty(this Type type, string name) => type.GetProperty(name, InstanceFlags) ?? type.GetBaseProperty(name); + static PropertyInfo GetBaseProperty(this Type type, string name) => type.BaseClassesAndInterfaces().Select(t => t.GetProperty(name, InstanceFlags)).FirstOrDefault(p => p != null); - - public static FieldInfo GetInheritedField(this Type type, string name) => type.GetField(name, InstanceFlags) ?? + public static FieldInfo GetInheritedField(this Type type, string name) => type.GetField(name, InstanceFlags) ?? type.GetBaseField(name); + static FieldInfo GetBaseField(this Type type, string name) => type.BaseClassesAndInterfaces().Select(t => t.GetField(name, InstanceFlags)).FirstOrDefault(f => f != null); - - public static MethodInfo GetInheritedMethod(this Type type, string name) => type.GetInstanceMethod(name) ?? - type.BaseClassesAndInterfaces().Select(t => t.GetInstanceMethod(name)).FirstOrDefault(m => m != null) - ?? throw new ArgumentOutOfRangeException(nameof(name), $"Cannot find member {name} of type {type}."); + public static MethodInfo GetInheritedMethod(this Type type, string name) => type.GetInstanceMethod(name) ?? type.GetBaseMethod(name) ?? + throw new ArgumentOutOfRangeException(nameof(name), $"Cannot find member {name} of type {type}."); + static MethodInfo GetBaseMethod(this Type type, string name) => + type.BaseClassesAndInterfaces().Select(t => t.GetInstanceMethod(name)).FirstOrDefault(m => m != null); public static MemberInfo GetFieldOrProperty(this Type type, string name) => type.GetInheritedProperty(name) ?? (MemberInfo)type.GetInheritedField(name) ?? throw new ArgumentOutOfRangeException(nameof(name), $"Cannot find member {name} of type {type}."); @@ -78,7 +79,7 @@ public static Type GetGenericInterface(this Type type, Type genericInterface) return type; } var interfaces = type.GetInterfaces(); - for(int index = interfaces.Length - 1; index >= 0; index--) + for (int index = interfaces.Length - 1; index >= 0; index--) { var interfaceType = interfaces[index]; if (interfaceType.IsGenericType(genericInterface)) @@ -103,7 +104,7 @@ public static IEnumerable GetTypeInheritance(this Type type) } public static MethodInfo GetStaticMethod(this Type type, string name) => type.GetMethod(name, StaticFlags); - public static MethodInfo GetInstanceMethod(this Type type, string name) => + public static MethodInfo GetInstanceMethod(this Type type, string name) => (MethodInfo)type.GetMember(name, MemberTypes.Method, InstanceFlags).FirstOrDefault(); } } \ No newline at end of file diff --git a/src/AutoMapper/Mappers/CollectionMapper.cs b/src/AutoMapper/Mappers/CollectionMapper.cs index dba7c215cd..e6ee27d90f 100644 --- a/src/AutoMapper/Mappers/CollectionMapper.cs +++ b/src/AutoMapper/Mappers/CollectionMapper.cs @@ -67,20 +67,35 @@ Expression MapCollectionCore(Expression destExpression) var itemExpr = configurationProvider.MapExpression(profileMap, new TypePair(sourceElementType, destinationElementType), itemParam); Expression destination, assignNewExpression; UseDestinationValue(); - var addItems = ForEach(itemParam, sourceExpression, Call(destination, addMethod, itemExpr)); + var statements = configurationProvider.Expressions; + PrimitiveHelper.Clear(ref statements); + statements.Add(itemExpr); + var addCall = Call(destination, addMethod, statements); + statements.Clear(); + var variables = configurationProvider.Variables; + PrimitiveHelper.Clear(ref variables); + var addItems = ForEach(variables, statements, itemParam, sourceExpression, addCall); var overMaxDepth = OverMaxDepth(memberMap?.TypeMap); if (overMaxDepth != null) { addItems = Condition(overMaxDepth, ExpressionBuilder.Empty, addItems); } var clearMethod = isIList ? IListClear : destinationCollectionType.GetMethod("Clear"); - return Block(new[] { newExpression, passedDestination }, - CheckContext() ?? ExpressionBuilder.Empty, - Assign(passedDestination, destExpression), - assignNewExpression, - Call(destination, clearMethod), - addItems, - destination); + statements.Clear(); + variables.Clear(); + variables.Add(newExpression); + variables.Add(passedDestination); + var checkContext = CheckContext(); + if (checkContext != null) + { + statements.Add(checkContext); + } + statements.Add(Assign(passedDestination, destExpression)); + statements.Add(assignNewExpression); + statements.Add(Call(destination, clearMethod)); + statements.Add(addItems); + statements.Add(destination); + return Block(variables, statements); void GetDestinationType() { var immutableCollection = !mustUseDestination && destinationType.IsValueType; @@ -146,7 +161,7 @@ static class ArrayMapper private static readonly MethodInfo MapMultidimensionalMethod = typeof(ArrayMapper).GetStaticMethod(nameof(MapMultidimensional)); private static readonly ParameterExpression Index = Variable(typeof(int), "destinationArrayIndex"); private static readonly BinaryExpression ResetIndex = Assign(Index, Zero); - private static readonly UnaryExpression IncrementIndex = PostIncrementAssign(Index); + private static readonly UnaryExpression[] IncrementIndex = new[] { PostIncrementAssign(Index) }; private static Array MapMultidimensional(Array source, Type destinationElementType, ResolutionContext context) { var sourceElementType = source.GetType().GetElementType(); @@ -169,6 +184,10 @@ public static Expression MapToArray(IGlobalConfiguration configurationProvider, Type sourceElementType = typeof(object); Expression createDestination; var destination = Parameter(destinationType, "destinationArray"); + var variables = configurationProvider.Variables; + var statements = configurationProvider.Expressions; + PrimitiveHelper.Clear(ref variables); + PrimitiveHelper.Clear(ref statements); if (sourceType.IsArray) { var mapFromArray = MapFromArray(); @@ -185,28 +204,40 @@ public static Expression MapToArray(IGlobalConfiguration configurationProvider, return mapFromIEnumerable; } var count = Call(CountMethod.MakeGenericMethod(sourceElementType), sourceExpression); - createDestination = Assign(destination, NewArrayBounds(destinationElementType, count)); + statements.Add(count); + createDestination = Assign(destination, NewArrayBounds(destinationElementType, statements)); } var itemParam = Parameter(sourceElementType, "sourceItem"); var itemExpr = configurationProvider.MapExpression(profileMap, new TypePair(sourceElementType, destinationElementType), itemParam); var setItem = Assign(ArrayAccess(destination, IncrementIndex), itemExpr); - return Block(new[] { destination, Index }, - createDestination, - ResetIndex, - ForEach(itemParam, sourceExpression, setItem), - destination); + variables.Clear(); + statements.Clear(); + var forEach = ForEach(variables, statements, itemParam, sourceExpression, setItem); + variables.Clear(); + statements.Clear(); + variables.Add(destination); + variables.Add(Index); + statements.Add(createDestination); + statements.Add(ResetIndex); + statements.Add(forEach); + statements.Add(destination); + return Block(variables, statements); Expression MapFromArray() { sourceElementType = sourceType.GetElementType(); - createDestination = Assign(destination, NewArrayBounds(destinationElementType, ArrayLength(sourceExpression))); + statements.Add(ArrayLength(sourceExpression)); + createDestination = Assign(destination, NewArrayBounds(destinationElementType, statements)); if (MustMap(sourceElementType, destinationElementType)) { return null; } - return Block(new[] { destination }, - createDestination, - Call(sourceExpression, CopyToMethod, destination, Zero), - destination); + variables.Clear(); + statements.Clear(); + variables.Add(destination); + statements.Add(createDestination); + statements.Add(Call(sourceExpression, CopyToMethod, destination, Zero)); + statements.Add(destination); + return Block(variables, statements); } Expression MapFromIEnumerable() { diff --git a/src/AutoMapper/TypeMap.cs b/src/AutoMapper/TypeMap.cs index e5790b0e20..8d7192c157 100644 --- a/src/AutoMapper/TypeMap.cs +++ b/src/AutoMapper/TypeMap.cs @@ -202,17 +202,17 @@ internal void IgnorePaths(MemberInfo destinationMember) } } public bool HasDerivedTypesToInclude => IncludedDerivedTypes.Count > 0; - public void Seal(IGlobalConfiguration configurationProvider, HashSet typeMapsPath) + public void Seal(IGlobalConfiguration configurationProvider) { if (_sealed) { return; } _sealed = true; - _details?.Seal(configurationProvider, this, typeMapsPath); + _details?.Seal(configurationProvider, this); if (!Projection) { - MapExpression = CreateMapperLambda(configurationProvider, typeMapsPath); + MapExpression = CreateMapperLambda(configurationProvider); } SourceTypeDetails = null; DestinationTypeDetails = null; @@ -257,8 +257,8 @@ public void IncludeBaseTypes(TypePair baseTypes) public void AddAfterMapAction(LambdaExpression afterMap) => Details.AddAfterMapAction(afterMap); public void AddValueTransformation(ValueTransformerConfiguration config) => Details.AddValueTransformation(config); public void ConstructUsingServiceLocator() => CustomCtorFunction = Lambda(ServiceLocator(DestinationType)); - internal LambdaExpression CreateMapperLambda(IGlobalConfiguration configurationProvider, HashSet typeMapsPath) => - Types.IsGenericTypeDefinition ? null : new TypeMapPlanBuilder(configurationProvider, this).CreateMapperLambda(typeMapsPath); + internal LambdaExpression CreateMapperLambda(IGlobalConfiguration configurationProvider) => + Types.IsGenericTypeDefinition ? null : new TypeMapPlanBuilder(configurationProvider, this).CreateMapperLambda(); private PropertyMap GetPropertyMap(string name) => _propertyMaps?.GetValueOrDefault(name); private PropertyMap GetPropertyMap(PropertyMap propertyMap) => GetPropertyMap(propertyMap.DestinationName); public void AsProxy() => CustomCtorFunction = Lambda(Call(CreateProxyMethod, Constant(DestinationType))); @@ -297,7 +297,7 @@ class TypeMapDetails public HashSet IncludedMembersTypeMaps { get; private set; } public List ValueTransformerConfigs { get; private set; } public Features Features => _features ??= new(); - public void Seal(IGlobalConfiguration configurationProvider, TypeMap thisMap, HashSet typeMapsPath) + public void Seal(IGlobalConfiguration configurationProvider, TypeMap thisMap) { if (InheritedTypeMaps != null) { @@ -315,7 +315,7 @@ public void Seal(IGlobalConfiguration configurationProvider, TypeMap thisMap, Ha { foreach (var includedMemberTypeMap in IncludedMembersTypeMaps) { - includedMemberTypeMap.TypeMap.Seal(configurationProvider, typeMapsPath); + includedMemberTypeMap.TypeMap.Seal(configurationProvider); ApplyIncludedMemberTypeMap(includedMemberTypeMap, thisMap); } } diff --git a/src/Benchmark/BenchEngine.cs b/src/Benchmark/BenchEngine.cs index 468ce3eb5e..5e7069a04a 100644 --- a/src/Benchmark/BenchEngine.cs +++ b/src/Benchmark/BenchEngine.cs @@ -17,18 +17,18 @@ public BenchEngine(IObjectToObjectMapper mapper, string mode) public void Start() { _mapper.Initialize(); - _mapper.Map(); + //_mapper.Map(); - var timer = Stopwatch.StartNew(); + //var timer = Stopwatch.StartNew(); - for(int i = 0; i < 1_000_000; i++) - { - _mapper.Map(); - } + //for(int i = 0; i < 1_000_000; i++) + //{ + // _mapper.Map(); + //} - timer.Stop(); + //timer.Stop(); - Console.WriteLine("{2:D3} ms {0}: - {1}", _mapper.Name, _mode, (int)timer.Elapsed.TotalMilliseconds); + //Console.WriteLine("{2:D3} ms {0}: - {1}", _mapper.Name, _mode, (int)timer.Elapsed.TotalMilliseconds); } } } \ No newline at end of file diff --git a/src/Benchmark/FlatteningMapper.cs b/src/Benchmark/FlatteningMapper.cs index 462401185b..04c154068b 100644 --- a/src/Benchmark/FlatteningMapper.cs +++ b/src/Benchmark/FlatteningMapper.cs @@ -20,7 +20,7 @@ public void Initialize() cfg.CreateMap(); cfg.CreateMap(); }); - config.AssertConfigurationIsValid(); + //config.AssertConfigurationIsValid(); _mapper = config.CreateMapper(); _customer = new Customer() { @@ -192,7 +192,7 @@ public void Initialize() cfg.CreateMap(); cfg.CreateMap(); }); - config.AssertConfigurationIsValid(); + //config.AssertConfigurationIsValid(); _mapper = config.CreateMapper(); _foo = Foo.New(); } @@ -352,7 +352,7 @@ public class CtorMapper : IObjectToObjectMapper public void Initialize() { var config = new MapperConfiguration(cfg => cfg.CreateMap()); - config.AssertConfigurationIsValid(); + //config.AssertConfigurationIsValid(); _mapper = config.CreateMapper(); _model = new Model11 { Value = 5 }; } @@ -406,7 +406,7 @@ public void Initialize() cfg.CreateMap(); cfg.CreateMap(); }); - config.AssertConfigurationIsValid(); + //config.AssertConfigurationIsValid(); _mapper = config.CreateMapper(); _source = new ModelObject { diff --git a/src/Benchmark/Program.cs b/src/Benchmark/Program.cs index 61e5f78689..b5195d2723 100644 --- a/src/Benchmark/Program.cs +++ b/src/Benchmark/Program.cs @@ -15,7 +15,7 @@ public static void Main(string[] args) { "Complex", new IObjectToObjectMapper[] { new ComplexTypeMapper(), new ManualComplexTypeMapper() } }, { "Deep", new IObjectToObjectMapper[] { new DeepTypeMapper(), new ManualDeepTypeMapper() } } }; - while (true) + //while (true) { foreach (var pair in mappers) { @@ -24,7 +24,7 @@ public static void Main(string[] args) new BenchEngine(mapper, pair.Key).Start(); } } - Console.ReadLine(); + //Console.ReadLine(); } } } From dac3062028e8926d34389fc27b9c7a1490dde55c Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Wed, 17 Aug 2022 11:13:02 +0300 Subject: [PATCH 28/67] rename configurationProvider to the shorter configuration in most places --- .../Configuration/MapperConfiguration.cs | 2 +- src/AutoMapper/Execution/ExpressionBuilder.cs | 66 +++++++++++++------ .../Execution/TypeMapPlanBuilder.cs | 45 +++++++------ src/AutoMapper/Features.cs | 8 +-- src/AutoMapper/Internal/PrimitiveHelper.cs | 11 ---- src/AutoMapper/Mapper.cs | 12 ++-- src/AutoMapper/Mappers/AssignableMapper.cs | 2 +- src/AutoMapper/Mappers/CollectionMapper.cs | 24 +++---- src/AutoMapper/Mappers/ConstructorMapper.cs | 2 +- .../Mappers/ConversionOperatorMapper.cs | 2 +- src/AutoMapper/Mappers/ConvertMapper.cs | 2 +- src/AutoMapper/Mappers/EnumToEnumMapper.cs | 7 +- src/AutoMapper/Mappers/FromDynamicMapper.cs | 2 +- .../Mappers/FromStringDictionaryMapper.cs | 2 +- src/AutoMapper/Mappers/IObjectMapper.cs | 6 +- src/AutoMapper/Mappers/KeyValueMapper.cs | 6 +- .../Mappers/NullableDestinationMapper.cs | 4 +- .../Mappers/NullableSourceMapper.cs | 4 +- src/AutoMapper/Mappers/ParseStringMapper.cs | 2 +- src/AutoMapper/Mappers/StringToEnumMapper.cs | 2 +- src/AutoMapper/Mappers/ToDynamicMapper.cs | 2 +- .../Mappers/ToStringDictionaryMapper.cs | 2 +- src/AutoMapper/Mappers/ToStringMapper.cs | 2 +- .../Mappers/UnderlyingEnumTypeMapper.cs | 2 +- src/AutoMapper/ProfileMap.cs | 66 +++++++++---------- .../QueryableExtensions/ProjectionBuilder.cs | 34 +++++----- src/AutoMapper/TypeMap.cs | 16 ++--- 27 files changed, 176 insertions(+), 159 deletions(-) diff --git a/src/AutoMapper/Configuration/MapperConfiguration.cs b/src/AutoMapper/Configuration/MapperConfiguration.cs index 3d4d4e0c90..24413e290a 100644 --- a/src/AutoMapper/Configuration/MapperConfiguration.cs +++ b/src/AutoMapper/Configuration/MapperConfiguration.cs @@ -233,7 +233,7 @@ LambdaExpression GenerateObjectMapperExpression(in MapRequest mapRequest, IObjec if (nullCheck) { var profileMap = mapRequest.MemberMap.Profile ?? Configuration; - fullExpression = NullCheckSource(profileMap, source, destination, fullExpression, mapRequest.MemberMap); + fullExpression = this.NullCheckSource(profileMap, source, destination, fullExpression, mapRequest.MemberMap); } return Lambda(fullExpression, source, destination, ContextParameter); } diff --git a/src/AutoMapper/Execution/ExpressionBuilder.cs b/src/AutoMapper/Execution/ExpressionBuilder.cs index 40a8d96d28..f3dd3b0839 100644 --- a/src/AutoMapper/Execution/ExpressionBuilder.cs +++ b/src/AutoMapper/Execution/ExpressionBuilder.cs @@ -42,12 +42,33 @@ public static class ExpressionBuilder private static readonly ParameterExpression[] Indexes = new[] { Index }; private static readonly BinaryExpression ResetIndex = Assign(Index, Zero); private static readonly UnaryExpression IncrementIndex = PostIncrementAssign(Index); - - public static Expression MapExpression(this IGlobalConfiguration configurationProvider, ProfileMap profileMap, TypePair typePair, Expression source, + public static (List Variables, List Expressions) ScratchPad(this IGlobalConfiguration configuration) + { + var variables = configuration.Variables; + if (variables == null) + { + variables = new(); + } + else + { + variables.Clear(); + } + var expressions = configuration.Expressions; + if (expressions == null) + { + expressions = new(); + } + else + { + expressions.Clear(); + } + return (variables, expressions); + } + public static Expression MapExpression(this IGlobalConfiguration configuration, ProfileMap profileMap, TypePair typePair, Expression source, MemberMap memberMap = null, Expression destination = null) { destination ??= Default(typePair.DestinationType); - var typeMap = configurationProvider.ResolveTypeMap(typePair); + var typeMap = configuration.ResolveTypeMap(typePair); Expression mapExpression = null; bool nullCheck; if (typeMap != null) @@ -56,7 +77,7 @@ public static Expression MapExpression(this IGlobalConfiguration configurationPr nullCheck = !typeMap.HasTypeConverter && allowNull.HasValue && allowNull != profileMap.AllowNullDestinationValues; if (!typeMap.HasDerivedTypesToInclude) { - typeMap.Seal(configurationProvider); + typeMap.Seal(configuration); if (typeMap.MapExpression != null) { mapExpression = typeMap.Invoke(source, destination); @@ -65,10 +86,10 @@ public static Expression MapExpression(this IGlobalConfiguration configurationPr } else { - var mapper = configurationProvider.FindMapper(typePair); + var mapper = configuration.FindMapper(typePair); if (mapper != null) { - mapExpression = mapper.MapExpression(configurationProvider, profileMap, memberMap, source, destination); + mapExpression = mapper.MapExpression(configuration, profileMap, memberMap, source, destination); nullCheck = mapExpression != source; mapExpression = ToType(mapExpression, typePair.DestinationType); } @@ -78,9 +99,10 @@ public static Expression MapExpression(this IGlobalConfiguration configurationPr } } mapExpression ??= ContextMap(typePair, source, destination, memberMap); - return nullCheck ? NullCheckSource(profileMap, source, destination, mapExpression, memberMap) : mapExpression; + return nullCheck ? configuration.NullCheckSource(profileMap, source, destination, mapExpression, memberMap) : mapExpression; } - public static Expression NullCheckSource(ProfileMap profileMap, Expression source, Expression destination, Expression mapExpression, MemberMap memberMap) + public static Expression NullCheckSource(this IGlobalConfiguration configuration, ProfileMap profileMap, Expression source, Expression destination, + Expression mapExpression, MemberMap memberMap) { var sourceType = source.Type; if (sourceType.IsValueType && !sourceType.IsNullableType()) @@ -120,10 +142,12 @@ Expression ClearDestinationCollection() } clearMethod = destinationCollectionType.GetMethod("Clear"); } - return Block(new[] { destinationVariable }, - Assign(destinationVariable, destination), - Condition(ReferenceEqual(collection, Null), Empty, Expression.Call(collection, clearMethod)), - destinationVariable); + var (variables, statements) = configuration.ScratchPad(); + variables.Add(destinationVariable); + statements.Add(Assign(destinationVariable, destination)); + statements.Add(Condition(ReferenceEqual(collection, Null), Empty, Expression.Call(collection, clearMethod))); + statements.Add(destinationVariable); + return Block(variables, statements); } Expression DefaultDestination() { @@ -264,17 +288,19 @@ public static Expression ForEach(List variables, List variables, List statements, ParameterExpression loopVar, Expression array, Expression loopContent) { @@ -291,7 +317,7 @@ static Expression ForEachArrayItem(List variables, List statements, Expression target, Expression body) { Expression finallyDispose; if (typeof(IDisposable).IsAssignableFrom(target.Type)) @@ -305,7 +331,9 @@ static Expression Using(Expression target, Expression body) return body; } var assignDisposable = Assign(Disposable, TypeAs(target, typeof(IDisposable))); - finallyDispose = Block(DisposableArray, assignDisposable, DisposeCall); + statements.Add(assignDisposable); + statements.Add(DisposeCall); + finallyDispose = Block(DisposableArray, statements); } return TryFinally(body, finallyDispose); } diff --git a/src/AutoMapper/Execution/TypeMapPlanBuilder.cs b/src/AutoMapper/Execution/TypeMapPlanBuilder.cs index 8dd5e6277b..cb36f77538 100644 --- a/src/AutoMapper/Execution/TypeMapPlanBuilder.cs +++ b/src/AutoMapper/Execution/TypeMapPlanBuilder.cs @@ -13,30 +13,30 @@ namespace AutoMapper.Execution public struct TypeMapPlanBuilder { private static readonly MethodInfo MappingError = typeof(TypeMapPlanBuilder).GetStaticMethod(nameof(MemberMappingError)); - private readonly IGlobalConfiguration _configurationProvider; + private readonly IGlobalConfiguration _configuration; private readonly ParameterExpression _destination; private readonly ParameterExpression _initialDestination; private readonly TypeMap _typeMap; private List _variables; private List _expressions; private CatchBlock[] _catches; - public TypeMapPlanBuilder(IGlobalConfiguration configurationProvider, TypeMap typeMap) + public TypeMapPlanBuilder(IGlobalConfiguration configuration, TypeMap typeMap) { - _configurationProvider = configurationProvider; + _configuration = configuration; _typeMap = typeMap; Source = Parameter(typeMap.SourceType, "source"); _initialDestination = Parameter(typeMap.DestinationType, "destination"); _destination = Variable(_initialDestination.Type, "typeMapDestination"); - _variables = configurationProvider.Variables; - _expressions = configurationProvider.Expressions; - _catches = configurationProvider.Catches; + _variables = configuration.Variables; + _expressions = configuration.Expressions; + _catches = configuration.Catches; } public Type DestinationType => _destination.Type; public ParameterExpression Source { get; } private static AutoMapperMappingException MemberMappingError(Exception innerException, MemberMap memberMap) => new("Error mapping types.", innerException, memberMap); ParameterExpression[] GetParameters(ParameterExpression source = null, ParameterExpression destination = null) { - var parameters = _configurationProvider.Parameters ?? new ParameterExpression[] { null, null, ContextParameter }; + var parameters = _configuration.Parameters ?? new ParameterExpression[] { null, null, ContextParameter }; parameters[0] = source ?? Source; parameters[1] = destination ?? _destination; return parameters; @@ -52,9 +52,9 @@ public LambdaExpression CreateMapperLambda() _variables ??= new(); _expressions ??= new(); _catches ??= new CatchBlock[1]; - var typeMapsPath = _configurationProvider.TypeMapsPath; + var typeMapsPath = _configuration.TypeMapsPath; Clear(ref typeMapsPath); - CheckForCycles(_configurationProvider, _typeMap, typeMapsPath); + CheckForCycles(_configuration, _typeMap, typeMapsPath); var createDestinationFunc = CreateDestinationFunc(); var assignmentFunc = CreateAssignmentFunc(createDestinationFunc); var mapperFunc = CreateMapperFunc(assignmentFunc); @@ -91,7 +91,7 @@ void IncludeMembers() _expressions.AddRange(_variables.Zip(_typeMap.IncludedMembersTypeMaps, (v, i) => Assign(v, i.MemberExpression.ReplaceParameters(source).NullCheck()))); } - private static void CheckForCycles(IGlobalConfiguration configurationProvider, TypeMap typeMap, HashSet typeMapsPath) + private static void CheckForCycles(IGlobalConfiguration configuration, TypeMap typeMap, HashSet typeMapsPath) { typeMapsPath.Add(typeMap); foreach (var memberMap in MemberMaps()) @@ -101,7 +101,7 @@ private static void CheckForCycles(IGlobalConfiguration configurationProvider, T { continue; } - if (memberMap.Inline && (memberTypeMap.PreserveReferences || typeMapsPath.Count == configurationProvider.MaxExecutionPlanDepth)) + if (memberMap.Inline && (memberTypeMap.PreserveReferences || typeMapsPath.Count == configuration.MaxExecutionPlanDepth)) { memberMap.Inline = false; TraceInline(typeMap, memberMap); @@ -127,13 +127,13 @@ private static void CheckForCycles(IGlobalConfiguration configurationProvider, T memberMap.Inline = false; TraceInline(typeMap, memberMap); } - foreach (var derivedTypeMap in configurationProvider.GetIncludedTypeMaps(memberTypeMap)) + foreach (var derivedTypeMap in configuration.GetIncludedTypeMaps(memberTypeMap)) { derivedTypeMap.PreserveReferences = true; Trace(typeMap, derivedTypeMap, memberMap); } } - CheckForCycles(configurationProvider, memberTypeMap, typeMapsPath); + CheckForCycles(configuration, memberTypeMap, typeMapsPath); } typeMapsPath.Remove(typeMap); return; @@ -141,7 +141,7 @@ IEnumerable MemberMaps() { var memberMaps = typeMap.MemberMaps; return typeMap.HasDerivedTypesToInclude ? - memberMaps.Concat(configurationProvider.GetIncludedTypeMaps(typeMap).SelectMany(tm => tm.MemberMaps)) : + memberMaps.Concat(configuration.GetIncludedTypeMaps(typeMap).SelectMany(tm => tm.MemberMaps)) : memberMaps; } TypeMap ResolveMemberTypeMap(MemberMap memberMap) @@ -151,7 +151,7 @@ TypeMap ResolveMemberTypeMap(MemberMap memberMap) return null; } var types = memberMap.Types(); - return types.ContainsGenericParameters ? null : configurationProvider.ResolveAssociatedTypeMap(types); + return types.ContainsGenericParameters ? null : configuration.ResolveAssociatedTypeMap(types); } [Conditional("DEBUG")] static void Trace(TypeMap typeMap, TypeMap memberTypeMap, MemberMap memberMap) => @@ -247,7 +247,7 @@ private Expression CreateMapperFunc(Expression assignmentFunc) { mapperFunc = Condition(overMaxDepth, Default(DestinationType), mapperFunc); } - mapperFunc = NullCheckSource(_typeMap.Profile, Source, _initialDestination, mapperFunc, null); + mapperFunc = _configuration.NullCheckSource(_typeMap.Profile, Source, _initialDestination, mapperFunc, null); return CheckReferencesCache(mapperFunc); } private Expression CheckReferencesCache(Expression valueBuilder) @@ -280,10 +280,13 @@ private Expression CreateConstructorParameterExpression(ConstructorParameterMap var customSource = GetCustomSource(ctorParamMap); var resolvedExpression = BuildValueResolverFunc(ctorParamMap, customSource, defaultValue); var resolvedValue = Variable(resolvedExpression.Type, "resolvedValue"); - var tryMap = Block(new[] { resolvedValue }, - Assign(resolvedValue, resolvedExpression), - MapMember(ctorParamMap, defaultValue, resolvedValue)); - return TryMemberMap(ctorParamMap, tryMap); + var mapMember = MapMember(ctorParamMap, defaultValue, resolvedValue); + _variables.Clear(); + _variables.Add(resolvedValue); + _expressions.Clear(); + _expressions.Add(Assign(resolvedValue, resolvedExpression)); + _expressions.Add(mapMember); + return TryMemberMap(ctorParamMap, Block(_variables, _expressions)); } private Expression TryPropertyMap(PropertyMap propertyMap) { @@ -375,7 +378,7 @@ Expression MapMember(MemberMap memberMap, Expression destinationMemberValue, Par { var typePair = memberMap.Types(); var mapMember = memberMap.Inline ? - _configurationProvider.MapExpression(_typeMap.Profile, typePair, resolvedValue, memberMap, destinationMemberValue) : + _configuration.MapExpression(_typeMap.Profile, typePair, resolvedValue, memberMap, destinationMemberValue) : ContextMap(typePair, resolvedValue, destinationMemberValue, memberMap); return memberMap.ApplyTransformers(mapMember); } diff --git a/src/AutoMapper/Features.cs b/src/AutoMapper/Features.cs index 6efacea876..ed2e2f0310 100644 --- a/src/AutoMapper/Features.cs +++ b/src/AutoMapper/Features.cs @@ -7,7 +7,7 @@ namespace AutoMapper.Features { public interface IGlobalFeature { - void Configure(IGlobalConfiguration configurationProvider); + void Configure(IGlobalConfiguration configuration); } public interface IMappingFeature { @@ -16,7 +16,7 @@ public interface IMappingFeature } public interface IRuntimeFeature { - void Seal(IGlobalConfiguration configurationProvider); + void Seal(IGlobalConfiguration configuration); } public class Features : IReadOnlyCollection { @@ -91,7 +91,7 @@ internal static void Configure(this Features features, TypeMap feature.Configure(typeMap); } } - internal static void Seal(this Features features, IGlobalConfiguration configurationProvider) + internal static void Seal(this Features features, IGlobalConfiguration configuration) { if (features.Count == 0) { @@ -99,7 +99,7 @@ internal static void Seal(this Features features, IGlobalConfig } foreach (var feature in features) { - feature.Seal(configurationProvider); + feature.Seal(configuration); } } } diff --git a/src/AutoMapper/Internal/PrimitiveHelper.cs b/src/AutoMapper/Internal/PrimitiveHelper.cs index 8f2a4603eb..4616fc5973 100644 --- a/src/AutoMapper/Internal/PrimitiveHelper.cs +++ b/src/AutoMapper/Internal/PrimitiveHelper.cs @@ -8,17 +8,6 @@ namespace AutoMapper.Internal [EditorBrowsable(EditorBrowsableState.Never)] public static class PrimitiveHelper { - public static void Clear(ref T collection) where T : IList, new() - { - if (collection == null) - { - collection = new(); - } - else - { - collection.Clear(); - } - } public static IReadOnlyCollection NullCheck(this IReadOnlyCollection source) => source ?? Array.Empty(); public static IEnumerable Concat(this IReadOnlyCollection collection, IReadOnlyCollection otherCollection) { diff --git a/src/AutoMapper/Mapper.cs b/src/AutoMapper/Mapper.cs index 9c272a2fb9..6aee4c5687 100644 --- a/src/AutoMapper/Mapper.cs +++ b/src/AutoMapper/Mapper.cs @@ -145,19 +145,19 @@ internal interface IInternalRuntimeMapper : IRuntimeMapper } public class Mapper : IMapper, IInternalRuntimeMapper { - private readonly IGlobalConfiguration _configurationProvider; + private readonly IGlobalConfiguration _configuration; private readonly Factory _serviceCtor; - public Mapper(IConfigurationProvider configurationProvider) : this(configurationProvider, configurationProvider.Internal().ServiceCtor) { } - public Mapper(IConfigurationProvider configurationProvider, Factory serviceCtor) + public Mapper(IConfigurationProvider configuration) : this(configuration, configuration.Internal().ServiceCtor) { } + public Mapper(IConfigurationProvider configuration, Factory serviceCtor) { - _configurationProvider = (IGlobalConfiguration)configurationProvider ?? throw new ArgumentNullException(nameof(configurationProvider)); + _configuration = (IGlobalConfiguration)configuration ?? throw new ArgumentNullException(nameof(configuration)); _serviceCtor = serviceCtor ?? throw new NullReferenceException(nameof(serviceCtor)); DefaultContext = new(this); } internal ResolutionContext DefaultContext { get; } ResolutionContext IInternalRuntimeMapper.DefaultContext => DefaultContext; Factory IInternalRuntimeMapper.ServiceCtor => _serviceCtor; - public IConfigurationProvider ConfigurationProvider => _configurationProvider; + public IConfigurationProvider ConfigurationProvider => _configuration; public TDestination Map(object source) => Map(source, default(TDestination)); public TDestination Map(object source, Action> opts) => Map(source, default, opts); public TDestination Map(TSource source) => Map(source, default(TDestination)); @@ -200,7 +200,7 @@ private TDestination MapCore( TypePair runtimeTypes = new(source?.GetType() ?? sourceType ?? typeof(TSource), destination?.GetType() ?? destinationType ?? typeof(TDestination)); memberMap ??= destination == null ? MemberMap.Instance : MemberMap.InstanceUseDestination; MapRequest mapRequest = new(requestedTypes, runtimeTypes, memberMap); - return _configurationProvider.GetExecutionPlan(mapRequest)(source, destination, context); + return _configuration.GetExecutionPlan(mapRequest)(source, destination, context); } } } \ No newline at end of file diff --git a/src/AutoMapper/Mappers/AssignableMapper.cs b/src/AutoMapper/Mappers/AssignableMapper.cs index 4d4ebf4366..a5d0b5ffa6 100644 --- a/src/AutoMapper/Mappers/AssignableMapper.cs +++ b/src/AutoMapper/Mappers/AssignableMapper.cs @@ -4,7 +4,7 @@ namespace AutoMapper.Internal.Mappers public class AssignableMapper : IObjectMapper { public bool IsMatch(TypePair context) => context.DestinationType.IsAssignableFrom(context.SourceType); - public Expression MapExpression(IGlobalConfiguration configurationProvider, ProfileMap profileMap, + public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) => sourceExpression; } } \ No newline at end of file diff --git a/src/AutoMapper/Mappers/CollectionMapper.cs b/src/AutoMapper/Mappers/CollectionMapper.cs index e6ee27d90f..72a95c42e4 100644 --- a/src/AutoMapper/Mappers/CollectionMapper.cs +++ b/src/AutoMapper/Mappers/CollectionMapper.cs @@ -16,12 +16,12 @@ public class CollectionMapper : IObjectMapper { public TypePair? GetAssociatedTypes(TypePair context) => new(GetElementType(context.SourceType), GetElementType(context.DestinationType)); public bool IsMatch(TypePair context) => context.IsCollection(); - public Expression MapExpression(IGlobalConfiguration configurationProvider, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) + public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) { var destinationType = destExpression.Type; if (destinationType.IsArray) { - return ArrayMapper.MapToArray(configurationProvider, profileMap, sourceExpression, destinationType); + return ArrayMapper.MapToArray(configuration, profileMap, sourceExpression, destinationType); } if (destinationType.IsGenericType(typeof(ReadOnlyCollection<>))) { @@ -64,16 +64,13 @@ Expression MapCollectionCore(Expression destExpression) throw new NotSupportedException($"Unknown collection. Consider a custom type converter from {sourceType} to {destinationType}."); } var itemParam = Parameter(sourceElementType, "item"); - var itemExpr = configurationProvider.MapExpression(profileMap, new TypePair(sourceElementType, destinationElementType), itemParam); + var itemExpr = configuration.MapExpression(profileMap, new TypePair(sourceElementType, destinationElementType), itemParam); Expression destination, assignNewExpression; UseDestinationValue(); - var statements = configurationProvider.Expressions; - PrimitiveHelper.Clear(ref statements); + var (variables, statements) = configuration.ScratchPad(); statements.Add(itemExpr); var addCall = Call(destination, addMethod, statements); statements.Clear(); - var variables = configurationProvider.Variables; - PrimitiveHelper.Clear(ref variables); var addItems = ForEach(variables, statements, itemParam, sourceExpression, addCall); var overMaxDepth = OverMaxDepth(memberMap?.TypeMap); if (overMaxDepth != null) @@ -146,7 +143,7 @@ void UseDestinationValue() } Expression CheckContext() { - var elementTypeMap = configurationProvider.ResolveTypeMap(sourceElementType, destinationElementType); + var elementTypeMap = configuration.ResolveTypeMap(sourceElementType, destinationElementType); return elementTypeMap == null ? null : ExpressionBuilder.CheckContext(elementTypeMap); } } @@ -173,7 +170,7 @@ private static Array MapMultidimensional(Array source, Type destinationElementTy } return destinationArray; } - public static Expression MapToArray(IGlobalConfiguration configurationProvider, ProfileMap profileMap, Expression sourceExpression, Type destinationType) + public static Expression MapToArray(IGlobalConfiguration configuration, ProfileMap profileMap, Expression sourceExpression, Type destinationType) { var destinationElementType = destinationType.GetElementType(); if (destinationType.GetArrayRank() > 1) @@ -184,10 +181,7 @@ public static Expression MapToArray(IGlobalConfiguration configurationProvider, Type sourceElementType = typeof(object); Expression createDestination; var destination = Parameter(destinationType, "destinationArray"); - var variables = configurationProvider.Variables; - var statements = configurationProvider.Expressions; - PrimitiveHelper.Clear(ref variables); - PrimitiveHelper.Clear(ref statements); + var (variables, statements) = configuration.ScratchPad(); if (sourceType.IsArray) { var mapFromArray = MapFromArray(); @@ -208,7 +202,7 @@ public static Expression MapToArray(IGlobalConfiguration configurationProvider, createDestination = Assign(destination, NewArrayBounds(destinationElementType, statements)); } var itemParam = Parameter(sourceElementType, "sourceItem"); - var itemExpr = configurationProvider.MapExpression(profileMap, new TypePair(sourceElementType, destinationElementType), itemParam); + var itemExpr = configuration.MapExpression(profileMap, new TypePair(sourceElementType, destinationElementType), itemParam); var setItem = Assign(ArrayAccess(destination, IncrementIndex), itemExpr); variables.Clear(); statements.Clear(); @@ -249,7 +243,7 @@ Expression MapFromIEnumerable() return Call(ToArrayMethod.MakeGenericMethod(sourceElementType), sourceExpression); } bool MustMap(Type sourceType, Type destinationType) => !destinationType.IsAssignableFrom(sourceType) || - configurationProvider.FindTypeMapFor(sourceType, destinationType) != null; + configuration.FindTypeMapFor(sourceType, destinationType) != null; } } } diff --git a/src/AutoMapper/Mappers/ConstructorMapper.cs b/src/AutoMapper/Mappers/ConstructorMapper.cs index c0b1c65c51..d4d6177f64 100644 --- a/src/AutoMapper/Mappers/ConstructorMapper.cs +++ b/src/AutoMapper/Mappers/ConstructorMapper.cs @@ -9,7 +9,7 @@ public class ConstructorMapper : IObjectMapper public bool IsMatch(TypePair context) => GetConstructor(context.SourceType, context.DestinationType) != null; private static ConstructorInfo GetConstructor(Type sourceType, Type destinationType) => destinationType.GetConstructor(TypeExtensions.InstanceFlags, null, new[] { sourceType }, null); - public Expression MapExpression(IGlobalConfiguration configurationProvider, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) + public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) { var constructor = GetConstructor(sourceExpression.Type, destExpression.Type); return Expression.New(constructor, ToType(sourceExpression, constructor.FirstParameterType())); diff --git a/src/AutoMapper/Mappers/ConversionOperatorMapper.cs b/src/AutoMapper/Mappers/ConversionOperatorMapper.cs index 6f790e18eb..6af476b5d5 100644 --- a/src/AutoMapper/Mappers/ConversionOperatorMapper.cs +++ b/src/AutoMapper/Mappers/ConversionOperatorMapper.cs @@ -20,7 +20,7 @@ private MethodInfo GetConversionOperator(Type sourceType, Type destinationType) } return destinationType.GetMethod(_operatorName, TypeExtensions.StaticFlags, null, new[] { sourceType }, null); } - public Expression MapExpression(IGlobalConfiguration configurationProvider, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) + public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) { var conversionOperator = GetConversionOperator(sourceExpression.Type, destExpression.Type); return Expression.Call(conversionOperator, ToType(sourceExpression, conversionOperator.FirstParameterType())); diff --git a/src/AutoMapper/Mappers/ConvertMapper.cs b/src/AutoMapper/Mappers/ConvertMapper.cs index 77da487c15..0ff272e886 100644 --- a/src/AutoMapper/Mappers/ConvertMapper.cs +++ b/src/AutoMapper/Mappers/ConvertMapper.cs @@ -8,7 +8,7 @@ public class ConvertMapper : IObjectMapper public static bool IsPrimitive(Type type) => type.IsPrimitive || type == typeof(string) || type == typeof(decimal); public bool IsMatch(TypePair types) => (types.SourceType == typeof(string) && types.DestinationType == typeof(DateTime)) || (IsPrimitive(types.SourceType) && IsPrimitive(types.DestinationType)); - public Expression MapExpression(IGlobalConfiguration configurationProvider, ProfileMap profileMap, + public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) { var convertMethod = typeof(Convert).GetMethod("To" + destExpression.Type.Name, new[] { sourceExpression.Type }); diff --git a/src/AutoMapper/Mappers/EnumToEnumMapper.cs b/src/AutoMapper/Mappers/EnumToEnumMapper.cs index 3276d01989..db4f8da486 100644 --- a/src/AutoMapper/Mappers/EnumToEnumMapper.cs +++ b/src/AutoMapper/Mappers/EnumToEnumMapper.cs @@ -9,7 +9,7 @@ public class EnumToEnumMapper : IObjectMapper { private static readonly MethodInfo TryParseMethod = typeof(Enum).StaticGenericMethod("TryParse", parametersCount: 3); public bool IsMatch(TypePair context) => context.IsEnumToEnum(); - public Expression MapExpression(IGlobalConfiguration configurationProvider, ProfileMap profileMap, + public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) { var destinationType = destExpression.Type; @@ -17,7 +17,10 @@ public Expression MapExpression(IGlobalConfiguration configurationProvider, Prof var result = Variable(destinationType, "destinationEnumValue"); var ignoreCase = True; var tryParse = Call(TryParseMethod.MakeGenericMethod(destinationType), sourceToString, ignoreCase, result); - return Block(new[] { result }, Condition(tryParse, result, Convert(sourceExpression, destinationType))); + var (variables, statements) = configuration.ScratchPad(); + variables.Add(result); + statements.Add(Condition(tryParse, result, Convert(sourceExpression, destinationType))); + return Block(variables, statements); } } } \ No newline at end of file diff --git a/src/AutoMapper/Mappers/FromDynamicMapper.cs b/src/AutoMapper/Mappers/FromDynamicMapper.cs index 52cfa2c482..5314d90c6a 100644 --- a/src/AutoMapper/Mappers/FromDynamicMapper.cs +++ b/src/AutoMapper/Mappers/FromDynamicMapper.cs @@ -40,7 +40,7 @@ private static object GetDynamically(string memberName, object target) return callsite.Target(callsite, target); } public bool IsMatch(TypePair context) => context.SourceType.IsDynamic() && !context.DestinationType.IsDynamic(); - public Expression MapExpression(IGlobalConfiguration configurationProvider, ProfileMap profileMap, + public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) => Call(MapMethodInfo, sourceExpression, destExpression.ToObject(), Constant(destExpression.Type), ContextParameter, Constant(profileMap)); } diff --git a/src/AutoMapper/Mappers/FromStringDictionaryMapper.cs b/src/AutoMapper/Mappers/FromStringDictionaryMapper.cs index f69992214e..d86a26e476 100644 --- a/src/AutoMapper/Mappers/FromStringDictionaryMapper.cs +++ b/src/AutoMapper/Mappers/FromStringDictionaryMapper.cs @@ -12,7 +12,7 @@ public class FromStringDictionaryMapper : IObjectMapper { private static readonly MethodInfo MapDynamicMethod = typeof(FromStringDictionaryMapper).GetStaticMethod(nameof(MapDynamic)); public bool IsMatch(TypePair context) => typeof(StringDictionary).IsAssignableFrom(context.SourceType); - public Expression MapExpression(IGlobalConfiguration configurationProvider, ProfileMap profileMap, MemberMap memberMap, + public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) => Call(MapDynamicMethod, sourceExpression, destExpression.ToObject(), Constant(destExpression.Type), ContextParameter, Constant(profileMap)); private static object MapDynamic(StringDictionary source, object boxedDestination, Type destinationType, ResolutionContext context, ProfileMap profileMap) diff --git a/src/AutoMapper/Mappers/IObjectMapper.cs b/src/AutoMapper/Mappers/IObjectMapper.cs index 0063d0de1a..af3004a45a 100644 --- a/src/AutoMapper/Mappers/IObjectMapper.cs +++ b/src/AutoMapper/Mappers/IObjectMapper.cs @@ -20,14 +20,14 @@ public interface IObjectMapper /// /// Builds a mapping expression equivalent to the base Map method /// - /// + /// /// /// /// Source parameter /// Destination parameter /// /// Map expression - Expression MapExpression(IGlobalConfiguration configurationProvider, ProfileMap profileMap, + Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression); TypePair? GetAssociatedTypes(TypePair initialTypes) => null; } @@ -59,7 +59,7 @@ public virtual bool IsMatch(TypePair context) => /// Destination object public abstract TDestination Map(TSource source, TDestination destination, Type sourceType, Type destinationType, ResolutionContext context); - public Expression MapExpression(IGlobalConfiguration configurationProvider, ProfileMap profileMap, + public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) => Call( Constant(this), diff --git a/src/AutoMapper/Mappers/KeyValueMapper.cs b/src/AutoMapper/Mappers/KeyValueMapper.cs index bc85002e8e..3a76883283 100644 --- a/src/AutoMapper/Mappers/KeyValueMapper.cs +++ b/src/AutoMapper/Mappers/KeyValueMapper.cs @@ -8,15 +8,15 @@ public class KeyValueMapper : IObjectMapper { public bool IsMatch(TypePair context) => IsKeyValue(context.SourceType) && IsKeyValue(context.DestinationType); public static bool IsKeyValue(Type type) => type.IsGenericType(typeof(KeyValuePair<,>)); - public Expression MapExpression(IGlobalConfiguration configurationProvider, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) + public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) { var sourceArguments = sourceExpression.Type.GenericTypeArguments; var destinationType = destExpression.Type; var destinationArguments = destinationType.GenericTypeArguments; var keys = new TypePair(sourceArguments[0], destinationArguments[0]); var values = new TypePair(sourceArguments[1], destinationArguments[1]); - var mapKeys = configurationProvider.MapExpression(profileMap, keys, ExpressionBuilder.Property(sourceExpression, "Key")); - var mapValues = configurationProvider.MapExpression(profileMap, values, ExpressionBuilder.Property(sourceExpression, "Value")); + var mapKeys = configuration.MapExpression(profileMap, keys, ExpressionBuilder.Property(sourceExpression, "Key")); + var mapValues = configuration.MapExpression(profileMap, values, ExpressionBuilder.Property(sourceExpression, "Value")); return Expression.New(destinationType.GetConstructor(destinationArguments), mapKeys, mapValues); } } diff --git a/src/AutoMapper/Mappers/NullableDestinationMapper.cs b/src/AutoMapper/Mappers/NullableDestinationMapper.cs index 28749d0aeb..76ef5d237a 100644 --- a/src/AutoMapper/Mappers/NullableDestinationMapper.cs +++ b/src/AutoMapper/Mappers/NullableDestinationMapper.cs @@ -6,8 +6,8 @@ namespace AutoMapper.Internal.Mappers public class NullableDestinationMapper : IObjectMapper { public bool IsMatch(TypePair context) => context.DestinationType.IsNullableType(); - public Expression MapExpression(IGlobalConfiguration configurationProvider, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) => - configurationProvider.MapExpression(profileMap, GetAssociatedTypes(sourceExpression.Type, destExpression.Type), sourceExpression, memberMap); + public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) => + configuration.MapExpression(profileMap, GetAssociatedTypes(sourceExpression.Type, destExpression.Type), sourceExpression, memberMap); public TypePair? GetAssociatedTypes(TypePair initialTypes) => GetAssociatedTypes(initialTypes.SourceType, initialTypes.DestinationType); TypePair GetAssociatedTypes(Type sourceType, Type destinationType) => new(sourceType, Nullable.GetUnderlyingType(destinationType)); } diff --git a/src/AutoMapper/Mappers/NullableSourceMapper.cs b/src/AutoMapper/Mappers/NullableSourceMapper.cs index 82558915b1..9d9a8ce711 100644 --- a/src/AutoMapper/Mappers/NullableSourceMapper.cs +++ b/src/AutoMapper/Mappers/NullableSourceMapper.cs @@ -6,8 +6,8 @@ namespace AutoMapper.Internal.Mappers public class NullableSourceMapper : IObjectMapper { public bool IsMatch(TypePair context) => context.SourceType.IsNullableType(); - public Expression MapExpression(IGlobalConfiguration configurationProvider, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) => - configurationProvider.MapExpression(profileMap, GetAssociatedTypes(sourceExpression.Type, destExpression.Type), + public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) => + configuration.MapExpression(profileMap, GetAssociatedTypes(sourceExpression.Type, destExpression.Type), ExpressionBuilder.Property(sourceExpression, "Value"), memberMap, destExpression); public TypePair? GetAssociatedTypes(TypePair initialTypes) => GetAssociatedTypes(initialTypes.SourceType, initialTypes.DestinationType); TypePair GetAssociatedTypes(Type sourceType, Type destinationType) => new(Nullable.GetUnderlyingType(sourceType), destinationType); diff --git a/src/AutoMapper/Mappers/ParseStringMapper.cs b/src/AutoMapper/Mappers/ParseStringMapper.cs index e96fb1f523..73a064f8db 100644 --- a/src/AutoMapper/Mappers/ParseStringMapper.cs +++ b/src/AutoMapper/Mappers/ParseStringMapper.cs @@ -6,7 +6,7 @@ public class ParseStringMapper : IObjectMapper { public bool IsMatch(TypePair context) => context.SourceType == typeof(string) && HasParse(context.DestinationType); static bool HasParse(Type type) => type == typeof(Guid) || type == typeof(TimeSpan) || type == typeof(DateTimeOffset); - public Expression MapExpression(IGlobalConfiguration configurationProvider, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) => + public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) => Expression.Call(destExpression.Type.GetMethod("Parse", new[] { typeof(string) }), sourceExpression); } } \ No newline at end of file diff --git a/src/AutoMapper/Mappers/StringToEnumMapper.cs b/src/AutoMapper/Mappers/StringToEnumMapper.cs index f84e0868f8..38e0aa1ba7 100644 --- a/src/AutoMapper/Mappers/StringToEnumMapper.cs +++ b/src/AutoMapper/Mappers/StringToEnumMapper.cs @@ -13,7 +13,7 @@ public class StringToEnumMapper : IObjectMapper private static readonly MethodInfo ParseMethod = typeof(Enum).StaticGenericMethod("Parse", parametersCount: 2); private static readonly PropertyInfo Length = typeof(string).GetProperty("Length"); public bool IsMatch(TypePair context) => context.SourceType == typeof(string) && context.DestinationType.IsEnum; - public Expression MapExpression(IGlobalConfiguration configurationProvider, ProfileMap profileMap, + public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) { var destinationType = destExpression.Type; diff --git a/src/AutoMapper/Mappers/ToDynamicMapper.cs b/src/AutoMapper/Mappers/ToDynamicMapper.cs index 16122923e3..fdef4e014b 100644 --- a/src/AutoMapper/Mappers/ToDynamicMapper.cs +++ b/src/AutoMapper/Mappers/ToDynamicMapper.cs @@ -43,7 +43,7 @@ private static void SetDynamically(string memberName, object target, object valu callsite.Target(callsite, target, value); } public bool IsMatch(TypePair context) => context.DestinationType.IsDynamic() && !context.SourceType.IsDynamic(); - public Expression MapExpression(IGlobalConfiguration configurationProvider, ProfileMap profileMap, + public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) => Call(MapMethodInfo, sourceExpression.ToObject(), destExpression, Constant(destExpression.Type), ContextParameter, Constant(profileMap)); } diff --git a/src/AutoMapper/Mappers/ToStringDictionaryMapper.cs b/src/AutoMapper/Mappers/ToStringDictionaryMapper.cs index c8ee4f69ea..5a17dd2f4a 100644 --- a/src/AutoMapper/Mappers/ToStringDictionaryMapper.cs +++ b/src/AutoMapper/Mappers/ToStringDictionaryMapper.cs @@ -10,7 +10,7 @@ public class ToStringDictionaryMapper : IObjectMapper { private static readonly MethodInfo MembersDictionaryMethodInfo = typeof(ToStringDictionaryMapper).GetStaticMethod(nameof(MembersDictionary)); public bool IsMatch(TypePair context) => typeof(IDictionary).IsAssignableFrom(context.DestinationType); - public Expression MapExpression(IGlobalConfiguration configurationProvider, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) => + public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) => Call(MembersDictionaryMethodInfo, sourceExpression.ToObject(), Constant(profileMap)); private static Dictionary MembersDictionary(object source, ProfileMap profileMap) => profileMap.CreateTypeDetails(source.GetType()).ReadAccessors.ToDictionary(p => p.Name, p => p.GetMemberValue(source)); diff --git a/src/AutoMapper/Mappers/ToStringMapper.cs b/src/AutoMapper/Mappers/ToStringMapper.cs index fc6a297976..df430d3c23 100644 --- a/src/AutoMapper/Mappers/ToStringMapper.cs +++ b/src/AutoMapper/Mappers/ToStringMapper.cs @@ -6,7 +6,7 @@ namespace AutoMapper.Internal.Mappers public class ToStringMapper : IObjectMapper { public bool IsMatch(TypePair context) => context.DestinationType == typeof(string); - public Expression MapExpression(IGlobalConfiguration configurationProvider, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) + public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) { var sourceType = sourceExpression.Type; var toStringCall = Call(sourceExpression, ExpressionBuilder.ObjectToString); diff --git a/src/AutoMapper/Mappers/UnderlyingEnumTypeMapper.cs b/src/AutoMapper/Mappers/UnderlyingEnumTypeMapper.cs index 900ae9dfa8..3f4c97b09d 100644 --- a/src/AutoMapper/Mappers/UnderlyingEnumTypeMapper.cs +++ b/src/AutoMapper/Mappers/UnderlyingEnumTypeMapper.cs @@ -4,7 +4,7 @@ namespace AutoMapper.Internal.Mappers public class UnderlyingTypeEnumMapper : IObjectMapper { public bool IsMatch(TypePair context) => context.IsEnumToUnderlyingType() || context.IsUnderlyingTypeToEnum(); - public Expression MapExpression(IGlobalConfiguration configurationProvider, ProfileMap profileMap, + public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) => sourceExpression; } } \ No newline at end of file diff --git a/src/AutoMapper/ProfileMap.cs b/src/AutoMapper/ProfileMap.cs index cb6170c61b..df381903fc 100644 --- a/src/AutoMapper/ProfileMap.cs +++ b/src/AutoMapper/ProfileMap.cs @@ -128,57 +128,57 @@ public TypeDetails CreateTypeDetails(Type type) return typeDetails; } private TypeDetails TypeDetailsFactory(Type type) => new(type, this); - public void Register(IGlobalConfiguration configurationProvider) + public void Register(IGlobalConfiguration configuration) { foreach (var config in _typeMapConfigs) { if (config.DestinationTypeOverride == null) { - BuildTypeMap(configurationProvider, config); + BuildTypeMap(configuration, config); if (config.ReverseTypeMap != null) { - BuildTypeMap(configurationProvider, config.ReverseTypeMap); + BuildTypeMap(configuration, config.ReverseTypeMap); } } } } - private void BuildTypeMap(IGlobalConfiguration configurationProvider, TypeMapConfiguration config) + private void BuildTypeMap(IGlobalConfiguration configuration, TypeMapConfiguration config) { - var sourceMembers = configurationProvider.SourceMembers; + var sourceMembers = configuration.SourceMembers; var typeMap = new TypeMap(config.SourceType, config.DestinationType, this, config, sourceMembers); config.Configure(typeMap, sourceMembers); - configurationProvider.RegisterTypeMap(typeMap); + configuration.RegisterTypeMap(typeMap); } - public void Configure(IGlobalConfiguration configurationProvider) + public void Configure(IGlobalConfiguration configuration) { foreach (var typeMapConfiguration in _typeMapConfigs) { if (typeMapConfiguration.DestinationTypeOverride == null) { - Configure(typeMapConfiguration, configurationProvider); + Configure(typeMapConfiguration, configuration); if (typeMapConfiguration.ReverseTypeMap != null) { - Configure(typeMapConfiguration.ReverseTypeMap, configurationProvider); + Configure(typeMapConfiguration.ReverseTypeMap, configuration); } } else { - configurationProvider.RegisterAsMap(typeMapConfiguration); + configuration.RegisterAsMap(typeMapConfiguration); } } } - private void Configure(TypeMapConfiguration typeMapConfiguration, IGlobalConfiguration configurationProvider) + private void Configure(TypeMapConfiguration typeMapConfiguration, IGlobalConfiguration configuration) { var typeMap = typeMapConfiguration.TypeMap; if (typeMap.IncludeAllDerivedTypes) { - IncludeAllDerived(configurationProvider, typeMap); + IncludeAllDerived(configuration, typeMap); } - Configure(typeMap, configurationProvider); + Configure(typeMap, configuration); } - private static void IncludeAllDerived(IGlobalConfiguration configurationProvider, TypeMap typeMap) + private static void IncludeAllDerived(IGlobalConfiguration configuration, TypeMap typeMap) { - foreach (var derivedMap in configurationProvider.GetAllTypeMaps().Where(tm => + foreach (var derivedMap in configuration.GetAllTypeMaps().Where(tm => typeMap != tm && typeMap.SourceType.IsAssignableFrom(tm.SourceType) && typeMap.DestinationType.IsAssignableFrom(tm.DestinationType))) @@ -186,13 +186,13 @@ private static void IncludeAllDerived(IGlobalConfiguration configurationProvider typeMap.IncludeDerivedTypes(derivedMap.Types); } } - private void Configure(TypeMap typeMap, IGlobalConfiguration configurationProvider) + private void Configure(TypeMap typeMap, IGlobalConfiguration configuration) { foreach (var action in AllTypeMapActions) { var expression = new MappingExpression(typeMap.Types, typeMap.ConfiguredMemberList); action(typeMap, expression); - expression.Configure(typeMap, configurationProvider.SourceMembers); + expression.Configure(typeMap, configuration.SourceMembers); } foreach (var action in AllPropertyMapActions) { @@ -203,33 +203,33 @@ private void Configure(TypeMap typeMap, IGlobalConfiguration configurationProvid memberExpression.Configure(typeMap); } } - ApplyBaseMaps(typeMap, typeMap, configurationProvider); - ApplyDerivedMaps(typeMap, typeMap, configurationProvider); - ApplyMemberMaps(typeMap, configurationProvider); + ApplyBaseMaps(typeMap, typeMap, configuration); + ApplyDerivedMaps(typeMap, typeMap, configuration); + ApplyMemberMaps(typeMap, configuration); } - public TypeMap CreateClosedGenericTypeMap(TypeMapConfiguration openMapConfig, TypePair closedTypes, IGlobalConfiguration configurationProvider) + public TypeMap CreateClosedGenericTypeMap(TypeMapConfiguration openMapConfig, TypePair closedTypes, IGlobalConfiguration configuration) { TypeMap closedMap; - lock (configurationProvider) + lock (configuration) { closedMap = new TypeMap(closedTypes.SourceType, closedTypes.DestinationType, this, openMapConfig); } - openMapConfig.Configure(closedMap, configurationProvider.SourceMembers); - Configure(closedMap, configurationProvider); + openMapConfig.Configure(closedMap, configuration.SourceMembers); + Configure(closedMap, configuration); closedMap.CloseGenerics(openMapConfig, closedTypes); return closedMap; } public TypeMapConfiguration GetGenericMap(TypePair genericPair) => _openTypeMapConfigs.GetValueOrDefault(genericPair); - private void ApplyBaseMaps(TypeMap derivedMap, TypeMap currentMap, IGlobalConfiguration configurationProvider) + private void ApplyBaseMaps(TypeMap derivedMap, TypeMap currentMap, IGlobalConfiguration configuration) { - foreach (var baseMap in configurationProvider.GetIncludedTypeMaps(currentMap.IncludedBaseTypes)) + foreach (var baseMap in configuration.GetIncludedTypeMaps(currentMap.IncludedBaseTypes)) { baseMap.IncludeDerivedTypes(currentMap.Types); derivedMap.AddInheritedMap(baseMap); - ApplyBaseMaps(derivedMap, baseMap, configurationProvider); + ApplyBaseMaps(derivedMap, baseMap, configuration); } } - private void ApplyMemberMaps(TypeMap currentMap, IGlobalConfiguration configurationProvider) + private void ApplyMemberMaps(TypeMap currentMap, IGlobalConfiguration configuration) { if (!currentMap.HasIncludedMembers) { @@ -237,11 +237,11 @@ private void ApplyMemberMaps(TypeMap currentMap, IGlobalConfiguration configurat } foreach (var includedMemberExpression in currentMap.GetAllIncludedMembers()) { - var includedMap = configurationProvider.GetIncludedTypeMap(includedMemberExpression.Body.Type, currentMap.DestinationType); + var includedMap = configuration.GetIncludedTypeMap(includedMemberExpression.Body.Type, currentMap.DestinationType); var includedMember = new IncludedMember(includedMap, includedMemberExpression); if (currentMap.AddMemberMap(includedMember)) { - ApplyMemberMaps(includedMap, configurationProvider); + ApplyMemberMaps(includedMap, configuration); foreach (var inheritedIncludedMember in includedMap.IncludedMembersTypeMaps) { currentMap.AddMemberMap(includedMember.Chain(inheritedIncludedMember)); @@ -249,13 +249,13 @@ private void ApplyMemberMaps(TypeMap currentMap, IGlobalConfiguration configurat } } } - private void ApplyDerivedMaps(TypeMap baseMap, TypeMap typeMap, IGlobalConfiguration configurationProvider) + private void ApplyDerivedMaps(TypeMap baseMap, TypeMap typeMap, IGlobalConfiguration configuration) { - foreach (var derivedMap in configurationProvider.GetIncludedTypeMaps(typeMap)) + foreach (var derivedMap in configuration.GetIncludedTypeMaps(typeMap)) { derivedMap.IncludeBaseTypes(typeMap.Types); derivedMap.AddInheritedMap(baseMap); - ApplyDerivedMaps(baseMap, derivedMap, configurationProvider); + ApplyDerivedMaps(baseMap, derivedMap, configuration); } } public bool MapDestinationPropertyToSource(TypeDetails sourceTypeDetails, Type destType, Type destMemberType, string destMemberName, List members, bool reverseNamingConventions) diff --git a/src/AutoMapper/QueryableExtensions/ProjectionBuilder.cs b/src/AutoMapper/QueryableExtensions/ProjectionBuilder.cs index 4be7489804..800d29fea2 100644 --- a/src/AutoMapper/QueryableExtensions/ProjectionBuilder.cs +++ b/src/AutoMapper/QueryableExtensions/ProjectionBuilder.cs @@ -39,11 +39,11 @@ internal static List DefaultProjectionMappers() => new EnumProjectionMapper(), }; private readonly LockingConcurrentDictionary _projectionCache; - private readonly IGlobalConfiguration _configurationProvider; + private readonly IGlobalConfiguration _configuration; private readonly IProjectionMapper[] _projectionMappers; - public ProjectionBuilder(IGlobalConfiguration configurationProvider, IProjectionMapper[] projectionMappers) + public ProjectionBuilder(IGlobalConfiguration configuration, IProjectionMapper[] projectionMappers) { - _configurationProvider = configurationProvider; + _configuration = configuration; _projectionMappers = projectionMappers; _projectionCache = new(CreateProjection); } @@ -51,18 +51,18 @@ public QueryExpressions GetProjection(Type sourceType, Type destinationType, obj { var projectionRequest = new ProjectionRequest(sourceType, destinationType, membersToExpand, Array.Empty()); var cachedExpressions = _projectionCache.GetOrAdd(projectionRequest); - if (parameters == null && !_configurationProvider.EnableNullPropagationForQueryMapping) + if (parameters == null && !_configuration.EnableNullPropagationForQueryMapping) { return cachedExpressions; } - return cachedExpressions.Prepare(_configurationProvider.EnableNullPropagationForQueryMapping, parameters); + return cachedExpressions.Prepare(_configuration.EnableNullPropagationForQueryMapping, parameters); } private QueryExpressions CreateProjection(ProjectionRequest request) => - CreateProjection(request, new FirstPassLetPropertyMaps(_configurationProvider, MemberPath.Empty, new())); + CreateProjection(request, new FirstPassLetPropertyMaps(_configuration, MemberPath.Empty, new())); public QueryExpressions CreateProjection(in ProjectionRequest request, LetPropertyMaps letPropertyMaps) { var instanceParameter = Parameter(request.SourceType, "dto"+ request.SourceType.Name); - var typeMap = _configurationProvider.ResolveTypeMap(request.SourceType, request.DestinationType) ?? throw TypeMap.MissingMapException(request.SourceType, request.DestinationType); + var typeMap = _configuration.ResolveTypeMap(request.SourceType, request.DestinationType) ?? throw TypeMap.MissingMapException(request.SourceType, request.DestinationType); var projection = CreateProjectionCore(request, instanceParameter, typeMap, letPropertyMaps); return letPropertyMaps.Count > 0 ? letPropertyMaps.GetSubQueryExpression(this, projection, typeMap, request, instanceParameter) : @@ -119,11 +119,11 @@ Expression TryProjectMember(MemberMap memberMap, bool? explicitExpansion = null, bool ShouldExpand() => explicitExpansion != true || request.ShouldExpand(letPropertyMaps.GetCurrentPath()); Expression ProjectMemberCore() { - var memberTypeMap = _configurationProvider.ResolveTypeMap(memberMap.SourceType, memberMap.DestinationType); + var memberTypeMap = _configuration.ResolveTypeMap(memberMap.SourceType, memberMap.DestinationType); var resolvedSource = ResolveSource(); memberProjection.Expression ??= resolvedSource; var memberRequest = request.InnerRequest(resolvedSource.Type, memberMap.DestinationType); - if (memberRequest.AlreadyExists && depth >= _configurationProvider.RecursiveQueriesMaxDepth) + if (memberRequest.AlreadyExists && depth >= _configuration.RecursiveQueriesMaxDepth) { return null; } @@ -141,7 +141,7 @@ Expression ProjectMemberCore() else { var projectionMapper = GetProjectionMapper(); - mappedExpression = projectionMapper.Project(_configurationProvider, memberRequest, resolvedSource, letPropertyMaps); + mappedExpression = projectionMapper.Project(_configuration, memberRequest, resolvedSource, letPropertyMaps); } return mappedExpression == null ? null : memberMap.ApplyTransformers(mappedExpression); Expression ResolveSource() @@ -214,7 +214,7 @@ class FirstPassLetPropertyMaps : LetPropertyMaps readonly Stack _currentPath = new(); readonly List _savedPaths = new(); readonly MemberPath _parentPath; - public FirstPassLetPropertyMaps(IGlobalConfiguration configurationProvider, MemberPath parentPath, TypePairCount builtProjections) : base(configurationProvider, builtProjections) + public FirstPassLetPropertyMaps(IGlobalConfiguration configuration, MemberPath parentPath, TypePairCount builtProjections) : base(configuration, builtProjections) => _parentPath = parentPath; public override Expression GetSubQueryMarker(LambdaExpression letExpression) { @@ -232,7 +232,7 @@ public override MemberPath GetCurrentPath() => _parentPath.Concat( _currentPath.Reverse().Select(p => (p.MemberMap as PropertyMap)?.DestinationMember).Where(p => p != null)); public override void Pop() => _currentPath.Pop(); public override int Count => _savedPaths.Count; - public override LetPropertyMaps New() => new FirstPassLetPropertyMaps(ConfigurationProvider, GetCurrentPath(), BuiltProjections); + public override LetPropertyMaps New() => new FirstPassLetPropertyMaps(Configuration, GetCurrentPath(), BuiltProjections); public override QueryExpressions GetSubQueryExpression(ProjectionBuilder builder, Expression projection, TypeMap typeMap, in ProjectionRequest request, ParameterExpression instanceParameter) { var letMapInfos = _savedPaths.Select(path => @@ -243,7 +243,7 @@ public override QueryExpressions GetSubQueryExpression(ProjectionBuilder builder var properties = letMapInfos.Select(m => m.Property).Concat(GePropertiesVisitor.Retrieve(projection, instanceParameter)); var letType = ProxyGenerator.GetSimilarType(typeof(object), properties); TypeMap letTypeMap; - lock(ConfigurationProvider) + lock(Configuration) { letTypeMap = new(request.SourceType, letType, typeMap.Profile); } @@ -333,9 +333,9 @@ protected override Expression VisitMember(MemberExpression node) [EditorBrowsable(EditorBrowsableState.Never)] public class LetPropertyMaps { - protected LetPropertyMaps(IGlobalConfiguration configurationProvider, TypePairCount builtProjections) + protected LetPropertyMaps(IGlobalConfiguration configuration, TypePairCount builtProjections) { - ConfigurationProvider = configurationProvider; + Configuration = configuration; BuiltProjections = builtProjections; } protected TypePairCount BuiltProjections { get; } @@ -353,8 +353,8 @@ public virtual void Push(MemberProjection memberProjection) { } public virtual MemberPath GetCurrentPath() => MemberPath.Empty; public virtual void Pop() {} public virtual int Count => 0; - public IGlobalConfiguration ConfigurationProvider { get; } - public virtual LetPropertyMaps New() => new(ConfigurationProvider, BuiltProjections); + public IGlobalConfiguration Configuration { get; } + public virtual LetPropertyMaps New() => new(Configuration, BuiltProjections); public virtual QueryExpressions GetSubQueryExpression(ProjectionBuilder builder, Expression projection, TypeMap typeMap, in ProjectionRequest request, ParameterExpression instanceParameter) => default; } diff --git a/src/AutoMapper/TypeMap.cs b/src/AutoMapper/TypeMap.cs index 8d7192c157..a831e0575c 100644 --- a/src/AutoMapper/TypeMap.cs +++ b/src/AutoMapper/TypeMap.cs @@ -202,17 +202,17 @@ internal void IgnorePaths(MemberInfo destinationMember) } } public bool HasDerivedTypesToInclude => IncludedDerivedTypes.Count > 0; - public void Seal(IGlobalConfiguration configurationProvider) + public void Seal(IGlobalConfiguration configuration) { if (_sealed) { return; } _sealed = true; - _details?.Seal(configurationProvider, this); + _details?.Seal(configuration, this); if (!Projection) { - MapExpression = CreateMapperLambda(configurationProvider); + MapExpression = CreateMapperLambda(configuration); } SourceTypeDetails = null; DestinationTypeDetails = null; @@ -257,8 +257,8 @@ public void IncludeBaseTypes(TypePair baseTypes) public void AddAfterMapAction(LambdaExpression afterMap) => Details.AddAfterMapAction(afterMap); public void AddValueTransformation(ValueTransformerConfiguration config) => Details.AddValueTransformation(config); public void ConstructUsingServiceLocator() => CustomCtorFunction = Lambda(ServiceLocator(DestinationType)); - internal LambdaExpression CreateMapperLambda(IGlobalConfiguration configurationProvider) => - Types.IsGenericTypeDefinition ? null : new TypeMapPlanBuilder(configurationProvider, this).CreateMapperLambda(); + internal LambdaExpression CreateMapperLambda(IGlobalConfiguration configuration) => + Types.IsGenericTypeDefinition ? null : new TypeMapPlanBuilder(configuration, this).CreateMapperLambda(); private PropertyMap GetPropertyMap(string name) => _propertyMaps?.GetValueOrDefault(name); private PropertyMap GetPropertyMap(PropertyMap propertyMap) => GetPropertyMap(propertyMap.DestinationName); public void AsProxy() => CustomCtorFunction = Lambda(Call(CreateProxyMethod, Constant(DestinationType))); @@ -297,7 +297,7 @@ class TypeMapDetails public HashSet IncludedMembersTypeMaps { get; private set; } public List ValueTransformerConfigs { get; private set; } public Features Features => _features ??= new(); - public void Seal(IGlobalConfiguration configurationProvider, TypeMap thisMap) + public void Seal(IGlobalConfiguration configuration, TypeMap thisMap) { if (InheritedTypeMaps != null) { @@ -315,7 +315,7 @@ public void Seal(IGlobalConfiguration configurationProvider, TypeMap thisMap) { foreach (var includedMemberTypeMap in IncludedMembersTypeMaps) { - includedMemberTypeMap.TypeMap.Seal(configurationProvider); + includedMemberTypeMap.TypeMap.Seal(configuration); ApplyIncludedMemberTypeMap(includedMemberTypeMap, thisMap); } } @@ -326,7 +326,7 @@ public void Seal(IGlobalConfiguration configurationProvider, TypeMap thisMap) ApplyInheritedTypeMap(inheritedTypeMap, thisMap); } } - _features?.Seal(configurationProvider); + _features?.Seal(configuration); } public void IncludeDerivedTypes(TypePair derivedTypes) { From b24560febbcbd69131f86e7a552370023b0ec202 Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Wed, 17 Aug 2022 12:13:52 +0300 Subject: [PATCH 29/67] less allocations --- src/AutoMapper/Execution/ExpressionBuilder.cs | 41 +++++++++---------- .../Execution/TypeMapPlanBuilder.cs | 28 +++++++------ src/AutoMapper/Mappers/MapperRegistry.cs | 2 +- src/AutoMapper/MemberMap.cs | 8 ++-- .../QueryableExtensions/ProjectionBuilder.cs | 2 +- src/Benchmark/FlatteningMapper.cs | 2 +- .../IMappingExpression/IncludeMembers.cs | 4 +- 7 files changed, 45 insertions(+), 42 deletions(-) diff --git a/src/AutoMapper/Execution/ExpressionBuilder.cs b/src/AutoMapper/Execution/ExpressionBuilder.cs index f3dd3b0839..3f8eed3158 100644 --- a/src/AutoMapper/Execution/ExpressionBuilder.cs +++ b/src/AutoMapper/Execution/ExpressionBuilder.cs @@ -366,10 +366,10 @@ private static Expression Replace(this ParameterReplaceVisitor visitor, LambdaEx return newLambda; } public static Expression Replace(this Expression exp, Expression old, Expression replace) => new ReplaceVisitor().Replace(exp, old, replace); - public static Expression NullCheck(this Expression expression, MemberMap memberMap = null, Expression defaultValue = null) + public static Expression NullCheck(this Expression expression, IGlobalConfiguration configuration, MemberMap memberMap = null, Expression defaultValue = null) { var chain = expression.GetChain(); - var min = memberMap?.IncludedMember != null ? 1 : 2; + var min = memberMap?.IncludedMember == null ? 2 : 1; if (chain.Count < min || chain.Peek().Target is not ParameterExpression parameter) { return expression; @@ -378,36 +378,35 @@ public static Expression NullCheck(this Expression expression, MemberMap memberM var returnType = (destinationType != null && destinationType != expression.Type && Nullable.GetUnderlyingType(destinationType) == expression.Type) ? destinationType : expression.Type; var defaultReturn = (defaultValue is { NodeType: ExpressionType.Default } && defaultValue.Type == returnType) ? defaultValue : Default(returnType); - ParameterExpression[] variables = null; - Expression begin; - string name; - if (min == 1) - { - begin = parameter; - name = parameter.Name; - } - else + List variables = null; + List expressions = null; + var name = parameter.Name; + var nullCheckedExpression = NullCheck(parameter); + if (variables == null) { - var second = chain.Pop(); - begin = second.Expression; - name = parameter.Name + second.MemberInfo.Name; + return nullCheckedExpression; } - int index = 0; - var nullCheckedExpression = NullCheck(begin); - return variables == null ? nullCheckedExpression : Block(variables, nullCheckedExpression); + expressions.Add(nullCheckedExpression); + return Block(variables, expressions); Expression NullCheck(Expression variable) { var member = chain.Pop(); + var skipNullCheck = min == 2 && variable == parameter; if (chain.Count == 0) { - return variable.IfNullElse(defaultReturn, UpdateTarget(expression, variable)); + var updated = UpdateTarget(expression, variable); + return skipNullCheck ? updated : variable.IfNullElse(defaultReturn, updated); + } + if (variables == null) + { + (variables, expressions) = configuration.ScratchPad(); } - variables ??= new ParameterExpression[chain.Count]; name += member.MemberInfo.Name; var newVariable = Variable(member.Expression.Type, name); - variables[index++] = newVariable; + variables.Add(newVariable); var assignment = Assign(newVariable, UpdateTarget(member.Expression, variable)); - return variable.IfNullElse(defaultReturn, Block(assignment, NullCheck(newVariable))); + var block = Block(assignment, NullCheck(newVariable)); + return skipNullCheck ? block : variable.IfNullElse(defaultReturn, block); } static Expression UpdateTarget(Expression sourceExpression, Expression newTarget) => sourceExpression switch { diff --git a/src/AutoMapper/Execution/TypeMapPlanBuilder.cs b/src/AutoMapper/Execution/TypeMapPlanBuilder.cs index cb36f77538..4d17e447f0 100644 --- a/src/AutoMapper/Execution/TypeMapPlanBuilder.cs +++ b/src/AutoMapper/Execution/TypeMapPlanBuilder.cs @@ -86,10 +86,14 @@ static void Clear(ref HashSet typeMapsPath) } void IncludeMembers() { - var source = Source; - _variables.AddRange(_typeMap.IncludedMembersTypeMaps.Select(i => i.Variable)); - _expressions.AddRange(_variables.Zip(_typeMap.IncludedMembersTypeMaps, (v, i) => - Assign(v, i.MemberExpression.ReplaceParameters(source).NullCheck()))); + var thisVar = this; + var includeVariables = _typeMap.IncludedMembersTypeMaps.Select(i => i.Variable).ToArray(); + var assignVariables = includeVariables.Zip(_typeMap.IncludedMembersTypeMaps, (v, i) => + Assign(v, i.MemberExpression.ReplaceParameters(thisVar.Source).NullCheck(thisVar._configuration))).ToArray(); + _expressions.Clear(); + _expressions.AddRange(assignVariables); + _variables.Clear(); + _variables.AddRange(includeVariables); } private static void CheckForCycles(IGlobalConfiguration configuration, TypeMap typeMap, HashSet typeMapsPath) { @@ -384,7 +388,7 @@ Expression MapMember(MemberMap memberMap, Expression destinationMemberValue, Par } private Expression BuildValueResolverFunc(MemberMap memberMap, Expression customSource, Expression destValueExpr) { - var valueResolverFunc = memberMap.Resolver?.GetExpression(memberMap, customSource, _destination, destValueExpr) ?? destValueExpr; + var valueResolverFunc = memberMap.Resolver?.GetExpression(_configuration, memberMap, customSource, _destination, destValueExpr) ?? destValueExpr; if (memberMap.NullSubstitute != null) { valueResolverFunc = memberMap.NullSubstitute(valueResolverFunc); @@ -403,7 +407,7 @@ private Expression BuildValueResolverFunc(MemberMap memberMap, Expression custom } public interface IValueResolver { - Expression GetExpression(MemberMap memberMap, Expression source, Expression destination, Expression destinationMember); + Expression GetExpression(IGlobalConfiguration configuration, MemberMap memberMap, Expression source, Expression destination, Expression destinationMember); MemberInfo GetSourceMember(MemberMap memberMap); Type ResolvedType { get; } string SourceMemberName => null; @@ -418,17 +422,17 @@ public abstract class LambdaValueResolver public class FuncResolver : LambdaValueResolver, IValueResolver { public FuncResolver(LambdaExpression lambda) : base(lambda) { } - public Expression GetExpression(MemberMap memberMap, Expression source, Expression destination, Expression destinationMember) => + public Expression GetExpression(IGlobalConfiguration configuration, MemberMap memberMap, Expression source, Expression destination, Expression destinationMember) => Lambda.ConvertReplaceParameters(new[] { source, destination, destinationMember, ContextParameter }); public MemberInfo GetSourceMember(MemberMap _) => null; } public class ExpressionResolver : LambdaValueResolver, IValueResolver { public ExpressionResolver(LambdaExpression lambda) : base(lambda) { } - public Expression GetExpression(MemberMap memberMap, Expression source, Expression _, Expression destinationMember) + public Expression GetExpression(IGlobalConfiguration configuration, MemberMap memberMap, Expression source, Expression _, Expression destinationMember) { var mapFrom = Lambda.ReplaceParameters(source); - var nullCheckedExpression = mapFrom.NullCheck(memberMap, destinationMember); + var nullCheckedExpression = mapFrom.NullCheck(configuration, memberMap, destinationMember); if (nullCheckedExpression != mapFrom) { return nullCheckedExpression; @@ -462,13 +466,13 @@ public class ValueConverter : ValueResolverConfig, IValueResolver { public ValueConverter(Type concreteType, Type interfaceType) : base(concreteType, interfaceType) => _instance = ServiceLocator(concreteType); public ValueConverter(object instance, Type interfaceType) : base(instance, interfaceType) { } - public Expression GetExpression(MemberMap memberMap, Expression source, Expression _, Expression destinationMember) + public Expression GetExpression(IGlobalConfiguration configuration, MemberMap memberMap, Expression source, Expression _, Expression destinationMember) { var iResolverTypeArgs = InterfaceType.GenericTypeArguments; var sourceMember = SourceMemberLambda?.ReplaceParameters(source) ?? (SourceMemberName != null ? PropertyOrField(source, SourceMemberName) : - memberMap.ChainSourceMembers(source, destinationMember) ?? Throw(Constant(BuildExceptionMessage()), iResolverTypeArgs[0])); + memberMap.ChainSourceMembers(configuration, source, destinationMember) ?? Throw(Constant(BuildExceptionMessage()), iResolverTypeArgs[0])); return Call(ToType(_instance, InterfaceType), "Convert", ToType(sourceMember, iResolverTypeArgs[0]), ContextParameter); AutoMapperConfigurationException BuildExceptionMessage() => new($"Cannot find a source member to pass to the value converter of type {ConcreteType}. Configure a source member to map from."); @@ -484,7 +488,7 @@ public class ClassValueResolver : ValueResolverConfig, IValueResolver { public ClassValueResolver(Type concreteType, Type interfaceType) : base(concreteType, interfaceType) { } public ClassValueResolver(object instance, Type interfaceType) : base(instance, interfaceType) { } - public Expression GetExpression(MemberMap memberMap, Expression source, Expression destination, Expression destinationMember) + public Expression GetExpression(IGlobalConfiguration configuration, MemberMap memberMap, Expression source, Expression destination, Expression destinationMember) { var typeMap = memberMap.TypeMap; var resolverInstance = _instance ?? ServiceLocator(typeMap.MakeGenericType(ConcreteType)); diff --git a/src/AutoMapper/Mappers/MapperRegistry.cs b/src/AutoMapper/Mappers/MapperRegistry.cs index 5161eec4d1..b7c5bb57f0 100644 --- a/src/AutoMapper/Mappers/MapperRegistry.cs +++ b/src/AutoMapper/Mappers/MapperRegistry.cs @@ -3,7 +3,7 @@ namespace AutoMapper.Internal.Mappers { internal static class MapperRegistry { - public static List Mappers() => new() + public static List Mappers() => new(capacity: 18) { new CollectionMapper(),// matches IEnumerable, requires a setter, ICollection<> or IList new AssignableMapper(),// except collections, which are copied; most likely match diff --git a/src/AutoMapper/MemberMap.cs b/src/AutoMapper/MemberMap.cs index 88d08b12af..1ddb309146 100644 --- a/src/AutoMapper/MemberMap.cs +++ b/src/AutoMapper/MemberMap.cs @@ -59,8 +59,8 @@ public void MapFrom(string sourceMembersPath) } public override string ToString() => DestinationName; public Expression ChainSourceMembers(Expression source) => SourceMembers.Chain(source); - public Expression ChainSourceMembers(Expression source, Expression defaultValue) => - ChainSourceMembers(source)?.NullCheck(this, defaultValue); + public Expression ChainSourceMembers(IGlobalConfiguration configuration, Expression source, Expression defaultValue) => + ChainSourceMembers(source)?.NullCheck(configuration, this, defaultValue); public bool AllowsNullDestinationValues => Profile?.AllowsNullDestinationValuesFor(this) ?? true; public bool AllowsNullCollections => (Profile?.AllowsNullCollectionsFor(this)).GetValueOrDefault(); public ProfileMap Profile => TypeMap?.Profile; @@ -75,8 +75,8 @@ public void MapByConvention(MemberInfo[] sourceMembers) SourceMembers = sourceMembers; Resolver = this; } - Expression IValueResolver.GetExpression(MemberMap memberMap, Expression source, Expression destination, Expression destinationMember) => - ChainSourceMembers(source, destinationMember); + Expression IValueResolver.GetExpression(IGlobalConfiguration configuration, MemberMap memberMap, Expression source, Expression destination, Expression destinationMember) => + ChainSourceMembers(configuration, source, destinationMember); MemberInfo IValueResolver.GetSourceMember(MemberMap memberMap) => SourceMembers[0]; Type IValueResolver.ResolvedType => SourceMembers[^1].GetMemberType(); } diff --git a/src/AutoMapper/QueryableExtensions/ProjectionBuilder.cs b/src/AutoMapper/QueryableExtensions/ProjectionBuilder.cs index 800d29fea2..6c30349577 100644 --- a/src/AutoMapper/QueryableExtensions/ProjectionBuilder.cs +++ b/src/AutoMapper/QueryableExtensions/ProjectionBuilder.cs @@ -30,7 +30,7 @@ public interface IProjectionMapper public class ProjectionBuilder : IProjectionBuilder { internal static List DefaultProjectionMappers() => - new() + new(capacity: 5) { new AssignableProjectionMapper(), new EnumerableProjectionMapper(), diff --git a/src/Benchmark/FlatteningMapper.cs b/src/Benchmark/FlatteningMapper.cs index 04c154068b..e40d9c4d69 100644 --- a/src/Benchmark/FlatteningMapper.cs +++ b/src/Benchmark/FlatteningMapper.cs @@ -394,6 +394,7 @@ public void Initialize() { var config = new MapperConfiguration(cfg => { + cfg.CreateMap(); cfg.CreateMap(); cfg.CreateMap(); cfg.CreateMap(); @@ -404,7 +405,6 @@ public void Initialize() cfg.CreateMap(); cfg.CreateMap(); cfg.CreateMap(); - cfg.CreateMap(); }); //config.AssertConfigurationIsValid(); _mapper = config.CreateMapper(); diff --git a/src/UnitTests/IMappingExpression/IncludeMembers.cs b/src/UnitTests/IMappingExpression/IncludeMembers.cs index b870a141c4..0fe26b2a72 100644 --- a/src/UnitTests/IMappingExpression/IncludeMembers.cs +++ b/src/UnitTests/IMappingExpression/IncludeMembers.cs @@ -96,10 +96,10 @@ class Destination cfg.CreateMap(MemberList.None); }); [Fact] - public static void Should_null_check() + public void Should_null_check() { Expression> expression = s => s.InnerSources.FirstOrDefault().InnerSource; - var result= expression.Body.NullCheck(); + var result= expression.Body.NullCheck(Configuration); } [Fact] public void Should_flatten() From 953d66da44f53062f55d08cbfde74339a92fdad4 Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Wed, 17 Aug 2022 19:04:41 +0300 Subject: [PATCH 30/67] converters with no source should throw --- src/AutoMapper/Execution/ExpressionBuilder.cs | 3 ++- .../Execution/TypeMapPlanBuilder.cs | 15 ++++++++------ src/AutoMapper/MemberMap.cs | 2 +- src/UnitTests/ValueConverters.cs | 20 +++++++++++++++++++ 4 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/AutoMapper/Execution/ExpressionBuilder.cs b/src/AutoMapper/Execution/ExpressionBuilder.cs index 3f8eed3158..2f7e2fc66f 100644 --- a/src/AutoMapper/Execution/ExpressionBuilder.cs +++ b/src/AutoMapper/Execution/ExpressionBuilder.cs @@ -342,7 +342,8 @@ static Expression Using(List statements, Expression target, Expressi public static MemberExpression Property(Expression target, string name) => Expression.Property(target, target.Type.GetInheritedProperty(name)); // Expression.Call(string) is inefficient because it does a case insensitive match - public static MethodCallExpression Call(Expression target, string name, params Expression[] arguments) => + public static MethodCallExpression Call(Expression target, string name) => Expression.Call(target, target.Type.GetInheritedMethod(name)); + public static MethodCallExpression Call(Expression target, string name, Expression[] arguments) => Expression.Call(target, target.Type.GetInheritedMethod(name), arguments); public static Expression ToObject(this Expression expression) => expression.Type.IsValueType ? Convert(expression, typeof(object)) : expression; public static Expression ToType(Expression expression, Type type) => expression.Type == type ? expression : Convert(expression, type); diff --git a/src/AutoMapper/Execution/TypeMapPlanBuilder.cs b/src/AutoMapper/Execution/TypeMapPlanBuilder.cs index 4d17e447f0..efa7ab8134 100644 --- a/src/AutoMapper/Execution/TypeMapPlanBuilder.cs +++ b/src/AutoMapper/Execution/TypeMapPlanBuilder.cs @@ -468,12 +468,15 @@ public class ValueConverter : ValueResolverConfig, IValueResolver public ValueConverter(object instance, Type interfaceType) : base(instance, interfaceType) { } public Expression GetExpression(IGlobalConfiguration configuration, MemberMap memberMap, Expression source, Expression _, Expression destinationMember) { - var iResolverTypeArgs = InterfaceType.GenericTypeArguments; - var sourceMember = SourceMemberLambda?.ReplaceParameters(source) ?? - (SourceMemberName != null ? - PropertyOrField(source, SourceMemberName) : - memberMap.ChainSourceMembers(configuration, source, destinationMember) ?? Throw(Constant(BuildExceptionMessage()), iResolverTypeArgs[0])); - return Call(ToType(_instance, InterfaceType), "Convert", ToType(sourceMember, iResolverTypeArgs[0]), ContextParameter); + var sourceMemberType = InterfaceType.GenericTypeArguments[0]; + var sourceMember = this switch + { + { SourceMemberLambda: { } } => SourceMemberLambda.ReplaceParameters(source), + { SourceMemberName: { } } => PropertyOrField(source, SourceMemberName), + _ when memberMap.SourceMembers.Length > 0 => memberMap.ChainSourceMembers(configuration, source, destinationMember), + _ => Throw(Constant(BuildExceptionMessage()), sourceMemberType) + }; + return Call(ToType(_instance, InterfaceType), InterfaceType.GetMethod("Convert"), ToType(sourceMember, sourceMemberType), ContextParameter); AutoMapperConfigurationException BuildExceptionMessage() => new($"Cannot find a source member to pass to the value converter of type {ConcreteType}. Configure a source member to map from."); } diff --git a/src/AutoMapper/MemberMap.cs b/src/AutoMapper/MemberMap.cs index 1ddb309146..5435a43da3 100644 --- a/src/AutoMapper/MemberMap.cs +++ b/src/AutoMapper/MemberMap.cs @@ -60,7 +60,7 @@ public void MapFrom(string sourceMembersPath) public override string ToString() => DestinationName; public Expression ChainSourceMembers(Expression source) => SourceMembers.Chain(source); public Expression ChainSourceMembers(IGlobalConfiguration configuration, Expression source, Expression defaultValue) => - ChainSourceMembers(source)?.NullCheck(configuration, this, defaultValue); + ChainSourceMembers(source).NullCheck(configuration, this, defaultValue); public bool AllowsNullDestinationValues => Profile?.AllowsNullDestinationValuesFor(this) ?? true; public bool AllowsNullCollections => (Profile?.AllowsNullCollectionsFor(this)).GetValueOrDefault(); public ProfileMap Profile => TypeMap?.Profile; diff --git a/src/UnitTests/ValueConverters.cs b/src/UnitTests/ValueConverters.cs index 0bdc703448..3bac752446 100644 --- a/src/UnitTests/ValueConverters.cs +++ b/src/UnitTests/ValueConverters.cs @@ -1,4 +1,5 @@ using Shouldly; +using System; using Xunit; namespace AutoMapper.UnitTests @@ -120,6 +121,25 @@ public void Should_apply_converters() dest.ValueFoo4.ShouldBe("0004"); } } + public class When_specifying_value_converter_with_no_source : AutoMapperSpecBase + { + public class EightDigitIntToStringConverter : IValueConverter + { + public string Convert(int sourceMember, ResolutionContext context) => sourceMember.ToString("d8"); + } + public class Source + { + } + public class Dest + { + public string ValueFoo1 { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.CreateMap() + .ForMember(d => d.ValueFoo1, opt => opt.ConvertUsing())); + [Fact] + public void Should_report_error() => new Action(()=>Map(new Source())).ShouldThrow().InnerException.Message.ShouldBe( + "Cannot find a source member to pass to the value converter of type AutoMapper.UnitTests.ValueConverters+When_specifying_value_converter_with_no_source+EightDigitIntToStringConverter. Configure a source member to map from."); + } public class When_specifying_value_converter_for_string_based_matching_member : AutoMapperSpecBase { From ebd2c434a71dd424e979dd64a25b5d168d8d076d Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Thu, 18 Aug 2022 07:09:49 +0300 Subject: [PATCH 31/67] less allocations --- .../Configuration/MapperConfiguration.cs | 19 +- .../Configuration/TypeMapConfiguration.cs | 17 +- src/AutoMapper/ConstructorMap.cs | 3 +- src/AutoMapper/Execution/ExpressionBuilder.cs | 14 +- src/AutoMapper/Execution/ObjectFactory.cs | 12 +- .../Execution/TypeMapPlanBuilder.cs | 48 ++-- src/AutoMapper/Internal/InternalApi.cs | 1 + src/AutoMapper/Internal/ReflectionHelper.cs | 4 +- src/AutoMapper/Internal/TypeDetails.cs | 32 ++- src/AutoMapper/Mappers/CollectionMapper.cs | 5 +- src/AutoMapper/Mappers/StringToEnumMapper.cs | 2 +- .../QueryableExtensions/ProjectionBuilder.cs | 4 +- src/AutoMapper/TypeMap.cs | 2 +- src/Benchmark/BenchEngine.cs | 2 +- src/Benchmark/FlatteningMapper.cs | 241 ++++++------------ .../IMappingExpression/IncludeMembers.cs | 2 +- src/UnitTests/Internal/TypeMapFactorySpecs.cs | 2 +- 17 files changed, 173 insertions(+), 237 deletions(-) diff --git a/src/AutoMapper/Configuration/MapperConfiguration.cs b/src/AutoMapper/Configuration/MapperConfiguration.cs index 24413e290a..eaf874f00d 100644 --- a/src/AutoMapper/Configuration/MapperConfiguration.cs +++ b/src/AutoMapper/Configuration/MapperConfiguration.cs @@ -3,7 +3,6 @@ using System.Linq; using System.Linq.Expressions; using System.Reflection; -using System.Security.Cryptography; using AutoMapper.Configuration; using AutoMapper.Features; using AutoMapper.Internal; @@ -68,6 +67,7 @@ public class MapperConfiguration : IGlobalConfiguration private readonly ParameterExpression[] _parameters = new ParameterExpression[] { null, null, ContextParameter }; private readonly CatchBlock[] _catches = new CatchBlock[1]; private readonly List _expressions = new(); + private readonly Dictionary _defaults; public MapperConfiguration(MapperConfigurationExpression configurationExpression) { var configuration = (IGlobalConfigurationExpression)configurationExpression; @@ -98,6 +98,7 @@ public MapperConfiguration(MapperConfigurationExpression configurationExpression typeMapsCount += profileMap.TypeMapsCount; openTypeMapsCount += profileMap.OpenTypeMapsCount; } + _defaults = new(3 * typeMapsCount); _configuredMaps = new(typeMapsCount); _hasOpenMaps = openTypeMapsCount > 0; _runtimeMaps = new(GetTypeMap, openTypeMapsCount); @@ -110,12 +111,15 @@ public MapperConfiguration(MapperConfigurationExpression configurationExpression { profile.Clear(); } + _configuredMaps.TrimExcess(); + _resolvedMaps.TrimExcess(); _typeMapsPath = null; _sourceMembers = null; _expressions = null; _variables = null; _parameters = null; _catches = null; + _defaults = null; _sealed = true; return; void Seal() @@ -259,6 +263,19 @@ static MapperConfigurationExpression Build(Action IGlobalConfiguration.TypeMapsPath => _typeMapsPath; ParameterExpression[] IGlobalConfiguration.Parameters => _parameters; CatchBlock[] IGlobalConfiguration.Catches => _catches; + DefaultExpression IGlobalConfiguration.GetDefault(Type type) + { + if (_defaults == null) + { + return Default(type); + } + if (!_defaults.TryGetValue(type, out var defaultExpression)) + { + defaultExpression = Default(type); + _defaults.Add(type, defaultExpression); + } + return defaultExpression; + } Func IGlobalConfiguration.GetExecutionPlan(in MapRequest mapRequest) => (Func)GetExecutionPlan(mapRequest); private Delegate GetExecutionPlan(in MapRequest mapRequest) => _executionPlans.GetOrAdd(mapRequest); diff --git a/src/AutoMapper/Configuration/TypeMapConfiguration.cs b/src/AutoMapper/Configuration/TypeMapConfiguration.cs index 0f24ed674e..ff4d8cb3ca 100644 --- a/src/AutoMapper/Configuration/TypeMapConfiguration.cs +++ b/src/AutoMapper/Configuration/TypeMapConfiguration.cs @@ -216,8 +216,21 @@ protected void IncludeBaseCore(Type sourceBase, Type destinationBase) _types.CheckIsDerivedFrom(baseTypes); TypeMapActions.Add(tm => tm.IncludeBaseTypes(baseTypes)); } - public IPropertyMapConfiguration GetDestinationMemberConfiguration(MemberInfo destinationMember) => - _memberConfigurations?.Find(m => m.DestinationMember == destinationMember); + public IPropertyMapConfiguration GetDestinationMemberConfiguration(MemberInfo destinationMember) + { + if (_memberConfigurations == null) + { + return null; + } + foreach (var config in _memberConfigurations) + { + if (config.DestinationMember == destinationMember) + { + return config; + } + } + return null; + } protected abstract void IgnoreDestinationMember(MemberInfo property, bool ignorePaths = true); } public abstract class MappingExpressionBase : TypeMapConfiguration, IMappingExpressionBase diff --git a/src/AutoMapper/ConstructorMap.cs b/src/AutoMapper/ConstructorMap.cs index 946bae36e1..2755ced3b2 100644 --- a/src/AutoMapper/ConstructorMap.cs +++ b/src/AutoMapper/ConstructorMap.cs @@ -7,6 +7,7 @@ using System.Reflection; namespace AutoMapper { + using Execution; [EditorBrowsable(EditorBrowsableState.Never)] public class ConstructorMap { @@ -96,7 +97,7 @@ public ConstructorParameterMap(ConstructorParameterMap parameterMap, IncludedMem public override IncludedMember IncludedMember { get; } public override MemberInfo[] SourceMembers { get; set; } public override string DestinationName => Parameter.Name; - public Expression DefaultValue() => Parameter.IsOptional ? Parameter.GetDefaultValue() : Expression.Default(DestinationType); + public Expression DefaultValue(IGlobalConfiguration configuration) => Parameter.IsOptional ? Parameter.GetDefaultValue(configuration) : configuration.Default(DestinationType); public override string ToString() => Parameter.Member.DeclaringType + "." + Parameter.Member + ".parameter " + Parameter.Name; } } \ No newline at end of file diff --git a/src/AutoMapper/Execution/ExpressionBuilder.cs b/src/AutoMapper/Execution/ExpressionBuilder.cs index 2f7e2fc66f..24a61e419c 100644 --- a/src/AutoMapper/Execution/ExpressionBuilder.cs +++ b/src/AutoMapper/Execution/ExpressionBuilder.cs @@ -42,9 +42,11 @@ public static class ExpressionBuilder private static readonly ParameterExpression[] Indexes = new[] { Index }; private static readonly BinaryExpression ResetIndex = Assign(Index, Zero); private static readonly UnaryExpression IncrementIndex = PostIncrementAssign(Index); + public static DefaultExpression Default(this IGlobalConfiguration configuration, Type type) => + configuration == null ? Expression.Default(type) : configuration.GetDefault(type); public static (List Variables, List Expressions) ScratchPad(this IGlobalConfiguration configuration) { - var variables = configuration.Variables; + var variables = configuration?.Variables; if (variables == null) { variables = new(); @@ -53,7 +55,7 @@ public static (List Variables, List Expressions { variables.Clear(); } - var expressions = configuration.Expressions; + var expressions = configuration?.Expressions; if (expressions == null) { expressions = new(); @@ -67,7 +69,7 @@ public static (List Variables, List Expressions public static Expression MapExpression(this IGlobalConfiguration configuration, ProfileMap profileMap, TypePair typePair, Expression source, MemberMap memberMap = null, Expression destination = null) { - destination ??= Default(typePair.DestinationType); + destination ??= configuration.Default(typePair.DestinationType); var typeMap = configuration.ResolveTypeMap(typePair); Expression mapExpression = null; bool nullCheck; @@ -153,7 +155,7 @@ Expression DefaultDestination() { if ((isCollection && profileMap.AllowsNullCollectionsFor(memberMap)) || (!isCollection && profileMap.AllowsNullDestinationValuesFor(memberMap))) { - return destination.NodeType == ExpressionType.Default ? destination : Default(destinationType); + return destination.NodeType == ExpressionType.Default ? destination : configuration.Default(destinationType); } if (destinationType.IsArray) { @@ -163,7 +165,7 @@ Expression DefaultDestination() Expression.Call(ArrayEmptyMethod.MakeGenericMethod(destinationElementType)) : NewArrayBounds(destinationElementType, Enumerable.Repeat(Zero, rank)); } - return ObjectFactory.GenerateConstructorExpression(destinationType); + return ObjectFactory.GenerateConstructorExpression(destinationType, configuration); } } public static Expression ServiceLocator(Type type) => Expression.Call(ContextParameter, ContextCreate, Constant(type)); @@ -378,7 +380,7 @@ public static Expression NullCheck(this Expression expression, IGlobalConfigurat var destinationType = memberMap?.DestinationType; var returnType = (destinationType != null && destinationType != expression.Type && Nullable.GetUnderlyingType(destinationType) == expression.Type) ? destinationType : expression.Type; - var defaultReturn = (defaultValue is { NodeType: ExpressionType.Default } && defaultValue.Type == returnType) ? defaultValue : Default(returnType); + var defaultReturn = (defaultValue is { NodeType: ExpressionType.Default } && defaultValue.Type == returnType) ? defaultValue : configuration.Default(returnType); List variables = null; List expressions = null; var name = parameter.Name; diff --git a/src/AutoMapper/Execution/ObjectFactory.cs b/src/AutoMapper/Execution/ObjectFactory.cs index b4c49443e6..4ff4fc3f30 100644 --- a/src/AutoMapper/Execution/ObjectFactory.cs +++ b/src/AutoMapper/Execution/ObjectFactory.cs @@ -15,17 +15,17 @@ public static class ObjectFactory private static readonly LockingConcurrentDictionary> CtorCache = new(GenerateConstructor); public static object CreateInstance(Type type) => CtorCache.GetOrAdd(type)(); private static Func GenerateConstructor(Type type) => - Lambda>(GenerateConstructorExpression(type).ToObject()).Compile(); + Lambda>(GenerateConstructorExpression(type, null).ToObject()).Compile(); public static object CreateInterfaceProxy(Type interfaceType) => CreateInstance(ProxyGenerator.GetProxyType(interfaceType)); - public static Expression GenerateConstructorExpression(Type type) => type switch + public static Expression GenerateConstructorExpression(Type type, IGlobalConfiguration configuration) => type switch { - { IsValueType: true } => Default(type), + { IsValueType: true } => configuration.Default(type), Type stringType when stringType == typeof(string) => Constant(string.Empty), { IsInterface: true } => CreateInterfaceExpression(type), { IsAbstract: true } => InvalidType(type, $"Cannot create an instance of abstract type {type}."), - _ => CallConstructor(type) + _ => CallConstructor(type, configuration) }; - private static Expression CallConstructor(Type type) + private static Expression CallConstructor(Type type, IGlobalConfiguration configuration) { var defaultCtor = type.GetConstructor(TypeExtensions.InstanceFlags, null, Type.EmptyTypes, null); if (defaultCtor != null) @@ -38,7 +38,7 @@ private static Expression CallConstructor(Type type) { return InvalidType(type, $"{type} needs to have a constructor with 0 args or only optional args. Validate your configuration for details."); } - var arguments = ctorWithOptionalArgs.args.Select(p => p.GetDefaultValue()); + var arguments = ctorWithOptionalArgs.args.Select(p => p.GetDefaultValue(configuration)); return New(ctorWithOptionalArgs.ctor, arguments); } private static Expression CreateInterfaceExpression(Type type) => diff --git a/src/AutoMapper/Execution/TypeMapPlanBuilder.cs b/src/AutoMapper/Execution/TypeMapPlanBuilder.cs index efa7ab8134..47f7864d07 100644 --- a/src/AutoMapper/Execution/TypeMapPlanBuilder.cs +++ b/src/AutoMapper/Execution/TypeMapPlanBuilder.cs @@ -16,6 +16,7 @@ public struct TypeMapPlanBuilder private readonly IGlobalConfiguration _configuration; private readonly ParameterExpression _destination; private readonly ParameterExpression _initialDestination; + private readonly ParameterExpression[] _parameters; private readonly TypeMap _typeMap; private List _variables; private List _expressions; @@ -30,16 +31,16 @@ public TypeMapPlanBuilder(IGlobalConfiguration configuration, TypeMap typeMap) _variables = configuration.Variables; _expressions = configuration.Expressions; _catches = configuration.Catches; + _parameters = _configuration.Parameters ?? new ParameterExpression[] { null, null, ContextParameter }; } public Type DestinationType => _destination.Type; public ParameterExpression Source { get; } private static AutoMapperMappingException MemberMappingError(Exception innerException, MemberMap memberMap) => new("Error mapping types.", innerException, memberMap); ParameterExpression[] GetParameters(ParameterExpression source = null, ParameterExpression destination = null) { - var parameters = _configuration.Parameters ?? new ParameterExpression[] { null, null, ContextParameter }; - parameters[0] = source ?? Source; - parameters[1] = destination ?? _destination; - return parameters; + _parameters[0] = source ?? Source; + _parameters[1] = destination ?? _destination; + return _parameters; } public LambdaExpression CreateMapperLambda() { @@ -86,14 +87,9 @@ static void Clear(ref HashSet typeMapsPath) } void IncludeMembers() { - var thisVar = this; - var includeVariables = _typeMap.IncludedMembersTypeMaps.Select(i => i.Variable).ToArray(); - var assignVariables = includeVariables.Zip(_typeMap.IncludedMembersTypeMaps, (v, i) => - Assign(v, i.MemberExpression.ReplaceParameters(thisVar.Source).NullCheck(thisVar._configuration))).ToArray(); - _expressions.Clear(); - _expressions.AddRange(assignVariables); - _variables.Clear(); - _variables.AddRange(includeVariables); + _variables.AddRange(_typeMap.IncludedMembersTypeMaps.Select(i => i.Variable)); + var source = Source; + _expressions.AddRange(_variables.Zip(_typeMap.IncludedMembersTypeMaps, (v, i) => Assign(v, i.MemberExpression.ReplaceParameters(source).NullCheck(null)))); } private static void CheckForCycles(IGlobalConfiguration configuration, TypeMap typeMap, HashSet typeMapsPath) { @@ -194,7 +190,7 @@ private Expression CreateAssignmentFunc(Expression createDestination) var property = TryPropertyMap(propertyMap); if (_typeMap.ConstructorParameterMatches(propertyMap.DestinationName)) { - property = _initialDestination.IfNullElse(Default(property.Type), property); + property = _initialDestination.IfNullElse(_configuration.Default(property.Type), property); } actions.Add(property); } @@ -220,20 +216,21 @@ private Expression CreateAssignmentFunc(Expression createDestination) private Expression TryPathMap(PathMap pathMap) { var destination = ((MemberExpression) pathMap.DestinationExpression.ConvertReplaceParameters(_destination)).Expression; + var configuration = _configuration; var createInnerObjects = CreateInnerObjects(destination); var setFinalValue = CreatePropertyMapFunc(pathMap, destination, pathMap.MemberPath.Last); var pathMapExpression = Block(createInnerObjects, setFinalValue); return TryMemberMap(pathMap, pathMapExpression); - static Expression CreateInnerObjects(Expression destination) + Expression CreateInnerObjects(Expression destination) { return Block(destination.GetMemberExpressions().Select(NullCheck).Append(ExpressionBuilder.Empty)); - static Expression NullCheck(MemberExpression memberExpression) + Expression NullCheck(MemberExpression memberExpression) { var setter = GetSetter(memberExpression); var ifNull = setter == null ? Throw(Constant(new NullReferenceException($"{memberExpression} cannot be null because it's used by ForPath.")), memberExpression.Type) - : (Expression)Assign(setter, ObjectFactory.GenerateConstructorExpression(memberExpression.Type)); - return memberExpression.IfNullElse(ifNull, Default(memberExpression.Type)); + : (Expression)Assign(setter, ObjectFactory.GenerateConstructorExpression(memberExpression.Type, configuration)); + return memberExpression.IfNullElse(ifNull, configuration.Default(memberExpression.Type)); } static Expression GetSetter(MemberExpression memberExpression) => memberExpression.Member switch { @@ -249,7 +246,7 @@ private Expression CreateMapperFunc(Expression assignmentFunc) var overMaxDepth = OverMaxDepth(_typeMap); if (overMaxDepth != null) { - mapperFunc = Condition(overMaxDepth, Default(DestinationType), mapperFunc); + mapperFunc = Condition(overMaxDepth, _configuration.Default(DestinationType), mapperFunc); } mapperFunc = _configuration.NullCheckSource(_typeMap.Profile, Source, _initialDestination, mapperFunc, null); return CheckReferencesCache(mapperFunc); @@ -265,10 +262,10 @@ private Expression CheckReferencesCache(Expression valueBuilder) } private Expression CreateNewDestinationFunc() => _typeMap switch { - { CustomCtorFunction: LambdaExpression constructUsingFunc } => constructUsingFunc.ReplaceParameters(new[] { Source, ContextParameter }), + { CustomCtorFunction: LambdaExpression constructUsingFunc } => constructUsingFunc.ReplaceParameters(GetParameters(destination: ContextParameter)), { ConstructorMap: { CanResolve: true } constructorMap } => ConstructorMapping(constructorMap), { DestinationType: { IsInterface: true } interfaceType } => Throw(Constant(new AutoMapperMappingException("Cannot create interface "+interfaceType, null, _typeMap)), interfaceType), - _ => ObjectFactory.GenerateConstructorExpression(DestinationType) + _ => ObjectFactory.GenerateConstructorExpression(DestinationType, _configuration) }; private Expression ConstructorMapping(ConstructorMap constructorMap) { @@ -280,7 +277,7 @@ private Expression ConstructorMapping(ConstructorMap constructorMap) } private Expression CreateConstructorParameterExpression(ConstructorParameterMap ctorParamMap) { - var defaultValue = ctorParamMap.DefaultValue(); + var defaultValue = ctorParamMap.DefaultValue(_configuration); var customSource = GetCustomSource(ctorParamMap); var resolvedExpression = BuildValueResolverFunc(ctorParamMap, customSource, defaultValue); var resolvedValue = Variable(resolvedExpression.Type, "resolvedValue"); @@ -311,7 +308,7 @@ private Expression CreatePropertyMapFunc(MemberMap memberMap, Expression destina { destinationMemberAccess = Property(destination, destinationProperty); destinationMemberReadOnly = !destinationProperty.CanWrite; - destinationMemberGetter = destinationProperty.CanRead ? destinationMemberAccess : Default(memberMap.DestinationType); + destinationMemberGetter = destinationProperty.CanRead ? destinationMemberAccess : _configuration.Default(memberMap.DestinationType); } else { @@ -349,7 +346,7 @@ Expression DestinationMemberValue(MemberMap memberMap, Expression destinationMem { return destinationMemberGetter; } - var defaultValue = Default(memberMap.DestinationType); + var defaultValue = _configuration.Default(memberMap.DestinationType); return DestinationType.IsValueType ? defaultValue : Condition(ReferenceEqual(_initialDestination, Null), defaultValue, destinationMemberGetter); } void Precondition(MemberMap memberMap, ParameterExpression customSource) @@ -398,7 +395,8 @@ private Expression BuildValueResolverFunc(MemberMap memberMap, Expression custom var toCreate = memberMap.SourceType; if (!toCreate.IsAbstract && toCreate.IsClass && !toCreate.IsArray) { - valueResolverFunc = Coalesce(valueResolverFunc, ToType(ObjectFactory.GenerateConstructorExpression(toCreate), valueResolverFunc.Type)); + var ctor = ObjectFactory.GenerateConstructorExpression(toCreate, _configuration); + valueResolverFunc = Coalesce(valueResolverFunc, ToType(ctor, valueResolverFunc.Type)); } } return valueResolverFunc; @@ -437,7 +435,7 @@ public Expression GetExpression(IGlobalConfiguration configuration, MemberMap me { return nullCheckedExpression; } - var defaultExpression = Default(mapFrom.Type); + var defaultExpression = configuration.Default(mapFrom.Type); return TryCatch(mapFrom, Catch(typeof(NullReferenceException), defaultExpression), Catch(typeof(ArgumentNullException), defaultExpression)); } public MemberInfo GetSourceMember(MemberMap _) => Lambda.GetMember(); diff --git a/src/AutoMapper/Internal/InternalApi.cs b/src/AutoMapper/Internal/InternalApi.cs index dc98a77db2..1bda4e6b5c 100644 --- a/src/AutoMapper/Internal/InternalApi.cs +++ b/src/AutoMapper/Internal/InternalApi.cs @@ -161,6 +161,7 @@ public interface IGlobalConfiguration : IConfigurationProvider List Expressions { get; } HashSet TypeMapsPath { get; } CatchBlock[] Catches { get; } + DefaultExpression GetDefault(Type type); } [EditorBrowsable(EditorBrowsableState.Never)] public interface IProfileExpressionInternal : IProfileExpression diff --git a/src/AutoMapper/Internal/ReflectionHelper.cs b/src/AutoMapper/Internal/ReflectionHelper.cs index acca515780..6c7ea27113 100644 --- a/src/AutoMapper/Internal/ReflectionHelper.cs +++ b/src/AutoMapper/Internal/ReflectionHelper.cs @@ -17,8 +17,8 @@ public static TypeMap[] GetIncludedTypeMaps(this IGlobalConfiguration configurat public static bool IsPublic(this PropertyInfo propertyInfo) => (propertyInfo.GetGetMethod() ?? propertyInfo.GetSetMethod()) != null; public static bool Has(this MemberInfo member) where TAttribute : Attribute => member.IsDefined(typeof(TAttribute)); public static bool CanBeSet(this MemberInfo member) => member is PropertyInfo property ? property.CanWrite : !((FieldInfo)member).IsInitOnly; - public static Expression GetDefaultValue(this ParameterInfo parameter) => - parameter is { DefaultValue: null, ParameterType: { IsValueType: true } type } ? Default(type) : ToType(Constant(parameter.DefaultValue), parameter.ParameterType); + public static Expression GetDefaultValue(this ParameterInfo parameter, IGlobalConfiguration configuration) => + parameter is { DefaultValue: null, ParameterType: { IsValueType: true } type } ? configuration.Default(type) : ToType(Constant(parameter.DefaultValue), parameter.ParameterType); public static object MapMember(this ResolutionContext context, MemberInfo member, object source, object destination = null) { var memberType = GetMemberType(member); diff --git a/src/AutoMapper/Internal/TypeDetails.cs b/src/AutoMapper/Internal/TypeDetails.cs index 71740b5aca..c1515c633c 100644 --- a/src/AutoMapper/Internal/TypeDetails.cs +++ b/src/AutoMapper/Internal/TypeDetails.cs @@ -133,8 +133,9 @@ public MethodInfo Close() public override object[] GetCustomAttributes(Type attributeType, bool inherit) => throw new NotImplementedException(); public override bool IsDefined(Type attributeType, bool inherit) => throw new NotImplementedException(); } - public static IEnumerable PossibleNames(string memberName, List prefixes, List postfixes) + public static string[] PossibleNames(string memberName, List prefixes, List postfixes) { + List result = null; foreach (var prefix in prefixes) { if (!memberName.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)) @@ -142,26 +143,23 @@ public static IEnumerable PossibleNames(string memberName, List continue; } var withoutPrefix = memberName[prefix.Length..]; - yield return withoutPrefix; - foreach (var s in PostFixes(postfixes, withoutPrefix)) - { - yield return s; - } + result ??= new(); + result.Add(withoutPrefix); + PostFixes(ref result, postfixes, withoutPrefix); } - foreach (var s in PostFixes(postfixes, memberName)) - { - yield return s; - } - } - private static IEnumerable PostFixes(List postfixes, string name) - { - foreach (var postfix in postfixes) + PostFixes(ref result, postfixes, memberName); + return result == null ? Array.Empty() : result.ToArray(); + static void PostFixes(ref List result, List< string> postfixes, string name) { - if (!name.EndsWith(postfix, StringComparison.OrdinalIgnoreCase)) + foreach (var postfix in postfixes) { - continue; + if (!name.EndsWith(postfix, StringComparison.OrdinalIgnoreCase)) + { + continue; + } + result ??= new(); + result.Add(name[..^postfix.Length]); } - yield return name[..^postfix.Length]; } } public Type Type { get; } diff --git a/src/AutoMapper/Mappers/CollectionMapper.cs b/src/AutoMapper/Mappers/CollectionMapper.cs index 72a95c42e4..b91774f185 100644 --- a/src/AutoMapper/Mappers/CollectionMapper.cs +++ b/src/AutoMapper/Mappers/CollectionMapper.cs @@ -40,7 +40,7 @@ Expression MapReadOnlyCollection(Type genericCollectionType, Type genericReadOnl { var destinationTypeArguments = destinationType.GenericTypeArguments; var closedCollectionType = genericCollectionType.MakeGenericType(destinationTypeArguments); - var dict = MapCollectionCore(Default(closedCollectionType)); + var dict = MapCollectionCore(configuration.Default(closedCollectionType)); var readOnlyClosedType = destinationType.IsInterface ? genericReadOnlyCollectionType.MakeGenericType(destinationTypeArguments) : destinationType; return New(readOnlyClosedType.GetConstructors()[0], dict); } @@ -138,7 +138,8 @@ void UseDestinationValue() else { destination = newExpression; - assignNewExpression = Assign(newExpression, Coalesce(passedDestination, ObjectFactory.GenerateConstructorExpression(passedDestination.Type))); + var ctor = ObjectFactory.GenerateConstructorExpression(passedDestination.Type, configuration); + assignNewExpression = Assign(newExpression, Coalesce(passedDestination, ctor)); } } Expression CheckContext() diff --git a/src/AutoMapper/Mappers/StringToEnumMapper.cs b/src/AutoMapper/Mappers/StringToEnumMapper.cs index 38e0aa1ba7..9e2832160d 100644 --- a/src/AutoMapper/Mappers/StringToEnumMapper.cs +++ b/src/AutoMapper/Mappers/StringToEnumMapper.cs @@ -20,7 +20,7 @@ public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap p var ignoreCase = True; var enumParse = Call(ParseMethod.MakeGenericMethod(destinationType), sourceExpression, ignoreCase); var enumMember = CheckEnumMember(sourceExpression, destinationType, enumParse, EqualsMethod); - return Condition(Equal(Property(sourceExpression, Length), Zero), Default(destinationType), enumMember); + return Condition(Equal(Property(sourceExpression, Length), Zero), configuration.Default(destinationType), enumMember); } internal static Expression CheckEnumMember(Expression sourceExpression, Type enumType, Expression defaultExpression, MethodInfo comparison = null) { diff --git a/src/AutoMapper/QueryableExtensions/ProjectionBuilder.cs b/src/AutoMapper/QueryableExtensions/ProjectionBuilder.cs index 6c30349577..fffd162932 100644 --- a/src/AutoMapper/QueryableExtensions/ProjectionBuilder.cs +++ b/src/AutoMapper/QueryableExtensions/ProjectionBuilder.cs @@ -201,7 +201,7 @@ IProjectionMapper GetProjectionMapper() { { CustomCtorExpression: LambdaExpression ctorExpression } => (NewExpression)ctorExpression.ReplaceParameters(instanceParameter), { ConstructorMap: { CanResolve: true } constructorMap } => - New(constructorMap.Ctor, constructorMap.CtorParams.Select(map => TryProjectMember(map, null, map.DefaultValue()) ?? Default(map.DestinationType))), + New(constructorMap.Ctor, constructorMap.CtorParams.Select(map => TryProjectMember(map, null, map.DefaultValue(null)) ?? Default(map.DestinationType))), _ => New(typeMap.DestinationType) }; } @@ -245,7 +245,7 @@ public override QueryExpressions GetSubQueryExpression(ProjectionBuilder builder TypeMap letTypeMap; lock(Configuration) { - letTypeMap = new(request.SourceType, letType, typeMap.Profile); + letTypeMap = new(request.SourceType, letType, typeMap.Profile, null); } var secondParameter = Parameter(letType, "dtoLet"); ReplaceSubQueries(); diff --git a/src/AutoMapper/TypeMap.cs b/src/AutoMapper/TypeMap.cs index a831e0575c..455cbddda8 100644 --- a/src/AutoMapper/TypeMap.cs +++ b/src/AutoMapper/TypeMap.cs @@ -24,7 +24,7 @@ public class TypeMap private TypeMapDetails _details; private Dictionary _propertyMaps; private bool _sealed; - public TypeMap(Type sourceType, Type destinationType, ProfileMap profile, TypeMapConfiguration typeMapConfiguration = null, List sourceMembers = null) + public TypeMap(Type sourceType, Type destinationType, ProfileMap profile, TypeMapConfiguration typeMapConfiguration, List sourceMembers = null) { Types = new(sourceType, destinationType); Profile = profile; diff --git a/src/Benchmark/BenchEngine.cs b/src/Benchmark/BenchEngine.cs index 5e7069a04a..887f8a137f 100644 --- a/src/Benchmark/BenchEngine.cs +++ b/src/Benchmark/BenchEngine.cs @@ -21,7 +21,7 @@ public void Start() //var timer = Stopwatch.StartNew(); - //for(int i = 0; i < 1_000_000; i++) + //for (int i = 0; i < 1_000_000; i++) //{ // _mapper.Map(); //} diff --git a/src/Benchmark/FlatteningMapper.cs b/src/Benchmark/FlatteningMapper.cs index e40d9c4d69..85aa55d8a1 100644 --- a/src/Benchmark/FlatteningMapper.cs +++ b/src/Benchmark/FlatteningMapper.cs @@ -6,22 +6,45 @@ namespace Benchmark.Flattening { using System.Collections.Generic; using System.Linq; - - public class DeepTypeMapper : IObjectToObjectMapper + static class Config { - private Customer _customer; - private IMapper _mapper; - public string Name { get; } = "Deep Types"; - public void Initialize() + public static readonly IMapper Mapper = CreateMapper(); + private static IMapper CreateMapper() { var config = new MapperConfiguration(cfg => { cfg.CreateMap(); cfg.CreateMap(); cfg.CreateMap(); + + cfg.CreateMap(); + cfg.CreateMap(); + + cfg.CreateMap(); + + cfg.CreateMap(); + cfg.CreateMap(); + cfg.CreateMap(); + cfg.CreateMap(); + cfg.CreateMap(); + cfg.CreateMap(); + cfg.CreateMap(); + cfg.CreateMap(); + cfg.CreateMap(); + cfg.CreateMap(); + cfg.CreateMap(); }); //config.AssertConfigurationIsValid(); - _mapper = config.CreateMapper(); + return config.CreateMapper(); + } + public static TDestination Map(TSource source) => Mapper.Map(source); + } + public class DeepTypeMapper : IObjectToObjectMapper + { + private Customer _customer; + public string Name { get; } = "Deep Types"; + public void Initialize() + { _customer = new Customer() { Address = new Address() { City = "istanbul", Country = "turkey", Id = 1, Street = "istiklal cad." }, @@ -41,51 +64,44 @@ public void Initialize() }.ToArray() }; } + public object Map() => Config.Map(_customer); + } + public class Address + { + public int Id { get; set; } + public string Street { get; set; } + public string City { get; set; } + public string Country { get; set; } + } - public object Map() - { - return _mapper.Map(_customer); - } - - public class Address - { - public int Id { get; set; } - public string Street { get; set; } - public string City { get; set; } - public string Country { get; set; } - } - - public class AddressDTO - { - public int Id { get; set; } - public string City { get; set; } - public string Country { get; set; } - } - - public class Customer - { - public int Id { get; set; } - public string Name { get; set; } - public decimal? Credit { get; set; } - public Address Address { get; set; } - public Address HomeAddress { get; set; } - public Address[] Addresses { get; set; } - public List
WorkAddresses { get; set; } - } - - public class CustomerDTO - { - public int Id { get; set; } - public string Name { get; set; } - public Address Address { get; set; } - public AddressDTO HomeAddress { get; set; } - public AddressDTO[] Addresses { get; set; } - public List WorkAddresses { get; set; } - public string AddressCity { get; set; } - } + public class AddressDTO + { + public int Id { get; set; } + public string City { get; set; } + public string Country { get; set; } + } + public class Customer + { + public int Id { get; set; } + public string Name { get; set; } + public decimal? Credit { get; set; } + public Address Address { get; set; } + public Address HomeAddress { get; set; } + public Address[] Addresses { get; set; } + public List
WorkAddresses { get; set; } } + public class CustomerDTO + { + public int Id { get; set; } + public string Name { get; set; } + public Address Address { get; set; } + public AddressDTO HomeAddress { get; set; } + public AddressDTO[] Addresses { get; set; } + public List WorkAddresses { get; set; } + public string AddressCity { get; set; } + } public class ManualDeepTypeMapper : IObjectToObjectMapper { private Customer _customer; @@ -135,71 +151,20 @@ public object Map() { dto.WorkAddresses.Add(new AddressDTO() { Id = workAddress.Id, Country = workAddress.Country, City = workAddress.City }); } - return dto; } - - public class Address - { - public int Id { get; set; } - public string Street { get; set; } - public string City { get; set; } - public string Country { get; set; } - } - - public class AddressDTO - { - public int Id { get; set; } - public string City { get; set; } - public string Country { get; set; } - } - - public class Customer - { - public int Id { get; set; } - public string Name { get; set; } - public decimal? Credit { get; set; } - public Address Address { get; set; } - public Address HomeAddress { get; set; } - public Address[] Addresses { get; set; } - public ICollection
WorkAddresses { get; set; } - } - - public class CustomerDTO - { - public int Id { get; set; } - public string Name { get; set; } - public Address Address { get; set; } - public AddressDTO HomeAddress { get; set; } - public AddressDTO[] Addresses { get; set; } - public List WorkAddresses { get; set; } - public string AddressCity { get; set; } - } - } - public class ComplexTypeMapper : IObjectToObjectMapper { private Foo _foo; public string Name { get; } = "Complex Types"; - private IMapper _mapper; - - public void Initialize() { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap(); - cfg.CreateMap(); - }); - //config.AssertConfigurationIsValid(); - _mapper = config.CreateMapper(); _foo = Foo.New(); } - public object Map() { - var dest = _mapper.Map(_foo); + var dest = Config.Map(_foo); return dest; } } @@ -339,75 +304,26 @@ public object Map() return dest; } } - - public class CtorMapper : IObjectToObjectMapper { private Model11 _model; - public string Name => "CtorMapper"; - - private IMapper _mapper; - - public void Initialize() - { - var config = new MapperConfiguration(cfg => cfg.CreateMap()); - //config.AssertConfigurationIsValid(); - _mapper = config.CreateMapper(); - _model = new Model11 { Value = 5 }; - } - - public object Map() - { - return _mapper.Map(_model); - } + public void Initialize() => _model = new Model11 { Value = 5 }; + public object Map() => Config.Map(_model); } - public class ManualCtorMapper : IObjectToObjectMapper { private Model11 _model; - public string Name => "ManualCtorMapper"; - - public void Initialize() - { - _model = new Model11 { Value = 5 }; - } - - public object Map() - { - return new Dto11(_model.Value); - } + public void Initialize() => _model = new Model11 { Value = 5 }; + public object Map() => new Dto11(_model.Value); } - public class FlatteningMapper : IObjectToObjectMapper { private ModelObject _source; - private IMapper _mapper; - - public string Name - { - get { return "AutoMapper"; } - } - + public string Name => "AutoMapper"; public void Initialize() { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap(); - cfg.CreateMap(); - cfg.CreateMap(); - cfg.CreateMap(); - cfg.CreateMap(); - cfg.CreateMap(); - cfg.CreateMap(); - cfg.CreateMap(); - cfg.CreateMap(); - cfg.CreateMap(); - cfg.CreateMap(); - }); - //config.AssertConfigurationIsValid(); - _mapper = config.CreateMapper(); _source = new ModelObject { BaseDate = new DateTime(2007, 4, 5), @@ -428,23 +344,14 @@ public void Initialize() ProperName = "Some other name" }, }; + var mapper = Config.Mapper; } - - public object Map() - { - return _mapper.Map(_source); - } + public object Map() => Config.Map(_source); } - public class ManualMapper : IObjectToObjectMapper { private ModelObject _source; - - public string Name - { - get { return "Manual"; } - } - + public string Name => "Manual"; public void Initialize() { _source = new ModelObject @@ -468,7 +375,6 @@ public void Initialize() }, }; } - public object Map() { return new ModelDto @@ -481,7 +387,6 @@ public object Map() }; } } - public class Model1 { public int Value { get; set; } diff --git a/src/UnitTests/IMappingExpression/IncludeMembers.cs b/src/UnitTests/IMappingExpression/IncludeMembers.cs index 0fe26b2a72..ba480f3069 100644 --- a/src/UnitTests/IMappingExpression/IncludeMembers.cs +++ b/src/UnitTests/IMappingExpression/IncludeMembers.cs @@ -99,7 +99,7 @@ class Destination public void Should_null_check() { Expression> expression = s => s.InnerSources.FirstOrDefault().InnerSource; - var result= expression.Body.NullCheck(Configuration); + var result= expression.Body.NullCheck(null); } [Fact] public void Should_flatten() diff --git a/src/UnitTests/Internal/TypeMapFactorySpecs.cs b/src/UnitTests/Internal/TypeMapFactorySpecs.cs index 3cb169c4ec..e02556a771 100644 --- a/src/UnitTests/Internal/TypeMapFactorySpecs.cs +++ b/src/UnitTests/Internal/TypeMapFactorySpecs.cs @@ -43,7 +43,7 @@ public void Should_map_properties_with_same_name() //mappingOptions.DestinationMemberNamingConvention = new PascalCaseNamingConvention(); var profile = new ProfileMap(mappingOptions); - var typeMap = new TypeMap(typeof(Source), typeof(Destination), profile); + var typeMap = new TypeMap(typeof(Source), typeof(Destination), profile, null); var propertyMaps = typeMap.PropertyMaps; From c5d7c364be400b7465d5749e068573bbe9a93d20 Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Thu, 18 Aug 2022 19:10:14 +0300 Subject: [PATCH 32/67] cosmetic --- src/AutoMapper/ApiCompatBaseline.txt | 8 +++- .../Configuration/ConfigurationValidator.cs | 17 +------- .../Configuration/Conventions/Mappers.cs | 2 - .../Conventions/MemberConfiguration.cs | 27 ++----------- .../Configuration/MapperConfiguration.cs | 15 +++---- .../MapperConfigurationExpression.cs | 6 +-- src/AutoMapper/Configuration/Profile.cs | 39 +++++++++++-------- .../Execution/TypeMapPlanBuilder.cs | 14 +++---- src/AutoMapper/Internal/InternalApi.cs | 5 ++- src/AutoMapper/ProfileMap.cs | 27 ++++++------- 10 files changed, 66 insertions(+), 94 deletions(-) diff --git a/src/AutoMapper/ApiCompatBaseline.txt b/src/AutoMapper/ApiCompatBaseline.txt index 2513596469..dc318ff2e7 100644 --- a/src/AutoMapper/ApiCompatBaseline.txt +++ b/src/AutoMapper/ApiCompatBaseline.txt @@ -25,6 +25,10 @@ MembersMustExist : Member 'public System.String AutoMapper.LowerUnderscoreNaming MembersMustExist : Member 'public System.Text.RegularExpressions.Regex AutoMapper.LowerUnderscoreNamingConvention.SplittingExpression.get()' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.String AutoMapper.PascalCaseNamingConvention.ReplaceValue(System.Text.RegularExpressions.Match)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Text.RegularExpressions.Regex AutoMapper.PascalCaseNamingConvention.SplittingExpression.get()' does not exist in the implementation but it does exist in the contract. +CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.CompilerGeneratedAttribute' exists on 'AutoMapper.Profile.DestinationMemberNamingConvention.get()' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.CompilerGeneratedAttribute' exists on 'AutoMapper.Profile.DestinationMemberNamingConvention.set(AutoMapper.INamingConvention)' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.CompilerGeneratedAttribute' exists on 'AutoMapper.Profile.SourceMemberNamingConvention.get()' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.CompilerGeneratedAttribute' exists on 'AutoMapper.Profile.SourceMemberNamingConvention.set(AutoMapper.INamingConvention)' in the contract but not the implementation. MembersMustExist : Member 'public AutoMapper.IMappingOperationOptions AutoMapper.ResolutionContext.Options.get()' does not exist in the implementation but it does exist in the contract. TypesMustExist : Type 'AutoMapper.ValueResolverConfiguration' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Linq.Expressions.LambdaExpression System.Linq.Expressions.LambdaExpression AutoMapper.ValueTransformerConfiguration.TransformerExpression' does not exist in the implementation but it does exist in the contract. @@ -46,6 +50,8 @@ CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'AutoMappe CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'AutoMapper.Configuration.Annotations.UseExistingValueAttribute' changed from '[AttributeUsageAttribute(384)]' in the contract to '[AttributeUsageAttribute(AttributeTargets.Field | AttributeTargets.Property)]' in the implementation. CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'AutoMapper.Configuration.Annotations.ValueConverterAttribute' changed from '[AttributeUsageAttribute(384)]' in the contract to '[AttributeUsageAttribute(AttributeTargets.Field | AttributeTargets.Property)]' in the implementation. CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'AutoMapper.Configuration.Annotations.ValueResolverAttribute' changed from '[AttributeUsageAttribute(384)]' in the contract to '[AttributeUsageAttribute(AttributeTargets.Field | AttributeTargets.Property)]' in the implementation. +MembersMustExist : Member 'public System.Collections.Generic.List AutoMapper.Configuration.Conventions.PrePostfixName.Postfixes.get()' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public System.Collections.Generic.List AutoMapper.Configuration.Conventions.PrePostfixName.Prefixes.get()' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Linq.Expressions.Expression System.Linq.Expressions.Expression AutoMapper.Execution.Member.Expression' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Linq.Expressions.Expression System.Linq.Expressions.Expression AutoMapper.Execution.Member.Target' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Reflection.MemberInfo System.Reflection.MemberInfo AutoMapper.Execution.Member.MemberInfo' does not exist in the implementation but it does exist in the contract. @@ -88,4 +94,4 @@ MembersMustExist : Member 'public AutoMapper.Internal.TypePair AutoMapper.Intern MembersMustExist : Member 'public System.Linq.IQueryable AutoMapper.QueryableExtensions.Extensions.Map(System.Linq.IQueryable, System.Linq.IQueryable, AutoMapper.IConfigurationProvider)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Collections.Generic.IReadOnlyCollection AutoMapper.QueryableExtensions.MemberVisitor.MemberPath.get()' does not exist in the implementation but it does exist in the contract. TypesMustExist : Type 'AutoMapper.QueryableExtensions.Impl.MemberAccessQueryMapperVisitor' does not exist in the implementation but it does exist in the contract. -Total Issues: 89 +Total Issues: 95 diff --git a/src/AutoMapper/Configuration/ConfigurationValidator.cs b/src/AutoMapper/Configuration/ConfigurationValidator.cs index 69655edde2..28904b102f 100644 --- a/src/AutoMapper/Configuration/ConfigurationValidator.cs +++ b/src/AutoMapper/Configuration/ConfigurationValidator.cs @@ -6,29 +6,23 @@ using AutoMapper.Internal.Mappers; namespace AutoMapper.Configuration { - using Validator = Action; [EditorBrowsable(EditorBrowsableState.Never)] public class ConfigurationValidator { private readonly IGlobalConfiguration _config; private readonly IGlobalConfigurationExpression _expression; - private readonly Validator[] _validators; - public ConfigurationValidator(IGlobalConfiguration config, IGlobalConfigurationExpression expression) { - _validators = expression.GetValidators(); _config = config; _expression = expression; } - private void Validate(ValidationContext context) { - foreach (var validator in _validators) + foreach (var validator in _expression.GetValidators()) { validator(context); } } - public void AssertConfigurationExpressionIsValid(IEnumerable typeMaps) { if (!_expression.AllowAdditiveTypeMapCreation) @@ -47,7 +41,6 @@ public void AssertConfigurationExpressionIsValid(IEnumerable typeMaps) } AssertConfigurationIsValid(typeMaps); } - public void AssertConfigurationIsValid(IEnumerable typeMaps) { var maps = typeMaps as TypeMap[] ?? typeMaps.ToArray(); @@ -64,10 +57,8 @@ where unmappedPropertyNames.Length > 0 || !canConstruct { throw new AutoMapperConfigurationException(badTypeMaps); } - var typeMapsChecked = new List(); var configExceptions = new List(); - foreach (var typeMap in maps) { try @@ -79,7 +70,6 @@ where unmappedPropertyNames.Length > 0 || !canConstruct configExceptions.Add(e); } } - if (configExceptions.Count > 1) { throw new AggregateException(configExceptions); @@ -89,7 +79,6 @@ where unmappedPropertyNames.Length > 0 || !canConstruct throw configExceptions[0]; } } - private void DryRunTypeMap(ICollection typeMapsChecked, TypePair types, TypeMap typeMap, MemberMap memberMap) { if(typeMap == null) @@ -107,15 +96,12 @@ private void DryRunTypeMap(ICollection typeMapsChecked, TypePair types, return; } typeMapsChecked.Add(typeMap); - var context = new ValidationContext(types, memberMap, typeMap); Validate(context); - if(!typeMap.ShouldCheckForValid) { return; } - CheckPropertyMaps(typeMapsChecked, typeMap); } else @@ -133,7 +119,6 @@ private void DryRunTypeMap(ICollection typeMapsChecked, TypePair types, } } } - private void CheckPropertyMaps(ICollection typeMapsChecked, TypeMap typeMap) { foreach (var memberMap in typeMap.MemberMaps) diff --git a/src/AutoMapper/Configuration/Conventions/Mappers.cs b/src/AutoMapper/Configuration/Conventions/Mappers.cs index 31b0662a08..f3100b4d19 100644 --- a/src/AutoMapper/Configuration/Conventions/Mappers.cs +++ b/src/AutoMapper/Configuration/Conventions/Mappers.cs @@ -36,8 +36,6 @@ public MemberInfo GetMatchingMemberInfo(TypeDetails sourceTypeDetails, Type dest } public class PrePostfixName : ISourceToDestinationNameMapper { - public List Prefixes { get; } = new(); - public List Postfixes { get; } = new(); public List DestinationPrefixes { get; } = new(); public List DestinationPostfixes { get; } = new(); public MemberInfo GetMatchingMemberInfo(TypeDetails sourceTypeDetails, Type destType, Type destMemberType, string nameToSearch) diff --git a/src/AutoMapper/Configuration/Conventions/MemberConfiguration.cs b/src/AutoMapper/Configuration/Conventions/MemberConfiguration.cs index 56c6b7fa2f..16f4b2996d 100644 --- a/src/AutoMapper/Configuration/Conventions/MemberConfiguration.cs +++ b/src/AutoMapper/Configuration/Conventions/MemberConfiguration.cs @@ -77,8 +77,8 @@ public bool MapDestinationPropertyToSource(ProfileMap options, TypeDetails sourc public class NameSplitMember : IChildMemberConfiguration { bool _default = true; - public INamingConvention SourceMemberNamingConvention { get; set; } - public INamingConvention DestinationMemberNamingConvention { get; set; } + public INamingConvention SourceMemberNamingConvention { get; set; } = PascalCaseNamingConvention.Instance; + public INamingConvention DestinationMemberNamingConvention { get; set; } = PascalCaseNamingConvention.Instance; public bool MapDestinationPropertyToSource(ProfileMap options, TypeDetails sourceType, Type destType, Type destMemberType, string nameToSearch, List resolvers, IMemberConfiguration parent, bool isReverseMap) => _default ? Default(options, sourceType, destType, destMemberType, nameToSearch, resolvers, parent, isReverseMap) : @@ -143,26 +143,7 @@ bool Conventions(ProfileMap options, TypeDetails sourceType, Type destType, Type } return false; } - internal void Set(INamingConvention source, INamingConvention destination) - { - if (source == null) - { - SourceMemberNamingConvention = PascalCaseNamingConvention.Instance; - } - else - { - SourceMemberNamingConvention = source; - _default = false; - } - if (destination == null) - { - DestinationMemberNamingConvention = PascalCaseNamingConvention.Instance; - } - else - { - DestinationMemberNamingConvention = destination; - _default = false; - } - } + internal void Seal() => _default = SourceMemberNamingConvention == PascalCaseNamingConvention.Instance && + DestinationMemberNamingConvention == PascalCaseNamingConvention.Instance; } } \ No newline at end of file diff --git a/src/AutoMapper/Configuration/MapperConfiguration.cs b/src/AutoMapper/Configuration/MapperConfiguration.cs index eaf874f00d..e62bfd897d 100644 --- a/src/AutoMapper/Configuration/MapperConfiguration.cs +++ b/src/AutoMapper/Configuration/MapperConfiguration.cs @@ -64,7 +64,7 @@ public class MapperConfiguration : IGlobalConfiguration private readonly HashSet _typeMapsPath = new(); private readonly List _sourceMembers = new(); private readonly List _variables = new(); - private readonly ParameterExpression[] _parameters = new ParameterExpression[] { null, null, ContextParameter }; + private readonly ParameterExpression[] _parameters = new[] { null, null, ContextParameter }; private readonly CatchBlock[] _catches = new CatchBlock[1]; private readonly List _expressions = new(); private readonly Dictionary _defaults; @@ -165,9 +165,12 @@ Delegate CompileExecutionPlan(MapRequest mapRequest) return executionPlan.Compile(); // breakpoint here to inspect all execution plans } } - public MapperConfiguration(Action configure) - : this(Build(configure)) + public MapperConfiguration(Action configure) : this(Build(configure)){} + static MapperConfigurationExpression Build(Action configure) { + MapperConfigurationExpression expr = new(); + configure(expr); + return expr; } public void AssertConfigurationIsValid() => _validator.AssertConfigurationExpressionIsValid(_configuredMaps.Values); public IMapper CreateMapper() => new Mapper(this); @@ -242,12 +245,6 @@ LambdaExpression GenerateObjectMapperExpression(in MapRequest mapRequest, IObjec return Lambda(fullExpression, source, destination, ContextParameter); } } - static MapperConfigurationExpression Build(Action configure) - { - var expr = new MapperConfigurationExpression(); - configure(expr); - return expr; - } IProjectionBuilder IGlobalConfiguration.ProjectionBuilder => _projectionBuilder; Func IGlobalConfiguration.ServiceCtor => _serviceCtor; bool IGlobalConfiguration.EnableNullPropagationForQueryMapping => _enableNullPropagationForQueryMapping; diff --git a/src/AutoMapper/Configuration/MapperConfigurationExpression.cs b/src/AutoMapper/Configuration/MapperConfigurationExpression.cs index 8785f30ded..ba24d4b667 100644 --- a/src/AutoMapper/Configuration/MapperConfigurationExpression.cs +++ b/src/AutoMapper/Configuration/MapperConfigurationExpression.cs @@ -93,8 +93,8 @@ public interface IMapperConfigurationExpression : IProfileExpression } public class MapperConfigurationExpression : Profile, IGlobalConfigurationExpression { - private readonly List _profiles = new List(); - private readonly List _validators = new List(); + private readonly List _profiles = new(); + private readonly List _validators = new(); private readonly List _mappers; private Func _serviceCtor = Activator.CreateInstance; @@ -119,7 +119,7 @@ void IGlobalConfigurationExpression.Validator(Validator validator) => /// int IGlobalConfigurationExpression.MaxExecutionPlanDepth { get; set; } = 1; - Validator[] IGlobalConfigurationExpression.GetValidators() => _validators.ToArray(); + List IGlobalConfigurationExpression.GetValidators() => _validators; List IGlobalConfigurationExpression.ProjectionMappers { get; } = ProjectionBuilder.DefaultProjectionMappers(); diff --git a/src/AutoMapper/Configuration/Profile.cs b/src/AutoMapper/Configuration/Profile.cs index 901fa060cf..c25306c0ea 100644 --- a/src/AutoMapper/Configuration/Profile.cs +++ b/src/AutoMapper/Configuration/Profile.cs @@ -63,9 +63,12 @@ public interface IProfileConfiguration /// public abstract class Profile : IProfileExpressionInternal, IProfileConfiguration { + private readonly List _prefixes = new() { "Get" }; + private readonly List _postfixes = new(); private readonly List _typeMapConfigs = new(); private readonly PrePostfixName _prePostfixName = new(); - private readonly List _memberConfigurations = new(); + private readonly NameSplitMember _nameSplitMember = new(); + private readonly List _memberConfigurations; private List> _allPropertyMapActions; private List> _allTypeMapActions; private List _globalIgnores; @@ -73,21 +76,15 @@ public abstract class Profile : IProfileExpressionInternal, IProfileConfiguratio private List _sourceExtensionMethods; private List _valueTransformerConfigs; private bool? _constructorMappingEnabled; - protected Profile(string profileName) : this() => ProfileName = profileName; - protected Profile() { ProfileName = GetType().FullName; - var memberConfiguration = new MemberConfiguration(); - memberConfiguration.MemberMappers.Add(new NameSplitMember()); - _prePostfixName.Prefixes.Add("Get"); + MemberConfiguration memberConfiguration = new() { MemberMappers = { _nameSplitMember } }; memberConfiguration.NameMapper.NamedMappers.Add(_prePostfixName); - _memberConfigurations.Add(memberConfiguration); + _memberConfigurations = new() { memberConfiguration }; } - protected Profile(string profileName, Action configurationAction) - : this(profileName) => configurationAction(this); - + protected Profile(string profileName, Action configurationAction) : this(profileName) => configurationAction(this); IMemberConfiguration DefaultMemberConfig => _memberConfigurations[0]; IMemberConfiguration IProfileExpressionInternal.DefaultMemberConfig => DefaultMemberConfig; bool? IProfileConfiguration.ConstructorMappingEnabled => _constructorMappingEnabled; @@ -114,10 +111,20 @@ IReadOnlyCollection> IProfil public Func ShouldMapField { get; set; } public Func ShouldMapMethod { get; set; } public Func ShouldUseConstructor { get; set; } - public INamingConvention SourceMemberNamingConvention { get; set; } - public INamingConvention DestinationMemberNamingConvention { get; set; } + public INamingConvention SourceMemberNamingConvention + { + get => _nameSplitMember.SourceMemberNamingConvention; + set => _nameSplitMember.SourceMemberNamingConvention = value; + } + public INamingConvention DestinationMemberNamingConvention + { + get => _nameSplitMember.DestinationMemberNamingConvention; + set => _nameSplitMember.DestinationMemberNamingConvention = value; + } public List ValueTransformers => _valueTransformerConfigs ??= new(); - + NameSplitMember IProfileExpressionInternal.NameSplitMember => _nameSplitMember; + List IProfileExpressionInternal.Prefixes => _prefixes; + List IProfileExpressionInternal.Postfixes => _postfixes; public void DisableConstructorMapping() => _constructorMappingEnabled = false; void IProfileExpressionInternal.ForAllMaps(Action configuration) @@ -164,11 +171,11 @@ public IMappingExpression CreateMap(Type sourceType, Type destinationType, Membe } return map; } - public void ClearPrefixes() => _prePostfixName.Prefixes.Clear(); + public void ClearPrefixes() => _prefixes.Clear(); public void ReplaceMemberName(string original, string newValue) => DefaultMemberConfig.AddName(_ => _.AddReplace(original, newValue)); - public void RecognizePrefixes(params string[] prefixes) => _prePostfixName.Prefixes.AddRange(prefixes); - public void RecognizePostfixes(params string[] postfixes) => _prePostfixName.Postfixes.AddRange(postfixes); + public void RecognizePrefixes(params string[] prefixes) => _prefixes.AddRange(prefixes); + public void RecognizePostfixes(params string[] postfixes) => _postfixes.AddRange(postfixes); public void RecognizeDestinationPrefixes(params string[] prefixes) => _prePostfixName.DestinationPrefixes.AddRange(prefixes); public void RecognizeDestinationPostfixes(params string[] postfixes) => _prePostfixName.DestinationPostfixes.AddRange(postfixes); public void AddGlobalIgnore(string propertyNameStartingWith) diff --git a/src/AutoMapper/Execution/TypeMapPlanBuilder.cs b/src/AutoMapper/Execution/TypeMapPlanBuilder.cs index 47f7864d07..b410c9bb45 100644 --- a/src/AutoMapper/Execution/TypeMapPlanBuilder.cs +++ b/src/AutoMapper/Execution/TypeMapPlanBuilder.cs @@ -36,15 +36,15 @@ public TypeMapPlanBuilder(IGlobalConfiguration configuration, TypeMap typeMap) public Type DestinationType => _destination.Type; public ParameterExpression Source { get; } private static AutoMapperMappingException MemberMappingError(Exception innerException, MemberMap memberMap) => new("Error mapping types.", innerException, memberMap); - ParameterExpression[] GetParameters(ParameterExpression source = null, ParameterExpression destination = null) + ParameterExpression[] GetParameters(ParameterExpression first = null, ParameterExpression second = null) { - _parameters[0] = source ?? Source; - _parameters[1] = destination ?? _destination; + _parameters[0] = first ?? Source; + _parameters[1] = second ?? _destination; return _parameters; } public LambdaExpression CreateMapperLambda() { - var parameters = GetParameters(destination: _initialDestination); + var parameters = GetParameters(second: _initialDestination); var customExpression = _typeMap.TypeConverter?.GetExpression(parameters); if (customExpression != null) { @@ -72,7 +72,7 @@ public LambdaExpression CreateMapperLambda() } _expressions.Add(mapperFunc); _variables.Add(_destination); - return Lambda(Block(_variables, _expressions), GetParameters(destination: _initialDestination)); + return Lambda(Block(_variables, _expressions), GetParameters(second: _initialDestination)); static void Clear(ref HashSet typeMapsPath) { if (typeMapsPath == null) @@ -262,7 +262,7 @@ private Expression CheckReferencesCache(Expression valueBuilder) } private Expression CreateNewDestinationFunc() => _typeMap switch { - { CustomCtorFunction: LambdaExpression constructUsingFunc } => constructUsingFunc.ReplaceParameters(GetParameters(destination: ContextParameter)), + { CustomCtorFunction: LambdaExpression constructUsingFunc } => constructUsingFunc.ReplaceParameters(GetParameters(second: ContextParameter)), { ConstructorMap: { CanResolve: true } constructorMap } => ConstructorMapping(constructorMap), { DestinationType: { IsInterface: true } interfaceType } => Throw(Constant(new AutoMapperMappingException("Cannot create interface "+interfaceType, null, _typeMap)), interfaceType), _ => ObjectFactory.GenerateConstructorExpression(DestinationType, _configuration) @@ -351,7 +351,7 @@ Expression DestinationMemberValue(MemberMap memberMap, Expression destinationMem } void Precondition(MemberMap memberMap, ParameterExpression customSource) { - var preCondition = memberMap.PreCondition.ConvertReplaceParameters(GetParameters(source: customSource)); + var preCondition = memberMap.PreCondition.ConvertReplaceParameters(GetParameters(first: customSource)); var ifThen = IfThen(preCondition, Block(_expressions)); _expressions.Clear(); _expressions.Add(ifThen); diff --git a/src/AutoMapper/Internal/InternalApi.cs b/src/AutoMapper/Internal/InternalApi.cs index 1bda4e6b5c..8add6a8881 100644 --- a/src/AutoMapper/Internal/InternalApi.cs +++ b/src/AutoMapper/Internal/InternalApi.cs @@ -47,7 +47,7 @@ public interface IGlobalConfigurationExpression : IMapperConfigurationExpression /// See the docs for details. /// int MaxExecutionPlanDepth { get; set; } - Validator[] GetValidators(); + List GetValidators(); List ProjectionMappers { get; } /// /// How many levels deep should recursive queries be expanded. @@ -166,6 +166,9 @@ public interface IGlobalConfiguration : IConfigurationProvider [EditorBrowsable(EditorBrowsableState.Never)] public interface IProfileExpressionInternal : IProfileExpression { + NameSplitMember NameSplitMember { get; } + List Prefixes { get; } + List Postfixes { get; } IMemberConfiguration DefaultMemberConfig { get; } IMemberConfiguration AddMemberConfiguration(); /// diff --git a/src/AutoMapper/ProfileMap.cs b/src/AutoMapper/ProfileMap.cs index df381903fc..a3aac95168 100644 --- a/src/AutoMapper/ProfileMap.cs +++ b/src/AutoMapper/ProfileMap.cs @@ -38,26 +38,21 @@ public ProfileMap(IProfileConfiguration profile, IGlobalConfigurationExpression ShouldMapMethod = profile.ShouldMapMethod ?? configuration?.ShouldMapMethod ?? (p => !p.IsSpecialName); ShouldUseConstructor = profile.ShouldUseConstructor ?? configuration?.ShouldUseConstructor ?? (c => true); ValueTransformers = profile.ValueTransformers.Concat(configuration?.ValueTransformers).ToArray(); - _memberConfigurations = profile.MemberConfigurations.Concat(globalProfile?.MemberConfigurations).ToArray(); - var nameSplitMember = (NameSplitMember)_memberConfigurations[0].MemberMappers.Find(m => m is NameSplitMember); - nameSplitMember?.Set(profile.SourceMemberNamingConvention, profile.DestinationMemberNamingConvention); + _memberConfigurations = profile.MemberConfigurations.Concat(globalProfile?.MemberConfigurations).ToArray(); var globalIgnores = profile.GlobalIgnores.Concat(globalProfile?.GlobalIgnores); GlobalIgnores = globalIgnores == Array.Empty() ? EmptyHashSet : new HashSet(globalIgnores); SourceExtensionMethods = profile.SourceExtensionMethods.Concat(globalProfile?.SourceExtensionMethods).ToArray(); AllPropertyMapActions = profile.AllPropertyMapActions.Concat(globalProfile?.AllPropertyMapActions).ToArray(); - AllTypeMapActions = profile.AllTypeMapActions.Concat(globalProfile?.AllTypeMapActions).ToArray(); - var prePostFixes = profile.MemberConfigurations.Concat(globalProfile?.MemberConfigurations) - .Select(m => m.NameMapper) - .SelectMany(m => m.NamedMappers) - .OfType() - .ToArray(); - Prefixes = prePostFixes.SelectMany(m => m.Prefixes).Distinct().ToList(); - Postfixes = prePostFixes.SelectMany(m => m.Postfixes).Distinct().ToList(); - SetTypeMapConfigs(); - SetOpenTypeMapConfigs(); - _typeDetails = new(2*_typeMapConfigs.Length); + AllTypeMapActions = profile.AllTypeMapActions.Concat(globalProfile?.AllTypeMapActions).ToArray(); + var profileInternal = (IProfileExpressionInternal)profile; + profileInternal.NameSplitMember.Seal(); + Prefixes = profileInternal.Prefixes.Concat(configuration?.Prefixes).Distinct().ToList(); + Postfixes = profileInternal.Postfixes.Concat(configuration?.Postfixes).Distinct().ToList(); + TypeMapConfigs(); + OpenTypeMapConfigs(); + _typeDetails = new(2 * _typeMapConfigs.Length); return; - void SetTypeMapConfigs() + void TypeMapConfigs() { _typeMapConfigs = new TypeMapConfiguration[profile.TypeMapConfigs.Count]; var index = 0; @@ -72,7 +67,7 @@ void SetTypeMapConfigs() } TypeMapsCount = index + reverseMapsCount; } - void SetOpenTypeMapConfigs() + void OpenTypeMapConfigs() { _openTypeMapConfigs = new(profile.OpenTypeMapConfigs.Count); foreach (var openTypeMapConfig in profile.OpenTypeMapConfigs) From 12676dd13798e181019562d17b4a79cb3f9ed721 Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Fri, 19 Aug 2022 11:27:35 +0300 Subject: [PATCH 33/67] less allocations --- src/AutoMapper/MemberMap.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/AutoMapper/MemberMap.cs b/src/AutoMapper/MemberMap.cs index 5435a43da3..cb796da0bc 100644 --- a/src/AutoMapper/MemberMap.cs +++ b/src/AutoMapper/MemberMap.cs @@ -59,8 +59,11 @@ public void MapFrom(string sourceMembersPath) } public override string ToString() => DestinationName; public Expression ChainSourceMembers(Expression source) => SourceMembers.Chain(source); - public Expression ChainSourceMembers(IGlobalConfiguration configuration, Expression source, Expression defaultValue) => - ChainSourceMembers(source).NullCheck(configuration, this, defaultValue); + public Expression ChainSourceMembers(IGlobalConfiguration configuration, Expression source, Expression defaultValue) + { + var expression = ChainSourceMembers(source); + return IncludedMember == null && SourceMembers.Length < 2 ? expression : expression.NullCheck(configuration, this, defaultValue); + } public bool AllowsNullDestinationValues => Profile?.AllowsNullDestinationValuesFor(this) ?? true; public bool AllowsNullCollections => (Profile?.AllowsNullCollectionsFor(this)).GetValueOrDefault(); public ProfileMap Profile => TypeMap?.Profile; From 85ff7057ac2cd3ed33e2c6e3d32262f6d7a86879 Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Fri, 19 Aug 2022 12:59:01 +0300 Subject: [PATCH 34/67] make MapFrom name more like the built-in mapping --- .../CtorParamConfigurationExpression.cs | 4 ++-- .../MemberConfigurationExpression.cs | 2 +- src/AutoMapper/Execution/ExpressionBuilder.cs | 3 ++- src/AutoMapper/Execution/TypeMapPlanBuilder.cs | 17 +++++++++++++++-- src/AutoMapper/Internal/ReflectionHelper.cs | 9 +++++++-- src/AutoMapper/MemberMap.cs | 10 +++++----- src/AutoMapper/TypeMap.cs | 4 ++-- src/UnitTests/Projection/MapFromTest.cs | 9 ++++++++- 8 files changed, 42 insertions(+), 16 deletions(-) diff --git a/src/AutoMapper/Configuration/CtorParamConfigurationExpression.cs b/src/AutoMapper/Configuration/CtorParamConfigurationExpression.cs index 544aedde98..5bd1ff09e8 100644 --- a/src/AutoMapper/Configuration/CtorParamConfigurationExpression.cs +++ b/src/AutoMapper/Configuration/CtorParamConfigurationExpression.cs @@ -62,8 +62,8 @@ public void MapFrom(Func resolver) public void MapFrom(string sourceMembersPath) { - ReflectionHelper.GetMemberPath(SourceType, sourceMembersPath); - _ctorParamActions.Add(cpm => cpm.MapFrom(sourceMembersPath)); + var sourceMembers = ReflectionHelper.GetMemberPath(SourceType, sourceMembersPath); + _ctorParamActions.Add(cpm => cpm.MapFrom(sourceMembersPath, sourceMembers)); } public void Configure(TypeMap typeMap) diff --git a/src/AutoMapper/Configuration/MemberConfigurationExpression.cs b/src/AutoMapper/Configuration/MemberConfigurationExpression.cs index 8fecabbfbf..3e2dba2d02 100644 --- a/src/AutoMapper/Configuration/MemberConfigurationExpression.cs +++ b/src/AutoMapper/Configuration/MemberConfigurationExpression.cs @@ -69,7 +69,7 @@ internal void MapFromUntyped(LambdaExpression sourceExpression) public void MapFrom(string sourceMembersPath) { _sourceMembers = ReflectionHelper.GetMemberPath(_sourceType, sourceMembersPath); - PropertyMapActions.Add(pm => pm.MapFrom(sourceMembersPath)); + PropertyMapActions.Add(pm => pm.MapFrom(sourceMembersPath, _sourceMembers)); } public void Condition(Func condition) => ConditionCore((src, dest, srcMember, destMember, ctxt) => condition(src, dest, srcMember, destMember, ctxt)); diff --git a/src/AutoMapper/Execution/ExpressionBuilder.cs b/src/AutoMapper/Execution/ExpressionBuilder.cs index 24a61e419c..6a491f2f2b 100644 --- a/src/AutoMapper/Execution/ExpressionBuilder.cs +++ b/src/AutoMapper/Execution/ExpressionBuilder.cs @@ -280,7 +280,8 @@ public static bool IsMemberPath(this LambdaExpression lambda, out Stack } return currentExpression == lambda.Body; } - public static LambdaExpression MemberAccessLambda(Type type, string memberPath) => GetMemberPath(type, memberPath).Lambda(); + public static LambdaExpression MemberAccessLambda(Type type, string memberPath, TypeMap typeMap) => + GetMemberPath(type, memberPath, typeMap).Lambda(); public static Expression ForEach(List variables, List statements, ParameterExpression loopVar, Expression collection, Expression loopContent) { if (collection.Type.IsArray) diff --git a/src/AutoMapper/Execution/TypeMapPlanBuilder.cs b/src/AutoMapper/Execution/TypeMapPlanBuilder.cs index b410c9bb45..93f48670ec 100644 --- a/src/AutoMapper/Execution/TypeMapPlanBuilder.cs +++ b/src/AutoMapper/Execution/TypeMapPlanBuilder.cs @@ -162,8 +162,8 @@ static void TraceInline(TypeMap typeMap, MemberMap memberMap) => } private Expression CreateDestinationFunc() { - var newDestFunc = ToType(CreateNewDestinationFunc(), DestinationType); - var getDest = DestinationType.IsValueType ? newDestFunc : Coalesce(_initialDestination, newDestFunc); + var newDestFunc = CreateNewDestinationFunc(); + var getDest = DestinationType.IsValueType ? newDestFunc : Coalesce(_initialDestination, ToType(newDestFunc, DestinationType)); var destinationFunc = Assign(_destination, getDest); return _typeMap.PreserveReferences ? Block(destinationFunc, Call(ContextParameter, CacheDestinationMethod, Source, Constant(DestinationType), _destination), _destination) : @@ -411,6 +411,19 @@ public interface IValueResolver string SourceMemberName => null; LambdaExpression ProjectToExpression => null; } + public class MemberPathResolver : IValueResolver + { + private readonly MemberInfo[] _members; + public MemberPathResolver(MemberInfo[] members) => _members = members; + public Type ResolvedType => _members?[^1].GetMemberType(); + public Expression GetExpression(IGlobalConfiguration configuration, MemberMap memberMap, Expression source, Expression destination, Expression destinationMember) + { + var expression = _members.Chain(source); + return memberMap.IncludedMember == null && _members.Length < 2 ? expression : expression.NullCheck(configuration, memberMap, destinationMember); + } + public MemberInfo GetSourceMember(MemberMap memberMap) => _members.Length == 1 ? _members[0] : null; + public LambdaExpression ProjectToExpression => _members.Lambda(); + } public abstract class LambdaValueResolver { public LambdaExpression Lambda { get; } diff --git a/src/AutoMapper/Internal/ReflectionHelper.cs b/src/AutoMapper/Internal/ReflectionHelper.cs index 6c7ea27113..d43b789d4a 100644 --- a/src/AutoMapper/Internal/ReflectionHelper.cs +++ b/src/AutoMapper/Internal/ReflectionHelper.cs @@ -45,16 +45,21 @@ public static void SetMemberValue(this MemberInfo propertyOrField, object target } throw Expected(propertyOrField); } - private static ArgumentOutOfRangeException Expected(MemberInfo propertyOrField) => new ArgumentOutOfRangeException(nameof(propertyOrField), "Expected a property or field, not " + propertyOrField); + private static ArgumentOutOfRangeException Expected(MemberInfo propertyOrField) => new(nameof(propertyOrField), "Expected a property or field, not " + propertyOrField); public static object GetMemberValue(this MemberInfo propertyOrField, object target) => propertyOrField switch { PropertyInfo property => property.GetValue(target, null), FieldInfo field => field.GetValue(target), _ => throw Expected(propertyOrField) }; - public static MemberInfo[] GetMemberPath(Type type, string fullMemberName) + public static MemberInfo[] GetMemberPath(Type type, string fullMemberName, TypeMap typeMap = null) { var memberNames = fullMemberName.Split('.'); + var sourceDetails = typeMap?.SourceTypeDetails; + if (sourceDetails != null && memberNames.Length == 1) + { + return new[] { sourceDetails.GetMember(memberNames[0]) }; + } var members = new MemberInfo[memberNames.Length]; Type previousType = type; for(int index = 0; index < memberNames.Length; index++) diff --git a/src/AutoMapper/MemberMap.cs b/src/AutoMapper/MemberMap.cs index cb796da0bc..ef5f96d639 100644 --- a/src/AutoMapper/MemberMap.cs +++ b/src/AutoMapper/MemberMap.cs @@ -50,12 +50,12 @@ public void MapFrom(LambdaExpression sourceMember) SetResolver(sourceMember); Ignored = false; } - public void MapFrom(string sourceMembersPath) + public void MapFrom(string sourceMembersPath, MemberInfo[] members) { - var mapExpression = TypeMap.SourceType.IsGenericTypeDefinition ? - EmptyLambda :// just a placeholder so the member is mapped - ExpressionBuilder.MemberAccessLambda(TypeMap.SourceType, sourceMembersPath); - MapFrom(mapExpression); + var sourceType = TypeMap.SourceType; + var sourceMembers = sourceType.ContainsGenericParameters ? null :// just a placeholder so the member is mapped + members[0].DeclaringType.ContainsGenericParameters ? ReflectionHelper.GetMemberPath(sourceType, sourceMembersPath, TypeMap) : members; + Resolver = new MemberPathResolver(sourceMembers); } public override string ToString() => DestinationName; public Expression ChainSourceMembers(Expression source) => SourceMembers.Chain(source); diff --git a/src/AutoMapper/TypeMap.cs b/src/AutoMapper/TypeMap.cs index 455cbddda8..c56ec53b65 100644 --- a/src/AutoMapper/TypeMap.cs +++ b/src/AutoMapper/TypeMap.cs @@ -137,8 +137,8 @@ public Type MakeGenericType(Type type) => type.IsGenericTypeDefinition ? type.MakeGenericType(SourceType.GenericTypeArguments.Concat(DestinationType.GenericTypeArguments).Take(type.GenericParametersCount()).ToArray()) : type; public bool HasIncludedMembers => IncludedMembers.Length > 0 || IncludedMembersNames.Length > 0; - public IEnumerable GetAllIncludedMembers() => IncludedMembersNames.Length == 0 || SourceType.ContainsGenericParameters ? - IncludedMembers : IncludedMembers.Concat(IncludedMembersNames.Select(name => MemberAccessLambda(SourceType, name))); + public IEnumerable GetAllIncludedMembers() => IncludedMembersNames.Length == 0 || SourceType.ContainsGenericParameters ? + IncludedMembers : IncludedMembers.Concat(IncludedMembersNames.Select(name => MemberAccessLambda(SourceType, name, this))); public bool ConstructorParameterMatches(string destinationPropertyName) => ConstructorMapping && ConstructorMap[destinationPropertyName] != null; private void AddPropertyMap(MemberInfo destProperty, Type destinationPropertyType, List sourceMembers) { diff --git a/src/UnitTests/Projection/MapFromTest.cs b/src/UnitTests/Projection/MapFromTest.cs index 021c8b5b8a..dd9a58acfa 100644 --- a/src/UnitTests/Projection/MapFromTest.cs +++ b/src/UnitTests/Projection/MapFromTest.cs @@ -48,8 +48,15 @@ public class UserDto { public string FullName { get; set; } } + [Fact] + public void Should_project_from_String() + { + var config = new MapperConfiguration(cfg => cfg.CreateMap() + .ForMember(dto => dto.FullName, opt => opt.MapFrom("FirstName"))); + var result = new[] { new UserModel { FirstName = "Hallo" } }.AsQueryable().ProjectTo(config).Single(); + result.FullName.ShouldBe("Hallo"); + } } - public class When_mapping_from_and_source_member_both_can_work : AutoMapperSpecBase { Dto _destination; From c71f168b84f06f2bf6382b217b410634e81737e6 Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Sat, 20 Aug 2022 16:40:24 +0300 Subject: [PATCH 35/67] less allocations --- src/AutoMapper/Execution/ExpressionBuilder.cs | 10 +++++----- src/AutoMapper/Internal/PrimitiveHelper.cs | 5 ++++- src/AutoMapper/Mappers/CollectionMapper.cs | 6 +++--- src/AutoMapper/Mappers/EnumToEnumMapper.cs | 2 +- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/AutoMapper/Execution/ExpressionBuilder.cs b/src/AutoMapper/Execution/ExpressionBuilder.cs index 6a491f2f2b..0b89b245a5 100644 --- a/src/AutoMapper/Execution/ExpressionBuilder.cs +++ b/src/AutoMapper/Execution/ExpressionBuilder.cs @@ -36,15 +36,15 @@ public static class ExpressionBuilder private static readonly MethodInfo ContextMapMethod = typeof(ResolutionContext).GetInstanceMethod(nameof(ResolutionContext.MapInternal)); private static readonly MethodInfo ArrayEmptyMethod = typeof(Array).GetStaticMethod(nameof(Array.Empty)); private static readonly ParameterExpression Disposable = Variable(typeof(IDisposable), "disposableEnumerator"); - private static readonly ParameterExpression[] DisposableArray = new[] { Disposable }; + private static readonly ReadOnlyCollection DisposableArray = Disposable.ToReadOnly(); private static readonly Expression DisposeCall = IfNullElse(Disposable, Empty, Expression.Call(Disposable, DisposeMethod)); private static readonly ParameterExpression Index = Variable(typeof(int), "sourceArrayIndex"); - private static readonly ParameterExpression[] Indexes = new[] { Index }; + private static readonly ReadOnlyCollection Indexes = Index.ToReadOnly(); private static readonly BinaryExpression ResetIndex = Assign(Index, Zero); private static readonly UnaryExpression IncrementIndex = PostIncrementAssign(Index); public static DefaultExpression Default(this IGlobalConfiguration configuration, Type type) => configuration == null ? Expression.Default(type) : configuration.GetDefault(type); - public static (List Variables, List Expressions) ScratchPad(this IGlobalConfiguration configuration) + public static (List Variables, List Expressions) Scratchpad(this IGlobalConfiguration configuration) { var variables = configuration?.Variables; if (variables == null) @@ -144,7 +144,7 @@ Expression ClearDestinationCollection() } clearMethod = destinationCollectionType.GetMethod("Clear"); } - var (variables, statements) = configuration.ScratchPad(); + var (variables, statements) = configuration.Scratchpad(); variables.Add(destinationVariable); statements.Add(Assign(destinationVariable, destination)); statements.Add(Condition(ReferenceEqual(collection, Null), Empty, Expression.Call(collection, clearMethod))); @@ -403,7 +403,7 @@ Expression NullCheck(Expression variable) } if (variables == null) { - (variables, expressions) = configuration.ScratchPad(); + (variables, expressions) = configuration.Scratchpad(); } name += member.MemberInfo.Name; var newVariable = Variable(member.Expression.Type, name); diff --git a/src/AutoMapper/Internal/PrimitiveHelper.cs b/src/AutoMapper/Internal/PrimitiveHelper.cs index 4616fc5973..401bb74b83 100644 --- a/src/AutoMapper/Internal/PrimitiveHelper.cs +++ b/src/AutoMapper/Internal/PrimitiveHelper.cs @@ -1,13 +1,16 @@ using System; -using System.Collections; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.ComponentModel; using System.Linq; +using System.Linq.Expressions; +using System.Runtime.CompilerServices; namespace AutoMapper.Internal { [EditorBrowsable(EditorBrowsableState.Never)] public static class PrimitiveHelper { + public static ReadOnlyCollection ToReadOnly(this T item) where T : Expression => new ReadOnlyCollectionBuilder{ item }.ToReadOnlyCollection(); public static IReadOnlyCollection NullCheck(this IReadOnlyCollection source) => source ?? Array.Empty(); public static IEnumerable Concat(this IReadOnlyCollection collection, IReadOnlyCollection otherCollection) { diff --git a/src/AutoMapper/Mappers/CollectionMapper.cs b/src/AutoMapper/Mappers/CollectionMapper.cs index b91774f185..fc314cb430 100644 --- a/src/AutoMapper/Mappers/CollectionMapper.cs +++ b/src/AutoMapper/Mappers/CollectionMapper.cs @@ -67,7 +67,7 @@ Expression MapCollectionCore(Expression destExpression) var itemExpr = configuration.MapExpression(profileMap, new TypePair(sourceElementType, destinationElementType), itemParam); Expression destination, assignNewExpression; UseDestinationValue(); - var (variables, statements) = configuration.ScratchPad(); + var (variables, statements) = configuration.Scratchpad(); statements.Add(itemExpr); var addCall = Call(destination, addMethod, statements); statements.Clear(); @@ -159,7 +159,7 @@ static class ArrayMapper private static readonly MethodInfo MapMultidimensionalMethod = typeof(ArrayMapper).GetStaticMethod(nameof(MapMultidimensional)); private static readonly ParameterExpression Index = Variable(typeof(int), "destinationArrayIndex"); private static readonly BinaryExpression ResetIndex = Assign(Index, Zero); - private static readonly UnaryExpression[] IncrementIndex = new[] { PostIncrementAssign(Index) }; + private static readonly ReadOnlyCollection IncrementIndex = PostIncrementAssign(Index).ToReadOnly(); private static Array MapMultidimensional(Array source, Type destinationElementType, ResolutionContext context) { var sourceElementType = source.GetType().GetElementType(); @@ -182,7 +182,7 @@ public static Expression MapToArray(IGlobalConfiguration configuration, ProfileM Type sourceElementType = typeof(object); Expression createDestination; var destination = Parameter(destinationType, "destinationArray"); - var (variables, statements) = configuration.ScratchPad(); + var (variables, statements) = configuration.Scratchpad(); if (sourceType.IsArray) { var mapFromArray = MapFromArray(); diff --git a/src/AutoMapper/Mappers/EnumToEnumMapper.cs b/src/AutoMapper/Mappers/EnumToEnumMapper.cs index db4f8da486..5e76b6ec37 100644 --- a/src/AutoMapper/Mappers/EnumToEnumMapper.cs +++ b/src/AutoMapper/Mappers/EnumToEnumMapper.cs @@ -17,7 +17,7 @@ public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap p var result = Variable(destinationType, "destinationEnumValue"); var ignoreCase = True; var tryParse = Call(TryParseMethod.MakeGenericMethod(destinationType), sourceToString, ignoreCase, result); - var (variables, statements) = configuration.ScratchPad(); + var (variables, statements) = configuration.Scratchpad(); variables.Add(result); statements.Add(Condition(tryParse, result, Convert(sourceExpression, destinationType))); return Block(variables, statements); From 3de255f3a15495fa2667437cd9b23513f0faa13e Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Sun, 21 Aug 2022 07:59:26 +0300 Subject: [PATCH 36/67] cosmetic --- .../Configuration/ConfigurationValidator.cs | 38 ++++++++----------- .../Configuration/MapperConfiguration.cs | 8 ++-- .../MapperConfigurationExpression.cs | 2 +- src/AutoMapper/Internal/InternalApi.cs | 2 +- 4 files changed, 21 insertions(+), 29 deletions(-) diff --git a/src/AutoMapper/Configuration/ConfigurationValidator.cs b/src/AutoMapper/Configuration/ConfigurationValidator.cs index 28904b102f..9f8776a36f 100644 --- a/src/AutoMapper/Configuration/ConfigurationValidator.cs +++ b/src/AutoMapper/Configuration/ConfigurationValidator.cs @@ -7,27 +7,20 @@ namespace AutoMapper.Configuration { [EditorBrowsable(EditorBrowsableState.Never)] - public class ConfigurationValidator + public readonly record struct ConfigurationValidator(IGlobalConfigurationExpression Expression) { - private readonly IGlobalConfiguration _config; - private readonly IGlobalConfigurationExpression _expression; - public ConfigurationValidator(IGlobalConfiguration config, IGlobalConfigurationExpression expression) - { - _config = config; - _expression = expression; - } private void Validate(ValidationContext context) { - foreach (var validator in _expression.GetValidators()) + foreach (var validator in Expression.Validators) { validator(context); } } - public void AssertConfigurationExpressionIsValid(IEnumerable typeMaps) + public void AssertConfigurationExpressionIsValid(IGlobalConfiguration config, IEnumerable typeMaps) { - if (!_expression.AllowAdditiveTypeMapCreation) + if (!Expression.AllowAdditiveTypeMapCreation) { - var duplicateTypeMapConfigs = _expression.Profiles.Append((Profile)_expression) + var duplicateTypeMapConfigs = Expression.Profiles.Append((Profile)Expression) .SelectMany(p => p.TypeMapConfigs, (profile, typeMap) => (profile, typeMap)) .GroupBy(x => x.typeMap.Types) .Where(g => g.Count() > 1) @@ -39,9 +32,9 @@ public void AssertConfigurationExpressionIsValid(IEnumerable typeMaps) throw new DuplicateTypeMapConfigurationException(duplicateTypeMapConfigs); } } - AssertConfigurationIsValid(typeMaps); + AssertConfigurationIsValid(config, typeMaps); } - public void AssertConfigurationIsValid(IEnumerable typeMaps) + public void AssertConfigurationIsValid(IGlobalConfiguration config, IEnumerable typeMaps) { var maps = typeMaps as TypeMap[] ?? typeMaps.ToArray(); var badTypeMaps = @@ -63,7 +56,7 @@ where unmappedPropertyNames.Length > 0 || !canConstruct { try { - DryRunTypeMap(typeMapsChecked, typeMap.Types, typeMap, null); + DryRunTypeMap(config, typeMapsChecked, typeMap.Types, typeMap, null); } catch (Exception e) { @@ -79,7 +72,7 @@ where unmappedPropertyNames.Length > 0 || !canConstruct throw configExceptions[0]; } } - private void DryRunTypeMap(ICollection typeMapsChecked, TypePair types, TypeMap typeMap, MemberMap memberMap) + private void DryRunTypeMap(IGlobalConfiguration config, ICollection typeMapsChecked, TypePair types, TypeMap typeMap, MemberMap memberMap) { if(typeMap == null) { @@ -87,7 +80,7 @@ private void DryRunTypeMap(ICollection typeMapsChecked, TypePair types, { return; } - typeMap = _config.ResolveTypeMap(types.SourceType, types.DestinationType); + typeMap = config.ResolveTypeMap(types.SourceType, types.DestinationType); } if (typeMap != null) { @@ -102,11 +95,11 @@ private void DryRunTypeMap(ICollection typeMapsChecked, TypePair types, { return; } - CheckPropertyMaps(typeMapsChecked, typeMap); + CheckPropertyMaps(config, typeMapsChecked, typeMap); } else { - var mapperToUse = _config.FindMapper(types); + var mapperToUse = config.FindMapper(types); if (mapperToUse == null) { throw new AutoMapperConfigurationException(memberMap.TypeMap.Types) { MemberMap = memberMap }; @@ -115,11 +108,11 @@ private void DryRunTypeMap(ICollection typeMapsChecked, TypePair types, Validate(context); if (mapperToUse.GetAssociatedTypes(types) is TypePair newTypes && newTypes != types) { - DryRunTypeMap(typeMapsChecked, newTypes, null, memberMap); + DryRunTypeMap(config, typeMapsChecked, newTypes, null, memberMap); } } } - private void CheckPropertyMaps(ICollection typeMapsChecked, TypeMap typeMap) + private void CheckPropertyMaps(IGlobalConfiguration config, ICollection typeMapsChecked, TypeMap typeMap) { foreach (var memberMap in typeMap.MemberMaps) { @@ -133,8 +126,7 @@ private void CheckPropertyMaps(ICollection typeMapsChecked, TypeMap typ { return; } - var destinationType = memberMap.DestinationType; - DryRunTypeMap(typeMapsChecked, new TypePair(sourceType, destinationType), null, memberMap); + DryRunTypeMap(config, typeMapsChecked, new(sourceType, memberMap.DestinationType), null, memberMap); } } } diff --git a/src/AutoMapper/Configuration/MapperConfiguration.cs b/src/AutoMapper/Configuration/MapperConfiguration.cs index e62bfd897d..4f6e226863 100644 --- a/src/AutoMapper/Configuration/MapperConfiguration.cs +++ b/src/AutoMapper/Configuration/MapperConfiguration.cs @@ -77,7 +77,7 @@ public MapperConfiguration(MapperConfigurationExpression configurationExpression } _mappers = configuration.Mappers.ToArray(); _executionPlans = new(CompileExecutionPlan); - _validator = new(this, configuration); + _validator = new(configuration); _projectionBuilder = new(this, configuration.ProjectionMappers.ToArray()); _serviceCtor = configuration.ServiceCtor; @@ -172,7 +172,7 @@ static MapperConfigurationExpression Build(Action _validator.AssertConfigurationExpressionIsValid(_configuredMaps.Values); + public void AssertConfigurationIsValid() => _validator.AssertConfigurationExpressionIsValid(this, _configuredMaps.Values); public IMapper CreateMapper() => new Mapper(this); public IMapper CreateMapper(Func serviceCtor) => new Mapper(this, serviceCtor); public void CompileMappings() @@ -478,14 +478,14 @@ IObjectMapper FindMapper(TypePair types) return null; } void IGlobalConfiguration.RegisterTypeMap(TypeMap typeMap) => _configuredMaps[typeMap.Types] = typeMap; - void IGlobalConfiguration.AssertConfigurationIsValid(TypeMap typeMap) => _validator.AssertConfigurationIsValid(new[] { typeMap }); + void IGlobalConfiguration.AssertConfigurationIsValid(TypeMap typeMap) => _validator.AssertConfigurationIsValid(this, new[] { typeMap }); void IGlobalConfiguration.AssertConfigurationIsValid(string profileName) { if (Profiles.All(x => x.Name != profileName)) { throw new ArgumentOutOfRangeException(nameof(profileName), $"Cannot find any profiles with the name '{profileName}'."); } - _validator.AssertConfigurationIsValid(_configuredMaps.Values.Where(typeMap => typeMap.Profile.Name == profileName)); + _validator.AssertConfigurationIsValid(this, _configuredMaps.Values.Where(typeMap => typeMap.Profile.Name == profileName)); } void IGlobalConfiguration.AssertConfigurationIsValid() => this.Internal().AssertConfigurationIsValid(typeof(TProfile).FullName); void IGlobalConfiguration.RegisterAsMap(TypeMapConfiguration typeMapConfiguration) => diff --git a/src/AutoMapper/Configuration/MapperConfigurationExpression.cs b/src/AutoMapper/Configuration/MapperConfigurationExpression.cs index ba24d4b667..71eb03c9eb 100644 --- a/src/AutoMapper/Configuration/MapperConfigurationExpression.cs +++ b/src/AutoMapper/Configuration/MapperConfigurationExpression.cs @@ -119,7 +119,7 @@ void IGlobalConfigurationExpression.Validator(Validator validator) => /// int IGlobalConfigurationExpression.MaxExecutionPlanDepth { get; set; } = 1; - List IGlobalConfigurationExpression.GetValidators() => _validators; + List IGlobalConfigurationExpression.Validators => _validators; List IGlobalConfigurationExpression.ProjectionMappers { get; } = ProjectionBuilder.DefaultProjectionMappers(); diff --git a/src/AutoMapper/Internal/InternalApi.cs b/src/AutoMapper/Internal/InternalApi.cs index 8add6a8881..fec22a306b 100644 --- a/src/AutoMapper/Internal/InternalApi.cs +++ b/src/AutoMapper/Internal/InternalApi.cs @@ -47,7 +47,7 @@ public interface IGlobalConfigurationExpression : IMapperConfigurationExpression /// See the docs for details. /// int MaxExecutionPlanDepth { get; set; } - List GetValidators(); + List Validators { get; } List ProjectionMappers { get; } /// /// How many levels deep should recursive queries be expanded. From 69257375ba5da244a7d05c701c10a0c294107652 Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Sun, 21 Aug 2022 11:43:27 +0300 Subject: [PATCH 37/67] use profiles in the benchmark --- src/Benchmark/FlatteningMapper.cs | 70 ++++++++++++++++++++----------- 1 file changed, 45 insertions(+), 25 deletions(-) diff --git a/src/Benchmark/FlatteningMapper.cs b/src/Benchmark/FlatteningMapper.cs index 85aa55d8a1..98c9c1d2f0 100644 --- a/src/Benchmark/FlatteningMapper.cs +++ b/src/Benchmark/FlatteningMapper.cs @@ -1,43 +1,63 @@ using System; using AutoMapper; - - +using System.Collections.Generic; +using System.Linq; namespace Benchmark.Flattening { - using System.Collections.Generic; - using System.Linq; static class Config { public static readonly IMapper Mapper = CreateMapper(); + class DeepTypeProfile : Profile + { + public DeepTypeProfile() + { + CreateMap(); + CreateMap(); + CreateMap(); + } + } + class ComplexTypesProfile : Profile + { + public ComplexTypesProfile() + { + CreateMap(); + CreateMap(); + } + } + class ConstructorProfile : Profile + { + public ConstructorProfile() => CreateMap(); + } + class FlatteningProfile : Profile + { + public FlatteningProfile() + { + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + } + } private static IMapper CreateMapper() { var config = new MapperConfiguration(cfg => { - cfg.CreateMap(); - cfg.CreateMap(); - cfg.CreateMap(); - - cfg.CreateMap(); - cfg.CreateMap(); - - cfg.CreateMap(); - - cfg.CreateMap(); - cfg.CreateMap(); - cfg.CreateMap(); - cfg.CreateMap(); - cfg.CreateMap(); - cfg.CreateMap(); - cfg.CreateMap(); - cfg.CreateMap(); - cfg.CreateMap(); - cfg.CreateMap(); - cfg.CreateMap(); + cfg.AddProfile(new DeepTypeProfile()); + cfg.AddProfile(new ComplexTypesProfile()); + cfg.AddProfile(new ConstructorProfile()); + cfg.AddProfile(new FlatteningProfile()); }); //config.AssertConfigurationIsValid(); return config.CreateMapper(); } - public static TDestination Map(TSource source) => Mapper.Map(source); + public static TDestination Map(TSource source) => Mapper.Map(source); } public class DeepTypeMapper : IObjectToObjectMapper { From 08ec72aec1c0008bd05982e35a898cddba7156cf Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Sun, 21 Aug 2022 13:13:08 +0300 Subject: [PATCH 38/67] simplify conventions --- src/AutoMapper/ApiCompatBaseline.txt | 17 +- src/AutoMapper/Configuration/Conventions.cs | 174 ++++++++++++++++++ .../Configuration/Conventions/Mappers.cs | 99 ---------- .../Conventions/MemberConfiguration.cs | 149 --------------- .../Configuration/INamingConvention.cs | 6 +- src/AutoMapper/Configuration/Profile.cs | 39 ++-- src/AutoMapper/Internal/InternalApi.cs | 4 +- src/AutoMapper/ProfileMap.cs | 30 +-- src/AutoMapper/TypeMap.cs | 4 +- src/UnitTests/Bug/NamingConventions.cs | 34 +--- src/UnitTests/Internal/TypeMapFactorySpecs.cs | 20 +- src/UnitTests/MapToAttributeTest.cs | 4 +- 12 files changed, 230 insertions(+), 350 deletions(-) create mode 100644 src/AutoMapper/Configuration/Conventions.cs delete mode 100644 src/AutoMapper/Configuration/Conventions/Mappers.cs delete mode 100644 src/AutoMapper/Configuration/Conventions/MemberConfiguration.cs diff --git a/src/AutoMapper/ApiCompatBaseline.txt b/src/AutoMapper/ApiCompatBaseline.txt index dc318ff2e7..a6ce2873f7 100644 --- a/src/AutoMapper/ApiCompatBaseline.txt +++ b/src/AutoMapper/ApiCompatBaseline.txt @@ -4,6 +4,7 @@ MembersMustExist : Member 'public System.Object System.Object AutoMapper.Context MembersMustExist : Member 'public System.Boolean AutoMapper.ContextCacheKey.Equals(AutoMapper.ContextCacheKey)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Boolean AutoMapper.ContextCacheKey.op_Equality(AutoMapper.ContextCacheKey, AutoMapper.ContextCacheKey)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Boolean AutoMapper.ContextCacheKey.op_Inequality(AutoMapper.ContextCacheKey, AutoMapper.ContextCacheKey)' does not exist in the implementation but it does exist in the contract. +CannotSealType : Type 'AutoMapper.ExactMatchNamingConvention' is actually (has the sealed modifier) sealed in the implementation but not sealed in the contract. MembersMustExist : Member 'public System.String AutoMapper.ExactMatchNamingConvention.ReplaceValue(System.Text.RegularExpressions.Match)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Text.RegularExpressions.Regex AutoMapper.ExactMatchNamingConvention.SplittingExpression.get()' does not exist in the implementation but it does exist in the contract. InterfacesShouldHaveSameMembers : Interface member 'public TMappingExpression AutoMapper.IMappingExpressionBase.AsProxy()' is present in the implementation but not in the contract. @@ -15,14 +16,19 @@ MembersMustExist : Member 'public System.String AutoMapper.INamingConvention.Rep InterfacesShouldHaveSameMembers : Interface member 'public System.String[] AutoMapper.INamingConvention.Split(System.String)' is present in the implementation but not in the contract. InterfacesShouldHaveSameMembers : Interface member 'public System.Text.RegularExpressions.Regex AutoMapper.INamingConvention.SplittingExpression.get()' is present in the contract but not in the implementation. MembersMustExist : Member 'public System.Text.RegularExpressions.Regex AutoMapper.INamingConvention.SplittingExpression.get()' does not exist in the implementation but it does exist in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public System.Collections.Generic.IReadOnlyCollection AutoMapper.IProfileConfiguration.MemberConfigurations' is present in the contract but not in the implementation. +InterfacesShouldHaveSameMembers : Interface member 'public System.Collections.Generic.IReadOnlyCollection AutoMapper.IProfileConfiguration.MemberConfigurations.get()' is present in the contract but not in the implementation. +MembersMustExist : Member 'public System.Collections.Generic.IReadOnlyCollection AutoMapper.IProfileConfiguration.MemberConfigurations.get()' does not exist in the implementation but it does exist in the contract. InterfacesShouldHaveSameMembers : Interface member 'public System.Collections.Generic.IReadOnlyCollection AutoMapper.IProfileConfiguration.OpenTypeMapConfigs.get()' is present in the implementation but not in the contract. InterfacesShouldHaveSameMembers : Interface member 'public System.Collections.Generic.IReadOnlyCollection AutoMapper.IProfileConfiguration.OpenTypeMapConfigs.get()' is present in the contract but not in the implementation. MembersMustExist : Member 'public System.Collections.Generic.IReadOnlyCollection AutoMapper.IProfileConfiguration.OpenTypeMapConfigs.get()' does not exist in the implementation but it does exist in the contract. InterfacesShouldHaveSameMembers : Interface member 'public System.Collections.Generic.IReadOnlyCollection AutoMapper.IProfileConfiguration.TypeMapConfigs.get()' is present in the implementation but not in the contract. InterfacesShouldHaveSameMembers : Interface member 'public System.Collections.Generic.IReadOnlyCollection AutoMapper.IProfileConfiguration.TypeMapConfigs.get()' is present in the contract but not in the implementation. MembersMustExist : Member 'public System.Collections.Generic.IReadOnlyCollection AutoMapper.IProfileConfiguration.TypeMapConfigs.get()' does not exist in the implementation but it does exist in the contract. +CannotSealType : Type 'AutoMapper.LowerUnderscoreNamingConvention' is actually (has the sealed modifier) sealed in the implementation but not sealed in the contract. MembersMustExist : Member 'public System.String AutoMapper.LowerUnderscoreNamingConvention.ReplaceValue(System.Text.RegularExpressions.Match)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Text.RegularExpressions.Regex AutoMapper.LowerUnderscoreNamingConvention.SplittingExpression.get()' does not exist in the implementation but it does exist in the contract. +CannotSealType : Type 'AutoMapper.PascalCaseNamingConvention' is actually (has the sealed modifier) sealed in the implementation but not sealed in the contract. MembersMustExist : Member 'public System.String AutoMapper.PascalCaseNamingConvention.ReplaceValue(System.Text.RegularExpressions.Match)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Text.RegularExpressions.Regex AutoMapper.PascalCaseNamingConvention.SplittingExpression.get()' does not exist in the implementation but it does exist in the contract. CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.CompilerGeneratedAttribute' exists on 'AutoMapper.Profile.DestinationMemberNamingConvention.get()' in the contract but not the implementation. @@ -50,8 +56,17 @@ CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'AutoMappe CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'AutoMapper.Configuration.Annotations.UseExistingValueAttribute' changed from '[AttributeUsageAttribute(384)]' in the contract to '[AttributeUsageAttribute(AttributeTargets.Field | AttributeTargets.Property)]' in the implementation. CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'AutoMapper.Configuration.Annotations.ValueConverterAttribute' changed from '[AttributeUsageAttribute(384)]' in the contract to '[AttributeUsageAttribute(AttributeTargets.Field | AttributeTargets.Property)]' in the implementation. CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'AutoMapper.Configuration.Annotations.ValueResolverAttribute' changed from '[AttributeUsageAttribute(384)]' in the contract to '[AttributeUsageAttribute(AttributeTargets.Field | AttributeTargets.Property)]' in the implementation. +TypesMustExist : Type 'AutoMapper.Configuration.Conventions.DefaultName' does not exist in the implementation but it does exist in the contract. +TypesMustExist : Type 'AutoMapper.Configuration.Conventions.IParentSourceToDestinationNameMapper' does not exist in the implementation but it does exist in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public System.Reflection.MemberInfo AutoMapper.Configuration.Conventions.ISourceToDestinationNameMapper.GetMatchingMemberInfo(AutoMapper.Internal.TypeDetails, System.Type, System.Type, System.String)' is present in the contract but not in the implementation. +MembersMustExist : Member 'public System.Reflection.MemberInfo AutoMapper.Configuration.Conventions.ISourceToDestinationNameMapper.GetMatchingMemberInfo(AutoMapper.Internal.TypeDetails, System.Type, System.Type, System.String)' does not exist in the implementation but it does exist in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public System.Reflection.MemberInfo AutoMapper.Configuration.Conventions.ISourceToDestinationNameMapper.GetSourceMember(AutoMapper.Internal.TypeDetails, System.Type, System.Type, System.String)' is present in the implementation but not in the contract. +TypesMustExist : Type 'AutoMapper.Configuration.Conventions.ParentSourceToDestinationNameMapper' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public System.Reflection.MemberInfo AutoMapper.Configuration.Conventions.PrePostfixName.GetMatchingMemberInfo(AutoMapper.Internal.TypeDetails, System.Type, System.Type, System.String)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Collections.Generic.List AutoMapper.Configuration.Conventions.PrePostfixName.Postfixes.get()' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Collections.Generic.List AutoMapper.Configuration.Conventions.PrePostfixName.Prefixes.get()' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public AutoMapper.Configuration.Conventions.ReplaceName AutoMapper.Configuration.Conventions.ReplaceName.AddReplace(System.String, System.String)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public System.Reflection.MemberInfo AutoMapper.Configuration.Conventions.ReplaceName.GetMatchingMemberInfo(AutoMapper.Internal.TypeDetails, System.Type, System.Type, System.String)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Linq.Expressions.Expression System.Linq.Expressions.Expression AutoMapper.Execution.Member.Expression' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Linq.Expressions.Expression System.Linq.Expressions.Expression AutoMapper.Execution.Member.Target' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Reflection.MemberInfo System.Reflection.MemberInfo AutoMapper.Execution.Member.MemberInfo' does not exist in the implementation but it does exist in the contract. @@ -94,4 +109,4 @@ MembersMustExist : Member 'public AutoMapper.Internal.TypePair AutoMapper.Intern MembersMustExist : Member 'public System.Linq.IQueryable AutoMapper.QueryableExtensions.Extensions.Map(System.Linq.IQueryable, System.Linq.IQueryable, AutoMapper.IConfigurationProvider)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Collections.Generic.IReadOnlyCollection AutoMapper.QueryableExtensions.MemberVisitor.MemberPath.get()' does not exist in the implementation but it does exist in the contract. TypesMustExist : Type 'AutoMapper.QueryableExtensions.Impl.MemberAccessQueryMapperVisitor' does not exist in the implementation but it does exist in the contract. -Total Issues: 95 +Total Issues: 110 diff --git a/src/AutoMapper/Configuration/Conventions.cs b/src/AutoMapper/Configuration/Conventions.cs new file mode 100644 index 0000000000..682e890782 --- /dev/null +++ b/src/AutoMapper/Configuration/Conventions.cs @@ -0,0 +1,174 @@ +using AutoMapper.Internal; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Reflection; +namespace AutoMapper.Configuration.Conventions +{ + public interface ISourceToDestinationNameMapper + { + MemberInfo GetSourceMember(TypeDetails sourceTypeDetails, Type destType, Type destMemberType, string nameToSearch); + } + [EditorBrowsable(EditorBrowsableState.Never)] + public class MemberConfiguration + { + NameSplitMember _nameSplitMember; + public INamingConvention SourceMemberNamingConvention { get; set; } = PascalCaseNamingConvention.Instance; + public INamingConvention DestinationMemberNamingConvention { get; set; } = PascalCaseNamingConvention.Instance; + public List NameToMemberMappers { get; } = new(); + public bool IsMatch(ProfileMap options, TypeDetails sourceTypeDetails, Type destType, Type destMemberType, string nameToSearch, List resolvers, bool isReverseMap) + { + var matchingMemberInfo = GetSourceMember(sourceTypeDetails, destType, destMemberType, nameToSearch); + if (matchingMemberInfo != null) + { + resolvers.Add(matchingMemberInfo); + return true; + } + return nameToSearch.Length == 0 || _nameSplitMember.IsMatch(options, sourceTypeDetails, destType, destMemberType, nameToSearch, resolvers, isReverseMap); + } + public MemberInfo GetSourceMember(TypeDetails sourceTypeDetails, Type destType, Type destMemberType, string nameToSearch) + { + var sourceMember = sourceTypeDetails.GetMember(nameToSearch); + if (sourceMember != null) + { + return sourceMember; + } + foreach (var namedMapper in NameToMemberMappers) + { + if ((sourceMember = namedMapper.GetSourceMember(sourceTypeDetails, destType, destMemberType, nameToSearch)) != null) + { + return sourceMember; + } + } + return null; + } + public void Seal() + { + var isDefault = SourceMemberNamingConvention == PascalCaseNamingConvention.Instance && DestinationMemberNamingConvention == PascalCaseNamingConvention.Instance; + _nameSplitMember = isDefault ? new DefaultNameSplitMember() : new ConventionsNameSplitMember(); + _nameSplitMember.Parent = this; + } + } + public class PrePostfixName : ISourceToDestinationNameMapper + { + public List DestinationPrefixes { get; } = new(); + public List DestinationPostfixes { get; } = new(); + public MemberInfo GetSourceMember(TypeDetails sourceTypeDetails, Type destType, Type destMemberType, string nameToSearch) + { + MemberInfo member; + foreach (var possibleSourceName in TypeDetails.PossibleNames(nameToSearch, DestinationPrefixes, DestinationPostfixes)) + { + if ((member = sourceTypeDetails.GetMember(possibleSourceName)) != null) + { + return member; + } + } + return null; + } + } + public class ReplaceName : ISourceToDestinationNameMapper + { + public List MemberNameReplacers { get; } = new(); + public MemberInfo GetSourceMember(TypeDetails sourceTypeDetails, Type destType, Type destMemberType, string nameToSearch) + { + var possibleSourceNames = PossibleNames(nameToSearch); + if (possibleSourceNames.Length == 0) + { + return null; + } + var possibleDestNames = sourceTypeDetails.ReadAccessors.Select(mi => (mi, possibles : PossibleNames(mi.Name))).ToArray(); + foreach (var sourceName in possibleSourceNames) + { + foreach (var (mi, possibles) in possibleDestNames) + { + if (possibles.Contains(sourceName, StringComparer.OrdinalIgnoreCase)) + { + return mi; + } + } + } + return null; + } + private string[] PossibleNames(string nameToSearch) => + MemberNameReplacers.Select(r => nameToSearch.Replace(r.OriginalValue, r.NewValue)) + .Concat(new[] { MemberNameReplacers.Aggregate(nameToSearch, (s, r) => s.Replace(r.OriginalValue, r.NewValue)), nameToSearch }) + .ToArray(); + } + [EditorBrowsable(EditorBrowsableState.Never)] + public readonly record struct MemberNameReplacer(string OriginalValue, string NewValue); + [EditorBrowsable(EditorBrowsableState.Never)] + public abstract class NameSplitMember + { + public MemberConfiguration Parent { get; set; } + public abstract bool IsMatch(ProfileMap options, TypeDetails sourceType, Type destType, Type destMemberType, string nameToSearch, List resolvers, bool isReverseMap); + } + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class DefaultNameSplitMember : NameSplitMember + { + public sealed override bool IsMatch(ProfileMap options, TypeDetails sourceType, Type destType, Type destMemberType, string nameToSearch, List resolvers, bool isReverseMap) + { + MemberInfo matchingMemberInfo = null; + int index = 1; + for (; index < nameToSearch.Length; index++) + { + if (char.IsUpper(nameToSearch[index]) && Found()) + { + return true; + } + } + return matchingMemberInfo != null && Found(); + bool Found() + { + var first = nameToSearch[..index]; + matchingMemberInfo = Parent.GetSourceMember(sourceType, destType, destMemberType, first); + if (matchingMemberInfo == null) + { + return false; + } + resolvers.Add(matchingMemberInfo); + var second = nameToSearch[index..]; + var details = options.CreateTypeDetails(matchingMemberInfo.GetMemberType()); + if (Parent.IsMatch(options, details, destType, destMemberType, second, resolvers, isReverseMap)) + { + return true; + } + resolvers.RemoveAt(resolvers.Count - 1); + return false; + } + } + } + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class ConventionsNameSplitMember : NameSplitMember + { + public sealed override bool IsMatch(ProfileMap options, TypeDetails sourceType, Type destType, Type destMemberType, string nameToSearch, List resolvers, bool isReverseMap) + { + var destinationMemberNamingConvention = isReverseMap ? Parent.SourceMemberNamingConvention : Parent.DestinationMemberNamingConvention; + var matches = destinationMemberNamingConvention.Split(nameToSearch); + var length = matches.Length; + if (length < 2) + { + return false; + } + var sourceMemberNamingConvention = isReverseMap ? Parent.DestinationMemberNamingConvention : Parent.SourceMemberNamingConvention; + var separator = sourceMemberNamingConvention.SeparatorCharacter; + for (var index = 1; index <= length; index++) + { + var first = string.Join(separator, matches, 0, index); + var matchingMemberInfo = Parent.GetSourceMember(sourceType, destType, destMemberType, first); + if (matchingMemberInfo != null) + { + resolvers.Add(matchingMemberInfo); + var second = string.Join(separator, matches, index, length - index); + var details = options.CreateTypeDetails(matchingMemberInfo.GetMemberType()); + if (Parent.IsMatch(options, details, destType, destMemberType, second, resolvers, isReverseMap)) + { + return true; + } + resolvers.RemoveAt(resolvers.Count - 1); + } + } + return false; + } + } +} \ No newline at end of file diff --git a/src/AutoMapper/Configuration/Conventions/Mappers.cs b/src/AutoMapper/Configuration/Conventions/Mappers.cs deleted file mode 100644 index f3100b4d19..0000000000 --- a/src/AutoMapper/Configuration/Conventions/Mappers.cs +++ /dev/null @@ -1,99 +0,0 @@ -using AutoMapper.Internal; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -namespace AutoMapper.Configuration.Conventions -{ - public interface ISourceToDestinationNameMapper - { - MemberInfo GetMatchingMemberInfo(TypeDetails sourceTypeDetails, Type destType, Type destMemberType, string nameToSearch); - } - public interface IParentSourceToDestinationNameMapper - { - List NamedMappers { get; } - MemberInfo GetMatchingMemberInfo(TypeDetails sourceTypeDetails, Type destType, Type destMemberType, string nameToSearch); - } - public sealed class DefaultName : ISourceToDestinationNameMapper - { - public MemberInfo GetMatchingMemberInfo(TypeDetails sourceTypeDetails, Type destType, Type destMemberType, string nameToSearch) => sourceTypeDetails.GetMember(nameToSearch); - } - public class ParentSourceToDestinationNameMapper : IParentSourceToDestinationNameMapper - { - public List NamedMappers { get; } = new(){ new DefaultName() }; - public MemberInfo GetMatchingMemberInfo(TypeDetails sourceTypeDetails, Type destType, Type destMemberType, string nameToSearch) - { - foreach (var namedMapper in NamedMappers) - { - var memberInfo = namedMapper.GetMatchingMemberInfo(sourceTypeDetails, destType, destMemberType, nameToSearch); - if (memberInfo != null) - { - return memberInfo; - } - } - return null; - } - } - public class PrePostfixName : ISourceToDestinationNameMapper - { - public List DestinationPrefixes { get; } = new(); - public List DestinationPostfixes { get; } = new(); - public MemberInfo GetMatchingMemberInfo(TypeDetails sourceTypeDetails, Type destType, Type destMemberType, string nameToSearch) - { - MemberInfo member; - foreach (var possibleSourceName in TypeDetails.PossibleNames(nameToSearch, DestinationPrefixes, DestinationPostfixes)) - { - if ((member = sourceTypeDetails.GetMember(possibleSourceName)) != null) - { - return member; - } - } - return null; - } - } - public class ReplaceName : ISourceToDestinationNameMapper - { - private readonly List _memberNameReplacers = new(); - - public ReplaceName AddReplace(string original, string newValue) - { - _memberNameReplacers.Add(new(original, newValue)); - return this; - } - public MemberInfo GetMatchingMemberInfo(TypeDetails sourceTypeDetails, Type destType, Type destMemberType, string nameToSearch) - { - var possibleSourceNames = PossibleNames(nameToSearch); - if (possibleSourceNames.Length == 0) - { - return null; - } - var possibleDestNames = sourceTypeDetails.ReadAccessors.Select(mi => (mi, possibles : PossibleNames(mi.Name))).ToArray(); - foreach (var sourceName in possibleSourceNames) - { - foreach (var (mi, possibles) in possibleDestNames) - { - if (possibles.Contains(sourceName, StringComparer.OrdinalIgnoreCase)) - { - return mi; - } - } - } - return null; - } - private string[] PossibleNames(string nameToSearch) => - _memberNameReplacers.Select(r => nameToSearch.Replace(r.OriginalValue, r.NewValue)) - .Concat(new[] { _memberNameReplacers.Aggregate(nameToSearch, (s, r) => s.Replace(r.OriginalValue, r.NewValue)), nameToSearch }) - .ToArray(); - } - public class MemberNameReplacer - { - public MemberNameReplacer(string originalValue, string newValue) - { - OriginalValue = originalValue; - NewValue = newValue; - } - - public string OriginalValue { get; } - public string NewValue { get; } - } -} \ No newline at end of file diff --git a/src/AutoMapper/Configuration/Conventions/MemberConfiguration.cs b/src/AutoMapper/Configuration/Conventions/MemberConfiguration.cs deleted file mode 100644 index 16f4b2996d..0000000000 --- a/src/AutoMapper/Configuration/Conventions/MemberConfiguration.cs +++ /dev/null @@ -1,149 +0,0 @@ -using AutoMapper.Internal; -using System; -using System.Collections; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; -using System.Reflection; -namespace AutoMapper.Configuration.Conventions -{ - [EditorBrowsable(EditorBrowsableState.Never)] - public interface IMemberConfiguration - { - List MemberMappers { get; } - IMemberConfiguration AddMember(Action setupAction = null) where TMemberMapper : IChildMemberConfiguration, new(); - IMemberConfiguration AddName(Action setupAction = null) where TNameMapper : ISourceToDestinationNameMapper, new(); - IParentSourceToDestinationNameMapper NameMapper { get; set; } - bool MapDestinationPropertyToSource(ProfileMap options, TypeDetails sourceType, Type destType, Type destMemberType, string nameToSearch, List resolvers, bool isReverseMap); - } - [EditorBrowsable(EditorBrowsableState.Never)] - public interface IChildMemberConfiguration - { - bool MapDestinationPropertyToSource(ProfileMap options, TypeDetails sourceType, Type destType, Type destMemberType, string nameToSearch, List resolvers, IMemberConfiguration parent, bool isReverseMap); - } - [EditorBrowsable(EditorBrowsableState.Never)] - public class DefaultMember : IChildMemberConfiguration - { - public IParentSourceToDestinationNameMapper NameMapper { get; set; } - public bool MapDestinationPropertyToSource(ProfileMap options, TypeDetails sourceTypeDetails, Type destType, Type destMemberType, string nameToSearch, List resolvers, IMemberConfiguration parent = null, bool isReverseMap = false) - { - var matchingMemberInfo = NameMapper.GetMatchingMemberInfo(sourceTypeDetails, destType, destMemberType, nameToSearch); - if (matchingMemberInfo != null) - { - resolvers.Add(matchingMemberInfo); - return true; - } - return nameToSearch.Length == 0; - } - } - [EditorBrowsable(EditorBrowsableState.Never)] - public class MemberConfiguration : IMemberConfiguration - { - public IParentSourceToDestinationNameMapper NameMapper { get; set; } - public List MemberMappers { get; } = new(); - public IMemberConfiguration AddMember(Action setupAction = null) where TMemberMapper : IChildMemberConfiguration, new() => - GetOrAdd(MemberMappers, setupAction); - public IMemberConfiguration AddName(Action setupAction = null) where TNameMapper : ISourceToDestinationNameMapper, new() => - GetOrAdd(NameMapper.NamedMappers, setupAction); - private IMemberConfiguration GetOrAdd(IList list, Action setupAction = null) where TMemberMapper : new() - { - var child = list.OfType().FirstOrDefault(); - if (child == null) - { - child = new(); - list.Add(child); - } - setupAction?.Invoke(child); - return this; - } - public MemberConfiguration() - { - NameMapper = new ParentSourceToDestinationNameMapper(); - MemberMappers.Add(new DefaultMember { NameMapper = NameMapper }); - } - public bool MapDestinationPropertyToSource(ProfileMap options, TypeDetails sourceType, Type destType, Type destMemberType, string nameToSearch, List resolvers, bool isReverseMap) - { - foreach (var memberMapper in MemberMappers) - { - if (memberMapper.MapDestinationPropertyToSource(options, sourceType, destType, destMemberType, nameToSearch, resolvers, this, isReverseMap)) - { - return true; - } - } - return false; - } - } - [EditorBrowsable(EditorBrowsableState.Never)] - public class NameSplitMember : IChildMemberConfiguration - { - bool _default = true; - public INamingConvention SourceMemberNamingConvention { get; set; } = PascalCaseNamingConvention.Instance; - public INamingConvention DestinationMemberNamingConvention { get; set; } = PascalCaseNamingConvention.Instance; - public bool MapDestinationPropertyToSource(ProfileMap options, TypeDetails sourceType, Type destType, Type destMemberType, string nameToSearch, List resolvers, IMemberConfiguration parent, bool isReverseMap) => - _default ? - Default(options, sourceType, destType, destMemberType, nameToSearch, resolvers, parent, isReverseMap) : - Conventions(options, sourceType, destType, destMemberType, nameToSearch, resolvers, parent, isReverseMap); - bool Default(ProfileMap options, TypeDetails sourceType, Type destType, Type destMemberType, string nameToSearch, List resolvers, IMemberConfiguration parent, bool isReverseMap) - { - MemberInfo matchingMemberInfo = null; - int index = 1; - for (; index < nameToSearch.Length; index++) - { - if (char.IsUpper(nameToSearch[index]) && Found()) - { - return true; - } - } - return matchingMemberInfo != null && Found(); - bool Found() - { - var first = nameToSearch[..index]; - matchingMemberInfo = parent.NameMapper.GetMatchingMemberInfo(sourceType, destType, destMemberType, first); - if (matchingMemberInfo == null) - { - return false; - } - resolvers.Add(matchingMemberInfo); - var second = nameToSearch[index..]; - var details = options.CreateTypeDetails(matchingMemberInfo.GetMemberType()); - if (parent.MapDestinationPropertyToSource(options, details, destType, destMemberType, second, resolvers, isReverseMap)) - { - return true; - } - resolvers.RemoveAt(resolvers.Count - 1); - return false; - } - } - bool Conventions(ProfileMap options, TypeDetails sourceType, Type destType, Type destMemberType, string nameToSearch, List resolvers, IMemberConfiguration parent, bool isReverseMap) - { - var destinationMemberNamingConvention = isReverseMap ? SourceMemberNamingConvention : DestinationMemberNamingConvention; - var matches = destinationMemberNamingConvention.Split(nameToSearch); - var length = matches.Length; - if (length < 2) - { - return false; - } - var sourceMemberNamingConvention = isReverseMap ? DestinationMemberNamingConvention : SourceMemberNamingConvention; - var separator = sourceMemberNamingConvention.SeparatorCharacter; - for (var index = 1; index <= length; index++) - { - var first = string.Join(separator, matches, 0, index); - var matchingMemberInfo = parent.NameMapper.GetMatchingMemberInfo(sourceType, destType, destMemberType, first); - if (matchingMemberInfo != null) - { - resolvers.Add(matchingMemberInfo); - var details = options.CreateTypeDetails(matchingMemberInfo.GetMemberType()); - var second = string.Join(separator, matches, index, length - index); - if (parent.MapDestinationPropertyToSource(options, details, destType, destMemberType, second, resolvers, isReverseMap)) - { - return true; - } - resolvers.RemoveAt(resolvers.Count - 1); - } - } - return false; - } - internal void Seal() => _default = SourceMemberNamingConvention == PascalCaseNamingConvention.Instance && - DestinationMemberNamingConvention == PascalCaseNamingConvention.Instance; - } -} \ No newline at end of file diff --git a/src/AutoMapper/Configuration/INamingConvention.cs b/src/AutoMapper/Configuration/INamingConvention.cs index c724fd107d..ba8e1e4de4 100644 --- a/src/AutoMapper/Configuration/INamingConvention.cs +++ b/src/AutoMapper/Configuration/INamingConvention.cs @@ -10,13 +10,13 @@ public interface INamingConvention string[] Split(string input); string SeparatorCharacter { get; } } - public class ExactMatchNamingConvention : INamingConvention + public sealed class ExactMatchNamingConvention : INamingConvention { public static readonly ExactMatchNamingConvention Instance = new(); public string[] Split(string _) => Array.Empty(); public string SeparatorCharacter => null; } - public class PascalCaseNamingConvention : INamingConvention + public sealed class PascalCaseNamingConvention : INamingConvention { public static readonly PascalCaseNamingConvention Instance = new(); public string SeparatorCharacter => ""; @@ -41,7 +41,7 @@ public string[] Split(string input) return result.ToArray(); } } - public class LowerUnderscoreNamingConvention : INamingConvention + public sealed class LowerUnderscoreNamingConvention : INamingConvention { public static readonly LowerUnderscoreNamingConvention Instance = new(); public string SeparatorCharacter => "_"; diff --git a/src/AutoMapper/Configuration/Profile.cs b/src/AutoMapper/Configuration/Profile.cs index c25306c0ea..4d4f8106cc 100644 --- a/src/AutoMapper/Configuration/Profile.cs +++ b/src/AutoMapper/Configuration/Profile.cs @@ -11,7 +11,6 @@ namespace AutoMapper using static Execution.ExpressionBuilder; public interface IProfileConfiguration { - IReadOnlyCollection MemberConfigurations { get; } bool? FieldMappingEnabled { get; } bool? MethodMappingEnabled { get; } bool? ConstructorMappingEnabled { get; } @@ -67,8 +66,8 @@ public abstract class Profile : IProfileExpressionInternal, IProfileConfiguratio private readonly List _postfixes = new(); private readonly List _typeMapConfigs = new(); private readonly PrePostfixName _prePostfixName = new(); - private readonly NameSplitMember _nameSplitMember = new(); - private readonly List _memberConfigurations; + private ReplaceName _replaceName; + private readonly MemberConfiguration _memberConfiguration; private List> _allPropertyMapActions; private List> _allTypeMapActions; private List _globalIgnores; @@ -80,13 +79,10 @@ public abstract class Profile : IProfileExpressionInternal, IProfileConfiguratio protected Profile() { ProfileName = GetType().FullName; - MemberConfiguration memberConfiguration = new() { MemberMappers = { _nameSplitMember } }; - memberConfiguration.NameMapper.NamedMappers.Add(_prePostfixName); - _memberConfigurations = new() { memberConfiguration }; + _memberConfiguration = new(){ NameToMemberMappers = { _prePostfixName } }; } protected Profile(string profileName, Action configurationAction) : this(profileName) => configurationAction(this); - IMemberConfiguration DefaultMemberConfig => _memberConfigurations[0]; - IMemberConfiguration IProfileExpressionInternal.DefaultMemberConfig => DefaultMemberConfig; + MemberConfiguration IProfileExpressionInternal.MemberConfiguration => _memberConfiguration; bool? IProfileConfiguration.ConstructorMappingEnabled => _constructorMappingEnabled; bool? IProfileExpressionInternal.MethodMappingEnabled { get; set; } bool? IProfileConfiguration.MethodMappingEnabled => this.Internal().MethodMappingEnabled; @@ -97,7 +93,6 @@ IReadOnlyCollection> IProfil => _allPropertyMapActions.NullCheck(); IReadOnlyCollection> IProfileConfiguration.AllTypeMapActions => _allTypeMapActions.NullCheck(); IReadOnlyCollection IProfileConfiguration.GlobalIgnores => _globalIgnores.NullCheck(); - IReadOnlyCollection IProfileConfiguration.MemberConfigurations => _memberConfigurations; IReadOnlyCollection IProfileConfiguration.SourceExtensionMethods => _sourceExtensionMethods.NullCheck(); IReadOnlyCollection IProfileConfiguration.TypeMapConfigs => _typeMapConfigs; IReadOnlyCollection IProfileConfiguration.OpenTypeMapConfigs => _openTypeMapConfigs.NullCheck(); @@ -113,16 +108,15 @@ IReadOnlyCollection> IProfil public Func ShouldUseConstructor { get; set; } public INamingConvention SourceMemberNamingConvention { - get => _nameSplitMember.SourceMemberNamingConvention; - set => _nameSplitMember.SourceMemberNamingConvention = value; + get => _memberConfiguration.SourceMemberNamingConvention; + set => _memberConfiguration.SourceMemberNamingConvention = value; } public INamingConvention DestinationMemberNamingConvention { - get => _nameSplitMember.DestinationMemberNamingConvention; - set => _nameSplitMember.DestinationMemberNamingConvention = value; + get => _memberConfiguration.DestinationMemberNamingConvention; + set => _memberConfiguration.DestinationMemberNamingConvention = value; } public List ValueTransformers => _valueTransformerConfigs ??= new(); - NameSplitMember IProfileExpressionInternal.NameSplitMember => _nameSplitMember; List IProfileExpressionInternal.Prefixes => _prefixes; List IProfileExpressionInternal.Postfixes => _postfixes; public void DisableConstructorMapping() => _constructorMappingEnabled = false; @@ -172,8 +166,15 @@ public IMappingExpression CreateMap(Type sourceType, Type destinationType, Membe return map; } public void ClearPrefixes() => _prefixes.Clear(); - public void ReplaceMemberName(string original, string newValue) => - DefaultMemberConfig.AddName(_ => _.AddReplace(original, newValue)); + public void ReplaceMemberName(string original, string newValue) + { + if (_replaceName == null) + { + _replaceName = new(); + _memberConfiguration.NameToMemberMappers.Add(_replaceName); + } + _replaceName.MemberNameReplacers.Add(new(original, newValue)); + } public void RecognizePrefixes(params string[] prefixes) => _prefixes.AddRange(prefixes); public void RecognizePostfixes(params string[] postfixes) => _postfixes.AddRange(postfixes); public void RecognizeDestinationPrefixes(params string[] prefixes) => _prePostfixName.DestinationPrefixes.AddRange(prefixes); @@ -183,12 +184,6 @@ public void AddGlobalIgnore(string propertyNameStartingWith) _globalIgnores ??= new(); _globalIgnores.Add(propertyNameStartingWith); } - IMemberConfiguration IProfileExpressionInternal.AddMemberConfiguration() - { - var condition = new MemberConfiguration(); - _memberConfigurations.Add(condition); - return condition; - } public void IncludeSourceExtensionMethods(Type type) { _sourceExtensionMethods ??= new(); diff --git a/src/AutoMapper/Internal/InternalApi.cs b/src/AutoMapper/Internal/InternalApi.cs index fec22a306b..beaf3a7cf7 100644 --- a/src/AutoMapper/Internal/InternalApi.cs +++ b/src/AutoMapper/Internal/InternalApi.cs @@ -166,11 +166,9 @@ public interface IGlobalConfiguration : IConfigurationProvider [EditorBrowsable(EditorBrowsableState.Never)] public interface IProfileExpressionInternal : IProfileExpression { - NameSplitMember NameSplitMember { get; } List Prefixes { get; } List Postfixes { get; } - IMemberConfiguration DefaultMemberConfig { get; } - IMemberConfiguration AddMemberConfiguration(); + MemberConfiguration MemberConfiguration { get; } /// /// Allows to enable null-value propagation for query mapping. /// Some providers (such as EntityFrameworkQueryVisitor) do not work with this feature enabled! diff --git a/src/AutoMapper/ProfileMap.cs b/src/AutoMapper/ProfileMap.cs index a3aac95168..1995917b73 100644 --- a/src/AutoMapper/ProfileMap.cs +++ b/src/AutoMapper/ProfileMap.cs @@ -22,7 +22,6 @@ public class ProfileMap private Dictionary _openTypeMapConfigs; private Dictionary _typeDetails; private ConcurrentDictionaryWrapper _runtimeTypeDetails; - private readonly IMemberConfiguration[] _memberConfigurations; public ProfileMap(IProfileConfiguration profile, IGlobalConfigurationExpression configuration = null) { var globalProfile = (IProfileConfiguration)configuration; @@ -38,14 +37,15 @@ public ProfileMap(IProfileConfiguration profile, IGlobalConfigurationExpression ShouldMapMethod = profile.ShouldMapMethod ?? configuration?.ShouldMapMethod ?? (p => !p.IsSpecialName); ShouldUseConstructor = profile.ShouldUseConstructor ?? configuration?.ShouldUseConstructor ?? (c => true); ValueTransformers = profile.ValueTransformers.Concat(configuration?.ValueTransformers).ToArray(); - _memberConfigurations = profile.MemberConfigurations.Concat(globalProfile?.MemberConfigurations).ToArray(); + var profileInternal = (IProfileExpressionInternal)profile; + MemberConfiguration = profileInternal.MemberConfiguration; + GlobalMemberConfiguration = configuration.Internal()?.MemberConfiguration; var globalIgnores = profile.GlobalIgnores.Concat(globalProfile?.GlobalIgnores); GlobalIgnores = globalIgnores == Array.Empty() ? EmptyHashSet : new HashSet(globalIgnores); SourceExtensionMethods = profile.SourceExtensionMethods.Concat(globalProfile?.SourceExtensionMethods).ToArray(); AllPropertyMapActions = profile.AllPropertyMapActions.Concat(globalProfile?.AllPropertyMapActions).ToArray(); AllTypeMapActions = profile.AllTypeMapActions.Concat(globalProfile?.AllTypeMapActions).ToArray(); - var profileInternal = (IProfileExpressionInternal)profile; - profileInternal.NameSplitMember.Seal(); + profileInternal.MemberConfiguration.Seal(); Prefixes = profileInternal.Prefixes.Concat(configuration?.Prefixes).Distinct().ToList(); Postfixes = profileInternal.Postfixes.Concat(configuration?.Postfixes).Distinct().ToList(); TypeMapConfigs(); @@ -103,7 +103,8 @@ internal void Clear() public IEnumerable> AllPropertyMapActions { get; } public IEnumerable> AllTypeMapActions { get; } public HashSet GlobalIgnores { get; } - public IEnumerable MemberConfigurations => _memberConfigurations; + public MemberConfiguration MemberConfiguration { get; } + public MemberConfiguration GlobalMemberConfiguration { get; } public IEnumerable SourceExtensionMethods { get; } public List Prefixes { get; } public List Postfixes { get; } @@ -253,21 +254,10 @@ private void ApplyDerivedMaps(TypeMap baseMap, TypeMap typeMap, IGlobalConfigura ApplyDerivedMaps(baseMap, derivedMap, configuration); } } - public bool MapDestinationPropertyToSource(TypeDetails sourceTypeDetails, Type destType, Type destMemberType, string destMemberName, List members, bool reverseNamingConventions) - { - if(destMemberName == null) - { - return false; - } - foreach (var memberConfiguration in _memberConfigurations) - { - if (memberConfiguration.MapDestinationPropertyToSource(this, sourceTypeDetails, destType, destMemberType, destMemberName, members, reverseNamingConventions)) - { - return true; - } - } - return false; - } + public bool MapDestinationPropertyToSource(TypeDetails sourceTypeDetails, Type destType, Type destMemberType, string destMemberName, List members, bool reverseNamingConventions) => + destMemberName != null && + (MemberConfiguration.IsMatch(this, sourceTypeDetails, destType, destMemberType, destMemberName, members, reverseNamingConventions) || + GlobalMemberConfiguration?.IsMatch(this, sourceTypeDetails, destType, destMemberType, destMemberName, members, reverseNamingConventions) is true); public bool AllowsNullDestinationValuesFor(MemberMap memberMap = null) => memberMap?.AllowNull ?? AllowNullDestinationValues; public bool AllowsNullCollectionsFor(MemberMap memberMap = null) => memberMap?.AllowNull ?? AllowNullCollections; } diff --git a/src/AutoMapper/TypeMap.cs b/src/AutoMapper/TypeMap.cs index c56ec53b65..142bcb93b9 100644 --- a/src/AutoMapper/TypeMap.cs +++ b/src/AutoMapper/TypeMap.cs @@ -35,6 +35,7 @@ public TypeMap(Type sourceType, Type destinationType, ProfileMap profile, TypeMa SourceTypeDetails = profile.CreateTypeDetails(sourceType); DestinationTypeDetails = profile.CreateTypeDetails(destinationType); sourceMembers ??= new(); + var isReverseMap = typeMapConfiguration?.IsReverseMap is true; foreach (var destinationProperty in DestinationTypeDetails.WriteAccessors) { var destinationName = destinationProperty.Name; @@ -45,8 +46,7 @@ public TypeMap(Type sourceType, Type destinationType, ProfileMap profile, TypeMa } sourceMembers.Clear(); var propertyType = destinationProperty.GetMemberType(); - if (profile.MapDestinationPropertyToSource(SourceTypeDetails, destinationType, propertyType, destinationName, sourceMembers, - typeMapConfiguration?.IsReverseMap is true)) + if (profile.MapDestinationPropertyToSource(SourceTypeDetails, destinationType, propertyType, destinationName, sourceMembers, isReverseMap)) { AddPropertyMap(destinationProperty, propertyType, sourceMembers); } diff --git a/src/UnitTests/Bug/NamingConventions.cs b/src/UnitTests/Bug/NamingConventions.cs index 12c63bd14f..cd6dbd41be 100644 --- a/src/UnitTests/Bug/NamingConventions.cs +++ b/src/UnitTests/Bug/NamingConventions.cs @@ -8,33 +8,6 @@ namespace AutoMapper.UnitTests.Bug.NamingConventions { - public class CaseSensitive : NonValidatingSpecBase - { - class Source - { - public int value; - } - class Destination - { - public int Value; - } - protected override MapperConfiguration CreateConfiguration() => new(c => - { - c.CreateMap(); - c.Internal().DefaultMemberConfig.NameMapper.NamedMappers[0] = new CaseSensitiveMapper(); - }); - private class CaseSensitiveMapper : ISourceToDestinationNameMapper - { - public MemberInfo GetMatchingMemberInfo(TypeDetails sourceTypeDetails, Type destType, Type destMemberType, string nameToSearch) - { - var sourceMember = sourceTypeDetails.GetMember(nameToSearch); - return sourceMember?.Name != nameToSearch ? null : sourceMember; - } - } - [Fact] - public void Should_consider_case() => - new Action(AssertConfigurationIsValid).ShouldThrow().Errors.Single().UnmappedPropertyNames.Single().ShouldBe("Value"); - } public class RemoveNameSplitMapper : NonValidatingSpecBase { class Source @@ -51,15 +24,14 @@ class Destination } protected override MapperConfiguration CreateConfiguration() => new(c => { - var mappers = c.Internal().DefaultMemberConfig.MemberMappers; - mappers.Remove(mappers.OfType().Single()); + c.Internal().DestinationMemberNamingConvention = ExactMatchNamingConvention.Instance; c.CreateMap(); }); [Fact] public void Should_not_validate() => Should.Throw(AssertConfigurationIsValid) .Errors.Single().UnmappedPropertyNames.Single().ShouldBe(nameof(Destination.InnerSourceValue)); } - public class ExactMatchNamingConvention : NonValidatingSpecBase + public class DisableNamingConvention : NonValidatingSpecBase { class Source { @@ -72,7 +44,7 @@ class Destination } protected override MapperConfiguration CreateConfiguration() => new(cfg=> { - cfg.DestinationMemberNamingConvention = new AutoMapper.ExactMatchNamingConvention(); + cfg.DestinationMemberNamingConvention = ExactMatchNamingConvention.Instance; cfg.CreateMap(); }); [Fact] diff --git a/src/UnitTests/Internal/TypeMapFactorySpecs.cs b/src/UnitTests/Internal/TypeMapFactorySpecs.cs index e02556a771..106064694c 100644 --- a/src/UnitTests/Internal/TypeMapFactorySpecs.cs +++ b/src/UnitTests/Internal/TypeMapFactorySpecs.cs @@ -66,15 +66,7 @@ private class Destination } private class TestProfile : Profile { - public TestProfile() - { - var namingConvention = new StubNamingConvention{ SeparatorCharacter = "__", SplittingExpression = new Regex(@"[\p{Ll}\p{Lu}0-9]+(?=__?)") }; - this.Internal().AddMemberConfiguration().AddMember(_ => - { - _.SourceMemberNamingConvention = namingConvention; - _.DestinationMemberNamingConvention = new PascalCaseNamingConvention(); - }); - } + public TestProfile() => SourceMemberNamingConvention = new StubNamingConvention{ SeparatorCharacter = "__", SplittingExpression = new Regex(@"[\p{Ll}\p{Lu}0-9]+(?=__?)") }; } protected override MapperConfiguration CreateConfiguration() => new(c => c.AddProfile()); [Fact] @@ -96,15 +88,7 @@ private class Destination } private class TestProfile : Profile { - public TestProfile() - { - var namingConvention = new StubNamingConvention{ SeparatorCharacter = "__", SplittingExpression = new Regex(@"[\p{Ll}\p{Lu}0-9]+(?=__?)") }; - this.Internal().AddMemberConfiguration().AddMember(_ => - { - _.SourceMemberNamingConvention = new PascalCaseNamingConvention(); - _.DestinationMemberNamingConvention = namingConvention; - }); - } + public TestProfile() => DestinationMemberNamingConvention = new StubNamingConvention{ SeparatorCharacter = "__", SplittingExpression = new Regex(@"[\p{Ll}\p{Lu}0-9]+(?=__?)") }; } protected override MapperConfiguration CreateConfiguration() => new(c => c.AddProfile()); [Fact] diff --git a/src/UnitTests/MapToAttributeTest.cs b/src/UnitTests/MapToAttributeTest.cs index e2f6e4c106..4707fd1e56 100644 --- a/src/UnitTests/MapToAttributeTest.cs +++ b/src/UnitTests/MapToAttributeTest.cs @@ -31,7 +31,7 @@ public class SourceToDestinationNameMapperAttributesMember : ISourceToDestinatio private static readonly SourceMember[] Empty = new SourceMember[0]; private readonly Dictionary _allSourceMembers = new Dictionary(); - public MemberInfo GetMatchingMemberInfo(TypeDetails sourceTypeDetails, Type destType, Type destMemberType, string nameToSearch) + public MemberInfo GetSourceMember(TypeDetails sourceTypeDetails, Type destType, Type destMemberType, string nameToSearch) { if (!_allSourceMembers.TryGetValue(sourceTypeDetails, out SourceMember[] sourceMembers)) { @@ -71,7 +71,7 @@ public class Category protected override MapperConfiguration CreateConfiguration() => new(cfg => { - cfg.Internal().AddMemberConfiguration().AddName(); + cfg.Internal().MemberConfiguration.NameToMemberMappers.Add(new SourceToDestinationNameMapperAttributesMember()); cfg.CreateProfile("New Profile", profile => { profile.CreateMap(); From e9287a20e5fbac51adafe02f8377748b6e321116 Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Sun, 21 Aug 2022 19:37:45 +0300 Subject: [PATCH 39/67] merge the profile member configuration with the global one --- src/AutoMapper/ApiCompatBaseline.txt | 5 ++- src/AutoMapper/Configuration/Conventions.cs | 40 +++++++++++++++++++-- src/AutoMapper/Configuration/Profile.cs | 4 +-- src/AutoMapper/Internal/TypeDetails.cs | 4 +-- src/AutoMapper/ProfileMap.cs | 15 ++++---- src/UnitTests/MapToAttributeTest.cs | 3 ++ 6 files changed, 54 insertions(+), 17 deletions(-) diff --git a/src/AutoMapper/ApiCompatBaseline.txt b/src/AutoMapper/ApiCompatBaseline.txt index a6ce2873f7..7215061b94 100644 --- a/src/AutoMapper/ApiCompatBaseline.txt +++ b/src/AutoMapper/ApiCompatBaseline.txt @@ -61,7 +61,10 @@ TypesMustExist : Type 'AutoMapper.Configuration.Conventions.IParentSourceToDesti InterfacesShouldHaveSameMembers : Interface member 'public System.Reflection.MemberInfo AutoMapper.Configuration.Conventions.ISourceToDestinationNameMapper.GetMatchingMemberInfo(AutoMapper.Internal.TypeDetails, System.Type, System.Type, System.String)' is present in the contract but not in the implementation. MembersMustExist : Member 'public System.Reflection.MemberInfo AutoMapper.Configuration.Conventions.ISourceToDestinationNameMapper.GetMatchingMemberInfo(AutoMapper.Internal.TypeDetails, System.Type, System.Type, System.String)' does not exist in the implementation but it does exist in the contract. InterfacesShouldHaveSameMembers : Interface member 'public System.Reflection.MemberInfo AutoMapper.Configuration.Conventions.ISourceToDestinationNameMapper.GetSourceMember(AutoMapper.Internal.TypeDetails, System.Type, System.Type, System.String)' is present in the implementation but not in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public void AutoMapper.Configuration.Conventions.ISourceToDestinationNameMapper.Merge(AutoMapper.Configuration.Conventions.ISourceToDestinationNameMapper)' is present in the implementation but not in the contract. TypesMustExist : Type 'AutoMapper.Configuration.Conventions.ParentSourceToDestinationNameMapper' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public System.Collections.Generic.List AutoMapper.Configuration.Conventions.PrePostfixName.DestinationPostfixes.get()' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public System.Collections.Generic.List AutoMapper.Configuration.Conventions.PrePostfixName.DestinationPrefixes.get()' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Reflection.MemberInfo AutoMapper.Configuration.Conventions.PrePostfixName.GetMatchingMemberInfo(AutoMapper.Internal.TypeDetails, System.Type, System.Type, System.String)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Collections.Generic.List AutoMapper.Configuration.Conventions.PrePostfixName.Postfixes.get()' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Collections.Generic.List AutoMapper.Configuration.Conventions.PrePostfixName.Prefixes.get()' does not exist in the implementation but it does exist in the contract. @@ -109,4 +112,4 @@ MembersMustExist : Member 'public AutoMapper.Internal.TypePair AutoMapper.Intern MembersMustExist : Member 'public System.Linq.IQueryable AutoMapper.QueryableExtensions.Extensions.Map(System.Linq.IQueryable, System.Linq.IQueryable, AutoMapper.IConfigurationProvider)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Collections.Generic.IReadOnlyCollection AutoMapper.QueryableExtensions.MemberVisitor.MemberPath.get()' does not exist in the implementation but it does exist in the contract. TypesMustExist : Type 'AutoMapper.QueryableExtensions.Impl.MemberAccessQueryMapperVisitor' does not exist in the implementation but it does exist in the contract. -Total Issues: 110 +Total Issues: 113 diff --git a/src/AutoMapper/Configuration/Conventions.cs b/src/AutoMapper/Configuration/Conventions.cs index 682e890782..6c30bebc28 100644 --- a/src/AutoMapper/Configuration/Conventions.cs +++ b/src/AutoMapper/Configuration/Conventions.cs @@ -9,6 +9,7 @@ namespace AutoMapper.Configuration.Conventions public interface ISourceToDestinationNameMapper { MemberInfo GetSourceMember(TypeDetails sourceTypeDetails, Type destType, Type destMemberType, string nameToSearch); + void Merge(ISourceToDestinationNameMapper otherNamedMapper); } [EditorBrowsable(EditorBrowsableState.Never)] public class MemberConfiguration @@ -49,11 +50,33 @@ public void Seal() _nameSplitMember = isDefault ? new DefaultNameSplitMember() : new ConventionsNameSplitMember(); _nameSplitMember.Parent = this; } + public void Merge(MemberConfiguration other) + { + if (other == null) + { + return; + } + var initialCount = NameToMemberMappers.Count; + for (int index = 0; index < other.NameToMemberMappers.Count; index++) + { + var otherNamedMapper = other.NameToMemberMappers[index]; + if (index < initialCount) + { + var namedMapper = NameToMemberMappers[index]; + if (namedMapper.GetType() == otherNamedMapper.GetType()) + { + namedMapper.Merge(otherNamedMapper); + continue; + } + } + NameToMemberMappers.Add(otherNamedMapper); + } + } } public class PrePostfixName : ISourceToDestinationNameMapper { - public List DestinationPrefixes { get; } = new(); - public List DestinationPostfixes { get; } = new(); + public HashSet DestinationPrefixes { get; } = new(); + public HashSet DestinationPostfixes { get; } = new(); public MemberInfo GetSourceMember(TypeDetails sourceTypeDetails, Type destType, Type destMemberType, string nameToSearch) { MemberInfo member; @@ -66,10 +89,16 @@ public MemberInfo GetSourceMember(TypeDetails sourceTypeDetails, Type destType, } return null; } + public void Merge(ISourceToDestinationNameMapper otherNamedMapper) + { + var typedOther = (PrePostfixName)otherNamedMapper; + DestinationPrefixes.UnionWith(typedOther.DestinationPrefixes); + DestinationPostfixes.UnionWith(typedOther.DestinationPostfixes); + } } public class ReplaceName : ISourceToDestinationNameMapper { - public List MemberNameReplacers { get; } = new(); + public HashSet MemberNameReplacers { get; } = new(); public MemberInfo GetSourceMember(TypeDetails sourceTypeDetails, Type destType, Type destMemberType, string nameToSearch) { var possibleSourceNames = PossibleNames(nameToSearch); @@ -90,6 +119,11 @@ public MemberInfo GetSourceMember(TypeDetails sourceTypeDetails, Type destType, } return null; } + public void Merge(ISourceToDestinationNameMapper otherNamedMapper) + { + var typedOther = (ReplaceName)otherNamedMapper; + MemberNameReplacers.UnionWith(typedOther.MemberNameReplacers); + } private string[] PossibleNames(string nameToSearch) => MemberNameReplacers.Select(r => nameToSearch.Replace(r.OriginalValue, r.NewValue)) .Concat(new[] { MemberNameReplacers.Aggregate(nameToSearch, (s, r) => s.Replace(r.OriginalValue, r.NewValue)), nameToSearch }) diff --git a/src/AutoMapper/Configuration/Profile.cs b/src/AutoMapper/Configuration/Profile.cs index 4d4f8106cc..7c833a021a 100644 --- a/src/AutoMapper/Configuration/Profile.cs +++ b/src/AutoMapper/Configuration/Profile.cs @@ -177,8 +177,8 @@ public void ReplaceMemberName(string original, string newValue) } public void RecognizePrefixes(params string[] prefixes) => _prefixes.AddRange(prefixes); public void RecognizePostfixes(params string[] postfixes) => _postfixes.AddRange(postfixes); - public void RecognizeDestinationPrefixes(params string[] prefixes) => _prePostfixName.DestinationPrefixes.AddRange(prefixes); - public void RecognizeDestinationPostfixes(params string[] postfixes) => _prePostfixName.DestinationPostfixes.AddRange(postfixes); + public void RecognizeDestinationPrefixes(params string[] prefixes) => _prePostfixName.DestinationPrefixes.UnionWith(prefixes); + public void RecognizeDestinationPostfixes(params string[] postfixes) => _prePostfixName.DestinationPostfixes.UnionWith(postfixes); public void AddGlobalIgnore(string propertyNameStartingWith) { _globalIgnores ??= new(); diff --git a/src/AutoMapper/Internal/TypeDetails.cs b/src/AutoMapper/Internal/TypeDetails.cs index c1515c633c..608d73750f 100644 --- a/src/AutoMapper/Internal/TypeDetails.cs +++ b/src/AutoMapper/Internal/TypeDetails.cs @@ -133,7 +133,7 @@ public MethodInfo Close() public override object[] GetCustomAttributes(Type attributeType, bool inherit) => throw new NotImplementedException(); public override bool IsDefined(Type attributeType, bool inherit) => throw new NotImplementedException(); } - public static string[] PossibleNames(string memberName, List prefixes, List postfixes) + public static string[] PossibleNames(string memberName, HashSet prefixes, HashSet postfixes) { List result = null; foreach (var prefix in prefixes) @@ -149,7 +149,7 @@ public static string[] PossibleNames(string memberName, List prefixes, L } PostFixes(ref result, postfixes, memberName); return result == null ? Array.Empty() : result.ToArray(); - static void PostFixes(ref List result, List< string> postfixes, string name) + static void PostFixes(ref List result, HashSet postfixes, string name) { foreach (var postfix in postfixes) { diff --git a/src/AutoMapper/ProfileMap.cs b/src/AutoMapper/ProfileMap.cs index 1995917b73..90b9f18094 100644 --- a/src/AutoMapper/ProfileMap.cs +++ b/src/AutoMapper/ProfileMap.cs @@ -39,15 +39,15 @@ public ProfileMap(IProfileConfiguration profile, IGlobalConfigurationExpression ValueTransformers = profile.ValueTransformers.Concat(configuration?.ValueTransformers).ToArray(); var profileInternal = (IProfileExpressionInternal)profile; MemberConfiguration = profileInternal.MemberConfiguration; - GlobalMemberConfiguration = configuration.Internal()?.MemberConfiguration; + MemberConfiguration.Merge(configuration.Internal()?.MemberConfiguration); var globalIgnores = profile.GlobalIgnores.Concat(globalProfile?.GlobalIgnores); GlobalIgnores = globalIgnores == Array.Empty() ? EmptyHashSet : new HashSet(globalIgnores); SourceExtensionMethods = profile.SourceExtensionMethods.Concat(globalProfile?.SourceExtensionMethods).ToArray(); AllPropertyMapActions = profile.AllPropertyMapActions.Concat(globalProfile?.AllPropertyMapActions).ToArray(); AllTypeMapActions = profile.AllTypeMapActions.Concat(globalProfile?.AllTypeMapActions).ToArray(); profileInternal.MemberConfiguration.Seal(); - Prefixes = profileInternal.Prefixes.Concat(configuration?.Prefixes).Distinct().ToList(); - Postfixes = profileInternal.Postfixes.Concat(configuration?.Postfixes).Distinct().ToList(); + Prefixes = new(profileInternal.Prefixes.Concat(configuration?.Prefixes)); + Postfixes = new(profileInternal.Postfixes.Concat(configuration?.Postfixes)); TypeMapConfigs(); OpenTypeMapConfigs(); _typeDetails = new(2 * _typeMapConfigs.Length); @@ -104,10 +104,9 @@ internal void Clear() public IEnumerable> AllTypeMapActions { get; } public HashSet GlobalIgnores { get; } public MemberConfiguration MemberConfiguration { get; } - public MemberConfiguration GlobalMemberConfiguration { get; } public IEnumerable SourceExtensionMethods { get; } - public List Prefixes { get; } - public List Postfixes { get; } + public HashSet Prefixes { get; } + public HashSet Postfixes { get; } public IReadOnlyCollection ValueTransformers { get; } public TypeDetails CreateTypeDetails(Type type) { @@ -255,9 +254,7 @@ private void ApplyDerivedMaps(TypeMap baseMap, TypeMap typeMap, IGlobalConfigura } } public bool MapDestinationPropertyToSource(TypeDetails sourceTypeDetails, Type destType, Type destMemberType, string destMemberName, List members, bool reverseNamingConventions) => - destMemberName != null && - (MemberConfiguration.IsMatch(this, sourceTypeDetails, destType, destMemberType, destMemberName, members, reverseNamingConventions) || - GlobalMemberConfiguration?.IsMatch(this, sourceTypeDetails, destType, destMemberType, destMemberName, members, reverseNamingConventions) is true); + destMemberName != null && MemberConfiguration.IsMatch(this, sourceTypeDetails, destType, destMemberType, destMemberName, members, reverseNamingConventions); public bool AllowsNullDestinationValuesFor(MemberMap memberMap = null) => memberMap?.AllowNull ?? AllowNullDestinationValues; public bool AllowsNullCollectionsFor(MemberMap memberMap = null) => memberMap?.AllowNull ?? AllowNullCollections; } diff --git a/src/UnitTests/MapToAttributeTest.cs b/src/UnitTests/MapToAttributeTest.cs index 4707fd1e56..6f86fe03d1 100644 --- a/src/UnitTests/MapToAttributeTest.cs +++ b/src/UnitTests/MapToAttributeTest.cs @@ -40,6 +40,9 @@ public MemberInfo GetSourceMember(TypeDetails sourceTypeDetails, Type destType, } return sourceMembers.FirstOrDefault(d => d.Attribute.IsMatch(sourceTypeDetails, d.Member, destType, destMemberType, nameToSearch)).Member; } + public void Merge(ISourceToDestinationNameMapper otherNamedMapper) + { + } readonly struct SourceMember { public SourceMember(MemberInfo sourceMember) From 0d2aa501dcb4f3779934c543e5fd041892a8c503 Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Mon, 22 Aug 2022 08:36:02 +0300 Subject: [PATCH 40/67] cosmetic --- src/AutoMapper/ApiCompatBaseline.txt | 3 ++- src/AutoMapper/Configuration/TypeMapConfiguration.cs | 7 ++++++- src/AutoMapper/Execution/ExpressionBuilder.cs | 7 +++---- src/AutoMapper/Internal/TypeExtensions.cs | 2 +- src/AutoMapper/Internal/TypePair.cs | 5 ++--- src/AutoMapper/Mappers/CollectionMapper.cs | 2 +- src/AutoMapper/MemberMap.cs | 5 ----- src/AutoMapper/ProfileMap.cs | 2 +- 8 files changed, 16 insertions(+), 17 deletions(-) diff --git a/src/AutoMapper/ApiCompatBaseline.txt b/src/AutoMapper/ApiCompatBaseline.txt index 7215061b94..87e6596d25 100644 --- a/src/AutoMapper/ApiCompatBaseline.txt +++ b/src/AutoMapper/ApiCompatBaseline.txt @@ -95,6 +95,7 @@ MembersMustExist : Member 'public AutoMapper.Internal.TypePair AutoMapper.Intern MembersMustExist : Member 'public AutoMapper.MemberMap AutoMapper.MemberMap AutoMapper.Internal.MapRequest.MemberMap' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Boolean AutoMapper.Internal.MapRequest.op_Equality(AutoMapper.Internal.MapRequest, AutoMapper.Internal.MapRequest)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Boolean AutoMapper.Internal.MapRequest.op_Inequality(AutoMapper.Internal.MapRequest, AutoMapper.Internal.MapRequest)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public System.Collections.Generic.IEnumerable AutoMapper.Internal.TypeExtensions.GetDeclaredConstructors(System.Type)' does not exist in the implementation but it does exist in the contract. CannotChangeAttribute : Attribute 'System.Runtime.CompilerServices.IteratorStateMachineAttribute' on 'AutoMapper.Internal.TypeExtensions.GetTypeInheritance(System.Type)' changed from '[IteratorStateMachineAttribute(typeof(TypeExtensions.d__19))]' in the contract to '[IteratorStateMachineAttribute(typeof(TypeExtensions.d__22))]' in the implementation. MembersMustExist : Member 'public System.Type System.Type AutoMapper.Internal.TypePair.DestinationType' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Type System.Type AutoMapper.Internal.TypePair.SourceType' does not exist in the implementation but it does exist in the contract. @@ -112,4 +113,4 @@ MembersMustExist : Member 'public AutoMapper.Internal.TypePair AutoMapper.Intern MembersMustExist : Member 'public System.Linq.IQueryable AutoMapper.QueryableExtensions.Extensions.Map(System.Linq.IQueryable, System.Linq.IQueryable, AutoMapper.IConfigurationProvider)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Collections.Generic.IReadOnlyCollection AutoMapper.QueryableExtensions.MemberVisitor.MemberPath.get()' does not exist in the implementation but it does exist in the contract. TypesMustExist : Type 'AutoMapper.QueryableExtensions.Impl.MemberAccessQueryMapperVisitor' does not exist in the implementation but it does exist in the contract. -Total Issues: 113 +Total Issues: 114 diff --git a/src/AutoMapper/Configuration/TypeMapConfiguration.cs b/src/AutoMapper/Configuration/TypeMapConfiguration.cs index ff4d8cb3ca..93f18aa612 100644 --- a/src/AutoMapper/Configuration/TypeMapConfiguration.cs +++ b/src/AutoMapper/Configuration/TypeMapConfiguration.cs @@ -141,8 +141,13 @@ private void MapDestinationCtorToSource(TypeMap typeMap, List source bool canMapResolve = true; foreach (var parameter in destCtor.Parameters) { + var name = parameter.Name; + if (name == null) + { + return; + } sourceMembers.Clear(); - var canResolve = typeMap.Profile.MapDestinationPropertyToSource(typeMap.SourceTypeDetails, constructor.DeclaringType, parameter.ParameterType, parameter.Name, sourceMembers, IsReverseMap); + var canResolve = typeMap.Profile.MapDestinationPropertyToSource(typeMap.SourceTypeDetails, constructor.DeclaringType, parameter.ParameterType, name, sourceMembers, IsReverseMap); if (!canResolve && !parameter.IsOptional && !IsConfigured(parameter)) { canMapResolve = false; diff --git a/src/AutoMapper/Execution/ExpressionBuilder.cs b/src/AutoMapper/Execution/ExpressionBuilder.cs index 0b89b245a5..b80f3022f2 100644 --- a/src/AutoMapper/Execution/ExpressionBuilder.cs +++ b/src/AutoMapper/Execution/ExpressionBuilder.cs @@ -37,9 +37,8 @@ public static class ExpressionBuilder private static readonly MethodInfo ArrayEmptyMethod = typeof(Array).GetStaticMethod(nameof(Array.Empty)); private static readonly ParameterExpression Disposable = Variable(typeof(IDisposable), "disposableEnumerator"); private static readonly ReadOnlyCollection DisposableArray = Disposable.ToReadOnly(); - private static readonly Expression DisposeCall = IfNullElse(Disposable, Empty, Expression.Call(Disposable, DisposeMethod)); + private static readonly Expression DisposeCall = IfThen(ReferenceNotEqual(Disposable, Null), Expression.Call(Disposable, DisposeMethod)); private static readonly ParameterExpression Index = Variable(typeof(int), "sourceArrayIndex"); - private static readonly ReadOnlyCollection Indexes = Index.ToReadOnly(); private static readonly BinaryExpression ResetIndex = Assign(Index, Zero); private static readonly UnaryExpression IncrementIndex = PostIncrementAssign(Index); public static DefaultExpression Default(this IGlobalConfiguration configuration, Type type) => @@ -147,7 +146,7 @@ Expression ClearDestinationCollection() var (variables, statements) = configuration.Scratchpad(); variables.Add(destinationVariable); statements.Add(Assign(destinationVariable, destination)); - statements.Add(Condition(ReferenceEqual(collection, Null), Empty, Expression.Call(collection, clearMethod))); + statements.Add(IfThen(ReferenceNotEqual(collection, Null), Expression.Call(collection, clearMethod))); statements.Add(destinationVariable); return Block(variables, statements); } @@ -314,7 +313,7 @@ static Expression ForEachArrayItem(List variables, List GetDeclaredConstructors(this Type type) => type.GetConstructors(InstanceFlags); + public static ConstructorInfo[] GetDeclaredConstructors(this Type type) => type.GetConstructors(InstanceFlags); public static int GenericParametersCount(this Type type) => type.GetTypeInfo().GenericTypeParameters.Length; diff --git a/src/AutoMapper/Internal/TypePair.cs b/src/AutoMapper/Internal/TypePair.cs index 4139844da4..0d2da10037 100644 --- a/src/AutoMapper/Internal/TypePair.cs +++ b/src/AutoMapper/Internal/TypePair.cs @@ -5,9 +5,8 @@ namespace AutoMapper.Internal [DebuggerDisplay("{RequestedTypes.SourceType.Name}, {RequestedTypes.DestinationType.Name} : {RuntimeTypes.SourceType.Name}, {RuntimeTypes.DestinationType.Name}")] public readonly record struct MapRequest(TypePair RequestedTypes, TypePair RuntimeTypes, MemberMap MemberMap) { - public bool Equals(MapRequest other) => RequestedTypes.Equals(other.RequestedTypes) && RuntimeTypes.Equals(other.RuntimeTypes) && - (MemberMap == other.MemberMap || MemberMap.MapperEquals(other.MemberMap)); - public override int GetHashCode() => HashCode.Combine(RequestedTypes, RuntimeTypes, MemberMap.MapperGetHashCode()); + public bool Equals(MapRequest other) => RequestedTypes.Equals(other.RequestedTypes) && RuntimeTypes.Equals(other.RuntimeTypes); + public override int GetHashCode() => HashCode.Combine(RequestedTypes, RuntimeTypes); } [DebuggerDisplay("{SourceType.Name}, {DestinationType.Name}")] public readonly record struct TypePair(Type SourceType, Type DestinationType) diff --git a/src/AutoMapper/Mappers/CollectionMapper.cs b/src/AutoMapper/Mappers/CollectionMapper.cs index fc314cb430..58f2326d46 100644 --- a/src/AutoMapper/Mappers/CollectionMapper.cs +++ b/src/AutoMapper/Mappers/CollectionMapper.cs @@ -75,7 +75,7 @@ Expression MapCollectionCore(Expression destExpression) var overMaxDepth = OverMaxDepth(memberMap?.TypeMap); if (overMaxDepth != null) { - addItems = Condition(overMaxDepth, ExpressionBuilder.Empty, addItems); + addItems = IfThenElse(overMaxDepth, ExpressionBuilder.Empty, addItems); } var clearMethod = isIList ? IListClear : destinationCollectionType.GetMethod("Clear"); statements.Clear(); diff --git a/src/AutoMapper/MemberMap.cs b/src/AutoMapper/MemberMap.cs index ef5f96d639..87aad9fabb 100644 --- a/src/AutoMapper/MemberMap.cs +++ b/src/AutoMapper/MemberMap.cs @@ -65,12 +65,7 @@ public Expression ChainSourceMembers(IGlobalConfiguration configuration, Express return IncludedMember == null && SourceMembers.Length < 2 ? expression : expression.NullCheck(configuration, this, defaultValue); } public bool AllowsNullDestinationValues => Profile?.AllowsNullDestinationValuesFor(this) ?? true; - public bool AllowsNullCollections => (Profile?.AllowsNullCollectionsFor(this)).GetValueOrDefault(); public ProfileMap Profile => TypeMap?.Profile; - private int MaxDepth => (TypeMap?.MaxDepth).GetValueOrDefault(); - public bool MapperEquals(MemberMap other) => other.MustUseDestination == MustUseDestination && other.MaxDepth == MaxDepth && - other.AllowsNullDestinationValues == AllowsNullDestinationValues && other.AllowsNullCollections == AllowsNullCollections; - public int MapperGetHashCode() => HashCode.Combine(MustUseDestination, MaxDepth, AllowsNullDestinationValues, AllowsNullCollections); protected Type GetSourceType() => Resolver?.ResolvedType ?? DestinationType; public void MapByConvention(MemberInfo[] sourceMembers) { diff --git a/src/AutoMapper/ProfileMap.cs b/src/AutoMapper/ProfileMap.cs index 90b9f18094..6e63c8f54c 100644 --- a/src/AutoMapper/ProfileMap.cs +++ b/src/AutoMapper/ProfileMap.cs @@ -254,7 +254,7 @@ private void ApplyDerivedMaps(TypeMap baseMap, TypeMap typeMap, IGlobalConfigura } } public bool MapDestinationPropertyToSource(TypeDetails sourceTypeDetails, Type destType, Type destMemberType, string destMemberName, List members, bool reverseNamingConventions) => - destMemberName != null && MemberConfiguration.IsMatch(this, sourceTypeDetails, destType, destMemberType, destMemberName, members, reverseNamingConventions); + MemberConfiguration.IsMatch(this, sourceTypeDetails, destType, destMemberType, destMemberName, members, reverseNamingConventions); public bool AllowsNullDestinationValuesFor(MemberMap memberMap = null) => memberMap?.AllowNull ?? AllowNullDestinationValues; public bool AllowsNullCollectionsFor(MemberMap memberMap = null) => memberMap?.AllowNull ?? AllowNullCollections; } From ec0a8322e663b94a857cc685e89482a3b8001108 Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Mon, 22 Aug 2022 16:46:10 +0300 Subject: [PATCH 41/67] test reusing the execution plan --- .../Configuration/MapperConfiguration.cs | 10 +- .../Execution/TypeMapPlanBuilder.cs | 5 +- src/AutoMapper/MemberMap.cs | 1 - src/AutoMapper/PropertyMap.cs | 2 +- src/UnitTests/ArraysAndLists.cs | 2 - src/UnitTests/BuildExecutionPlan.cs | 217 +++++++++++++----- 6 files changed, 171 insertions(+), 66 deletions(-) diff --git a/src/AutoMapper/Configuration/MapperConfiguration.cs b/src/AutoMapper/Configuration/MapperConfiguration.cs index 4f6e226863..b2bd46287e 100644 --- a/src/AutoMapper/Configuration/MapperConfiguration.cs +++ b/src/AutoMapper/Configuration/MapperConfiguration.cs @@ -218,14 +218,12 @@ LambdaExpression GenerateObjectMapperExpression(in MapRequest mapRequest, IObjec var destination = Parameter(destinationType, "mapperDestination"); var runtimeDestinationType = mapRequest.RuntimeTypes.DestinationType; Expression fullExpression; - bool nullCheck; if (mapper == null) { var exception = new AutoMapperMappingException("Missing type map configuration or unsupported mapping.", null, mapRequest.RuntimeTypes) { MemberMap = mapRequest.MemberMap }; - nullCheck = true; fullExpression = Throw(Constant(exception), runtimeDestinationType); } else @@ -233,15 +231,11 @@ LambdaExpression GenerateObjectMapperExpression(in MapRequest mapRequest, IObjec var checkNullValueTypeDest = CheckNullValueType(destination, runtimeDestinationType); var mapperSource = ToType(source, mapRequest.RuntimeTypes.SourceType); var map = mapper.MapExpression(this, Configuration, mapRequest.MemberMap, mapperSource, ToType(checkNullValueTypeDest, runtimeDestinationType)); - nullCheck = map != mapperSource; var newException = Call(MappingError, ExceptionParameter, Constant(mapRequest)); fullExpression = TryCatch(ToType(map, destinationType), Catch(ExceptionParameter, Throw(newException, destinationType))); } - if (nullCheck) - { - var profileMap = mapRequest.MemberMap.Profile ?? Configuration; - fullExpression = this.NullCheckSource(profileMap, source, destination, fullExpression, mapRequest.MemberMap); - } + var profileMap = mapRequest.MemberMap.Profile ?? Configuration; + fullExpression = this.NullCheckSource(profileMap, source, destination, fullExpression, mapRequest.MemberMap); return Lambda(fullExpression, source, destination, ContextParameter); } } diff --git a/src/AutoMapper/Execution/TypeMapPlanBuilder.cs b/src/AutoMapper/Execution/TypeMapPlanBuilder.cs index 93f48670ec..35e5935b3d 100644 --- a/src/AutoMapper/Execution/TypeMapPlanBuilder.cs +++ b/src/AutoMapper/Execution/TypeMapPlanBuilder.cs @@ -378,9 +378,10 @@ ParameterExpression SetVariables(Expression valueResolver, ParameterExpression r Expression MapMember(MemberMap memberMap, Expression destinationMemberValue, ParameterExpression resolvedValue) { var typePair = memberMap.Types(); + var profile = _typeMap.Profile; var mapMember = memberMap.Inline ? - _configuration.MapExpression(_typeMap.Profile, typePair, resolvedValue, memberMap, destinationMemberValue) : - ContextMap(typePair, resolvedValue, destinationMemberValue, memberMap); + _configuration.MapExpression(profile, typePair, resolvedValue, memberMap, destinationMemberValue) : + _configuration.NullCheckSource(profile, resolvedValue, destinationMemberValue, ContextMap(typePair, resolvedValue, destinationMemberValue, memberMap), memberMap); return memberMap.ApplyTransformers(mapMember); } private Expression BuildValueResolverFunc(MemberMap memberMap, Expression customSource, Expression destValueExpr) diff --git a/src/AutoMapper/MemberMap.cs b/src/AutoMapper/MemberMap.cs index 87aad9fabb..f185aeca82 100644 --- a/src/AutoMapper/MemberMap.cs +++ b/src/AutoMapper/MemberMap.cs @@ -16,7 +16,6 @@ namespace AutoMapper [EditorBrowsable(EditorBrowsableState.Never)] public class MemberMap : IValueResolver { - private static readonly LambdaExpression EmptyLambda = Lambda(ExpressionBuilder.Null); protected MemberMap(TypeMap typeMap = null) => TypeMap = typeMap; internal static readonly MemberMap Instance = new(); internal static readonly MemberMap InstanceUseDestination = new PropertyMap(default(MemberInfo), null, null) { UseDestinationValue = true }; diff --git a/src/AutoMapper/PropertyMap.cs b/src/AutoMapper/PropertyMap.cs index fd7fc7fa9f..5f417ec923 100644 --- a/src/AutoMapper/PropertyMap.cs +++ b/src/AutoMapper/PropertyMap.cs @@ -24,7 +24,7 @@ public PropertyMap(PropertyMap includedMemberMap, TypeMap typeMap, IncludedMembe : this(includedMemberMap, typeMap) => Details.IncludedMember = includedMember.Chain(includedMemberMap.IncludedMember); private MemberMapDetails Details => _details ??= new(); public MemberInfo DestinationMember { get; } - public override string DestinationName => DestinationMember.Name; + public override string DestinationName => DestinationMember?.Name; public override Type DestinationType { get; protected set; } public override MemberInfo[] SourceMembers { get; set; } = Array.Empty(); public override bool CanBeSet => ReflectionHelper.CanBeSet(DestinationMember); diff --git a/src/UnitTests/ArraysAndLists.cs b/src/UnitTests/ArraysAndLists.cs index 5a1e3987f0..b7d7abc8c4 100644 --- a/src/UnitTests/ArraysAndLists.cs +++ b/src/UnitTests/ArraysAndLists.cs @@ -2,7 +2,6 @@ using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; -using System.ComponentModel; using Xunit; using Shouldly; using System.Linq; @@ -10,7 +9,6 @@ using System.Linq.Expressions; using AutoMapper.Internal; using AutoMapper.Internal.Mappers; - namespace AutoMapper.UnitTests.ArraysAndLists { public class When_mapping_to_Existing_IEnumerable : AutoMapperSpecBase diff --git a/src/UnitTests/BuildExecutionPlan.cs b/src/UnitTests/BuildExecutionPlan.cs index 1933ec0819..7aa436f54c 100644 --- a/src/UnitTests/BuildExecutionPlan.cs +++ b/src/UnitTests/BuildExecutionPlan.cs @@ -1,65 +1,178 @@ using System; -using AutoMapper; +using System.Collections.Generic; using Shouldly; using Xunit; - -namespace AutoMapper.UnitTests +namespace AutoMapper.UnitTests; +public class BuildExecutionPlan : AutoMapperSpecBase { - public class BuildExecutionPlan : AutoMapperSpecBase + Model _source; + Dto _destination; + public class Model { - Model _source; - Dto _destination; - - public class Model + public Guid? Id { get; set; } + public Guid? FooId { get; set; } + public string FullDescription { get; set; } + public string ShortDescription { get; set; } + public DateTime Date { get; set; } + public int? IntValue { get; set; } + } + public class Dto + { + public Guid? Id { get; set; } + public string FooId { get; set; } + public string FullDescription { get; set; } + public string ShortDescription { get; set; } + public DateTime Date { get; set; } + public int IntValue { get; set; } + public string CompanyName { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(c => + { + c.CreateMap().ForMember(d => d.CompanyName, o => o.Ignore()); + }); + protected override void Because_of() + { + _source = new Model { - public Guid? Id { get; set; } - public Guid? FooId { get; set; } - public string FullDescription { get; set; } - public string ShortDescription { get; set; } - public DateTime Date { get; set; } - public int? IntValue { get; set; } - } - - public class Dto + Id = Guid.NewGuid(), + FooId = Guid.NewGuid(), + ShortDescription = "Yoyodyne Foo", + FullDescription = "Deluxe Foo Manufactured by Yoyodyne, Inc.", + Date = DateTime.Now, + IntValue = 13, + }; + var plan = Configuration.BuildExecutionPlan(typeof(Model), typeof(Dto)); + _destination = ((Func)plan.Compile())(_source, null, null); + } + [Fact] + public void Should_build_the_execution_plan() + { + _destination.Id.ShouldBe(_source.Id); + _destination.FooId.ShouldBe(_source.FooId.ToString()); + _destination.ShortDescription.ShouldBe(_source.ShortDescription); + _destination.FullDescription.ShouldBe(_source.FullDescription); + _destination.Date.ShouldBe(_source.Date); + _destination.IntValue.ShouldBe(_source.IntValue.Value); + } +} +public class When_reusing_the_execution_plan_inner_map : AutoMapperSpecBase +{ + class Source + { + public Inner Inner { get; set; } + } + class Destination + { + public Inner Inner { get; set; } + } + class Inner { } + protected override MapperConfiguration CreateConfiguration() => new(c => + { + c.AllowNullDestinationValues = false; + c.CreateMap(); + c.CreateMap().ForAllMembers(o => { - public Guid? Id { get; set; } - public string FooId { get; set; } - public string FullDescription { get; set; } - public string ShortDescription { get; set; } - public DateTime Date { get; set; } - public int IntValue { get; set; } - public string CompanyName { get; set; } - } - - protected override MapperConfiguration CreateConfiguration() => new(c => + o.AllowNull(); + o.MapAtRuntime(); + }); + }); + [Fact] + public void Should_consider_per_member_settings() + { + Mapper.Map(null).ShouldNotBeNull(); + var destination = Map(new Source()); + destination.Inner.ShouldBeNull(); + } +} +public class AllowNullWithMapAtRuntime : AutoMapperSpecBase +{ + class Source + { + public Inner Inner { get; set; } + } + class Destination + { + public Inner Inner { get; set; } + } + class Inner { } + protected override MapperConfiguration CreateConfiguration() => new(c => + { + c.AllowNullDestinationValues = false; + c.CreateMap(); + c.CreateMap().ForAllMembers(o => { - c.CreateMap().ForMember(d => d.CompanyName, o => o.Ignore()); + o.AllowNull(); + o.MapAtRuntime(); }); - - protected override void Because_of() + }); + [Fact] + public void Should_consider_per_member_settings() + { + var destination = Map(new Source()); + destination.Inner.ShouldBeNull(); + } +} +public class When_reusing_the_execution_plan : AutoMapperSpecBase +{ + class Source + { + public int[] Ints { get; set; } + public string String { get; set; } + } + class Destination + { + public int[] Ints { get; set; } + public string String { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(c => + { + c.AllowNullDestinationValues = false; + c.CreateMap().ForAllMembers(o => { - _source = new Model - { - Id = Guid.NewGuid(), - FooId = Guid.NewGuid(), - ShortDescription = "Yoyodyne Foo", - FullDescription = "Deluxe Foo Manufactured by Yoyodyne, Inc.", - Date = DateTime.Now, - IntValue = 13, - }; - var plan = Configuration.BuildExecutionPlan(typeof(Model), typeof(Dto)); - _destination = ((Func)plan.Compile())(_source, null, null); - } - - [Fact] - public void Should_build_the_execution_plan() + o.AllowNull(); + o.MapAtRuntime(); + }); + }); + [Fact] + public void Should_consider_per_member_settings() + { + Mapper.Map(null).Length.ShouldBe(0); + Mapper.Map(null).Length.ShouldBe(0); + var destination = Map(new Source()); + destination.Ints.ShouldBeNull(); + destination.String.ShouldBeNull(); + } +} +public class When_reusing_the_execution_plan_existing_destination : AutoMapperSpecBase +{ + class Source + { + public int[] Ints { get; set; } + } + class OtherSource + { + public int[] Ints { get; set; } + } + class Destination + { + public ICollection Ints { get; set; } = new HashSet(); + } + protected override MapperConfiguration CreateConfiguration() => new(c => + { + c.CreateMap().ForAllMembers(o => o.MapAtRuntime()); + c.CreateMap().ForAllMembers(o => { - _destination.Id.ShouldBe(_source.Id); - _destination.FooId.ShouldBe(_source.FooId.ToString()); - _destination.ShortDescription.ShouldBe(_source.ShortDescription); - _destination.FullDescription.ShouldBe(_source.FullDescription); - _destination.Date.ShouldBe(_source.Date); - _destination.IntValue.ShouldBe(_source.IntValue.Value); - } + o.UseDestinationValue(); + o.MapAtRuntime(); + }); + }); + [Fact] + public void Should_consider_per_member_settings() + { + var ints = new[] { 1, 1, 1 }; + var destination = Map(new OtherSource { Ints = ints }); + destination.Ints.ShouldBe(ints); + destination = Map(new Source { Ints = ints }); + destination.Ints.ShouldBe(new[] { 1 }); } } \ No newline at end of file From 593ad5316a6d95ffac6897b25e2a169eff969244 Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Mon, 22 Aug 2022 22:10:15 +0300 Subject: [PATCH 42/67] refactor test base classes --- src/AutoMapper/AutoMapperMappingException.cs | 2 +- src/UnitTests/AutoMapperSpecBase.cs | 41 +++----------- src/UnitTests/Bug/MapFromClosureBug.cs | 2 +- src/UnitTests/Bug/MultidimensionalArrays.cs | 8 +-- src/UnitTests/Bug/NonExistingProperty.cs | 2 +- src/UnitTests/Bug/ObjectTypeMapFailure.cs | 2 +- .../Bug/RepeatedMappingConfigurationTest.cs | 2 +- src/UnitTests/BuildExecutionPlan.cs | 3 +- src/UnitTests/ConfigurationRules.cs | 2 +- src/UnitTests/ExplicitMapperCreation.cs | 53 ++++++------------- src/UnitTests/ExpressionBridge.cs | 9 +--- .../NonGenericReverseMapping.cs | 2 +- src/UnitTests/Internal/MapperTests.cs | 2 +- src/UnitTests/Internal/TypeMapFactorySpecs.cs | 6 +-- ...dedBaseMappingShouldInheritBaseMappings.cs | 2 +- ...ncludedMappingShouldInheritBaseMappings.cs | 2 +- .../ReverseMapWithInclude.cs | 2 +- src/UnitTests/MemberNameReplacers.cs | 2 +- src/UnitTests/MemberResolution.cs | 14 ++--- src/UnitTests/ReverseMapping.cs | 2 +- 20 files changed, 47 insertions(+), 113 deletions(-) diff --git a/src/AutoMapper/AutoMapperMappingException.cs b/src/AutoMapper/AutoMapperMappingException.cs index 85ee5ea676..2190465677 100644 --- a/src/AutoMapper/AutoMapperMappingException.cs +++ b/src/AutoMapper/AutoMapperMappingException.cs @@ -53,7 +53,7 @@ public override string Message message += newLine + $"{TypeMap.SourceType.Name} -> {TypeMap.DestinationType.Name}"; message += newLine + $"{TypeMap.SourceType.FullName} -> {TypeMap.DestinationType.FullName}"; } - if (MemberMap != null) + if (MemberMap?.TypeMap != null) { message = message + newLine + newLine + "Destination Member:"; message += newLine + $"{MemberMap}" + newLine; diff --git a/src/UnitTests/AutoMapperSpecBase.cs b/src/UnitTests/AutoMapperSpecBase.cs index 5e83c73734..3f65ec1299 100644 --- a/src/UnitTests/AutoMapperSpecBase.cs +++ b/src/UnitTests/AutoMapperSpecBase.cs @@ -1,14 +1,10 @@ using System; -using Xunit; using AutoMapper.Internal; using Shouldly; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; -using AutoMapper.Configuration; - namespace AutoMapper.UnitTests; - /// /// Ignore this member for validation and skip during mapping /// @@ -46,10 +42,14 @@ public abstract class AutoMapperSpecBase : NonValidatingSpecBase protected override void AssertConfigurationIsValid() => Configuration.Internal(); } -public abstract class NonValidatingSpecBase : SpecBase +public abstract class NonValidatingSpecBase : IDisposable { + protected NonValidatingSpecBase() + { + Because_of(); + } private IMapper _mapper; - protected abstract MapperConfiguration CreateConfiguration(); + protected virtual MapperConfiguration CreateConfiguration() => throw new NotImplementedException(); protected IGlobalConfiguration Configuration => Mapper.ConfigurationProvider.Internal(); protected IMapper Mapper => _mapper ??= CreateMapper(); IMapper CreateMapper() @@ -71,41 +71,12 @@ protected IQueryable ProjectTo(IQueryable source, ob protected IQueryable ProjectTo(IQueryable source, IDictionary parameters, params string[] membersToExpand) => Mapper.ProjectTo(source, parameters, membersToExpand); public IEnumerable GetProfiles() => Configuration.Profiles; -} - -public abstract class SpecBaseBase -{ - protected virtual void MainSetup() - { - Establish_context(); - Because_of(); - } - - protected virtual void MainTeardown() - { - Cleanup(); - } - - protected virtual void Establish_context() - { - } - protected virtual void Because_of() { } - protected virtual void Cleanup() { } -} -public abstract class SpecBase : SpecBaseBase, IDisposable -{ - protected SpecBase() - { - Establish_context(); - Because_of(); - } - public void Dispose() { Cleanup(); diff --git a/src/UnitTests/Bug/MapFromClosureBug.cs b/src/UnitTests/Bug/MapFromClosureBug.cs index 9d6e7a95c8..216290bda7 100644 --- a/src/UnitTests/Bug/MapFromClosureBug.cs +++ b/src/UnitTests/Bug/MapFromClosureBug.cs @@ -4,7 +4,7 @@ using Shouldly; using Xunit; - public class MapFromClosureBug : SpecBaseBase + public class MapFromClosureBug : NonValidatingSpecBase { private static readonly IDateProvider _dateProvider = new DateProvider(); diff --git a/src/UnitTests/Bug/MultidimensionalArrays.cs b/src/UnitTests/Bug/MultidimensionalArrays.cs index 4ff862276d..0a5d0ba94e 100644 --- a/src/UnitTests/Bug/MultidimensionalArrays.cs +++ b/src/UnitTests/Bug/MultidimensionalArrays.cs @@ -52,18 +52,14 @@ public void Should_map_multidimensional_array() } } - public class FillMultidimensionalArray : SpecBase + public class FillMultidimensionalArray : NonValidatingSpecBase { int[,] _source; MultidimensionalArrayFiller _filler; - protected override void Establish_context() + protected override void Because_of() { _source = new int[4,3]; _filler = new MultidimensionalArrayFiller(_source); - } - - protected override void Because_of() - { for(int index = 0; index < _source.Length; index++) { _filler.NewValue(index); diff --git a/src/UnitTests/Bug/NonExistingProperty.cs b/src/UnitTests/Bug/NonExistingProperty.cs index ef1c384828..ea8854aa90 100644 --- a/src/UnitTests/Bug/NonExistingProperty.cs +++ b/src/UnitTests/Bug/NonExistingProperty.cs @@ -4,7 +4,7 @@ namespace AutoMapper.UnitTests.Bug { - public class NonExistingProperty : SpecBase + public class NonExistingProperty : NonValidatingSpecBase { public class Source { diff --git a/src/UnitTests/Bug/ObjectTypeMapFailure.cs b/src/UnitTests/Bug/ObjectTypeMapFailure.cs index fd4b2ee80f..307465ac36 100644 --- a/src/UnitTests/Bug/ObjectTypeMapFailure.cs +++ b/src/UnitTests/Bug/ObjectTypeMapFailure.cs @@ -3,7 +3,7 @@ namespace AutoMapper.UnitTests.Bug { - public class ObjectTypeMapFailure : SpecBase + public class ObjectTypeMapFailure : NonValidatingSpecBase { [Fact] public void Should_map_the_object_type() diff --git a/src/UnitTests/Bug/RepeatedMappingConfigurationTest.cs b/src/UnitTests/Bug/RepeatedMappingConfigurationTest.cs index ea94703464..0b4e9766ec 100644 --- a/src/UnitTests/Bug/RepeatedMappingConfigurationTest.cs +++ b/src/UnitTests/Bug/RepeatedMappingConfigurationTest.cs @@ -2,7 +2,7 @@ namespace AutoMapper.UnitTests.Bug { - public class When_mapping_for_derived_class_is_duplicated : SpecBase + public class When_mapping_for_derived_class_is_duplicated : NonValidatingSpecBase { public class ModelObject { diff --git a/src/UnitTests/BuildExecutionPlan.cs b/src/UnitTests/BuildExecutionPlan.cs index 7aa436f54c..fbdef71092 100644 --- a/src/UnitTests/BuildExecutionPlan.cs +++ b/src/UnitTests/BuildExecutionPlan.cs @@ -109,7 +109,8 @@ class Inner { } public void Should_consider_per_member_settings() { var destination = Map(new Source()); - destination.Inner.ShouldBeNull(); + destination.Inner.ShouldBeNull(); + new Action(() => Map("")).ShouldThrow().Message.ShouldNotContain("Destination member"); } } public class When_reusing_the_execution_plan : AutoMapperSpecBase diff --git a/src/UnitTests/ConfigurationRules.cs b/src/UnitTests/ConfigurationRules.cs index 4ebb267cd8..ebc900675a 100644 --- a/src/UnitTests/ConfigurationRules.cs +++ b/src/UnitTests/ConfigurationRules.cs @@ -6,7 +6,7 @@ namespace AutoMapper.UnitTests { - public class ConfigurationRules : SpecBase + public class ConfigurationRules : NonValidatingSpecBase { public class Source { } public class Dest { } diff --git a/src/UnitTests/ExplicitMapperCreation.cs b/src/UnitTests/ExplicitMapperCreation.cs index f20af41987..4298c79cdb 100644 --- a/src/UnitTests/ExplicitMapperCreation.cs +++ b/src/UnitTests/ExplicitMapperCreation.cs @@ -1,43 +1,22 @@ using Shouldly; using Xunit; - -namespace AutoMapper.UnitTests +namespace AutoMapper.UnitTests; +public class ExplicitMapperCreation : AutoMapperSpecBase { - public class ExplicitMapperCreation : SpecBase + protected override MapperConfiguration CreateConfiguration() =>new(cfg => cfg.CreateMap()); + public class Source { - private IMapper _mapper; - private MapperConfiguration _config; - - protected override void Establish_context() - { - _config = new MapperConfiguration(cfg => cfg.CreateMap()); - - _mapper = _config.CreateMapper(); - } - - public class Source - { - public int Value { get; set; } - } - - public class Dest - { - public int Value { get; set; } - } - - [Fact] - public void Should_map() - { - var source = new Source {Value = 10}; - var dest = _mapper.Map(source); - - dest.Value.ShouldBe(source.Value); - } - - [Fact] - public void Should_have_valid_config() - { - _config.AssertConfigurationIsValid(); - } + public int Value { get; set; } + } + public class Dest + { + public int Value { get; set; } + } + [Fact] + public void Should_map() + { + var source = new Source {Value = 10}; + var dest = Mapper.Map(source); + dest.Value.ShouldBe(source.Value); } } \ No newline at end of file diff --git a/src/UnitTests/ExpressionBridge.cs b/src/UnitTests/ExpressionBridge.cs index d71d56235a..3d8306cfb3 100644 --- a/src/UnitTests/ExpressionBridge.cs +++ b/src/UnitTests/ExpressionBridge.cs @@ -99,7 +99,7 @@ public class BillOfMaterials { public int BillOfMaterialsID { set; get; } } - public class When_mapping_using_expressions : SpecBase + public class When_mapping_using_expressions : NonValidatingSpecBase { private List _products; private Expression> _simpleProductConversionLinq; @@ -109,7 +109,7 @@ public class When_mapping_using_expressions : SpecBase private List _extendedProducts; private MapperConfiguration _config; - protected override void Establish_context() + protected override void Because_of() { _config = new MapperConfiguration(cfg => { @@ -160,16 +160,11 @@ protected override void Establish_context() } } }; - } - - protected override void Because_of() - { var queryable = _products.AsQueryable(); _simpleProducts = queryable.Select(_simpleProductConversionLinq).ToList(); _extendedProducts = queryable.Select(_extendedProductConversionLinq).ToList(); - } [Fact] diff --git a/src/UnitTests/IMappingExpression/NonGenericReverseMapping.cs b/src/UnitTests/IMappingExpression/NonGenericReverseMapping.cs index 725b907d06..f12525aad5 100644 --- a/src/UnitTests/IMappingExpression/NonGenericReverseMapping.cs +++ b/src/UnitTests/IMappingExpression/NonGenericReverseMapping.cs @@ -66,7 +66,7 @@ public class Dest public void Validate() => AssertConfigurationIsValid(); } - public class When_reverse_mapping_and_ignoring : SpecBase + public class When_reverse_mapping_and_ignoring : NonValidatingSpecBase { public class Foo { diff --git a/src/UnitTests/Internal/MapperTests.cs b/src/UnitTests/Internal/MapperTests.cs index 512b2c9966..24531120f3 100644 --- a/src/UnitTests/Internal/MapperTests.cs +++ b/src/UnitTests/Internal/MapperTests.cs @@ -3,7 +3,7 @@ namespace AutoMapper.UnitTests.Tests { - public class MapperTests : SpecBase + public class MapperTests : NonValidatingSpecBase { public class Source { diff --git a/src/UnitTests/Internal/TypeMapFactorySpecs.cs b/src/UnitTests/Internal/TypeMapFactorySpecs.cs index 106064694c..abd006bc46 100644 --- a/src/UnitTests/Internal/TypeMapFactorySpecs.cs +++ b/src/UnitTests/Internal/TypeMapFactorySpecs.cs @@ -16,7 +16,7 @@ public class StubNamingConvention : INamingConvention public string[] Split(string input) => SplittingExpression.Matches(input).Select(m=>m.Value).ToArray(); } - public class When_constructing_type_maps_with_matching_property_names : SpecBase + public class When_constructing_type_maps_with_matching_property_names : NonValidatingSpecBase { public class Source { @@ -95,7 +95,7 @@ private class TestProfile : Profile public void Should_split_using_naming_convention_rules() => AssertConfigurationIsValid(); } - public class When_using_a_source_member_name_replacer : SpecBase + public class When_using_a_source_member_name_replacer : NonValidatingSpecBase { public class Source { @@ -130,7 +130,7 @@ public void Should_map_properties_with_different_names() } } - public class When_using_a_source_member_name_replacer_with_profile : SpecBase + public class When_using_a_source_member_name_replacer_with_profile : NonValidatingSpecBase { public class Source { diff --git a/src/UnitTests/MappingInheritance/IncludedBaseMappingShouldInheritBaseMappings.cs b/src/UnitTests/MappingInheritance/IncludedBaseMappingShouldInheritBaseMappings.cs index ca7ed38e38..863fd9907f 100644 --- a/src/UnitTests/MappingInheritance/IncludedBaseMappingShouldInheritBaseMappings.cs +++ b/src/UnitTests/MappingInheritance/IncludedBaseMappingShouldInheritBaseMappings.cs @@ -6,7 +6,7 @@ namespace AutoMapper.UnitTests.Bug using AutoMapper; using CustomMapping; - public class IncludedMappingShouldInheritBaseMappings : SpecBase + public class IncludedMappingShouldInheritBaseMappings : NonValidatingSpecBase { public class ModelObject diff --git a/src/UnitTests/MappingInheritance/IncludedMappingShouldInheritBaseMappings.cs b/src/UnitTests/MappingInheritance/IncludedMappingShouldInheritBaseMappings.cs index e6eedf11a7..f889b14fbd 100644 --- a/src/UnitTests/MappingInheritance/IncludedMappingShouldInheritBaseMappings.cs +++ b/src/UnitTests/MappingInheritance/IncludedMappingShouldInheritBaseMappings.cs @@ -72,7 +72,7 @@ public void ShouldMapOk() keyValue.Value.ShouldBe("value1"); } } - public class IncludedBaseMappingShouldInheritBaseMappings : SpecBase + public class IncludedBaseMappingShouldInheritBaseMappings : NonValidatingSpecBase { public class ModelObject { diff --git a/src/UnitTests/MappingInheritance/ReverseMapWithInclude.cs b/src/UnitTests/MappingInheritance/ReverseMapWithInclude.cs index a5f8f91c02..867a6a438f 100644 --- a/src/UnitTests/MappingInheritance/ReverseMapWithInclude.cs +++ b/src/UnitTests/MappingInheritance/ReverseMapWithInclude.cs @@ -4,7 +4,7 @@ using Shouldly; using Xunit; - public class ReverseMapWithInclude : SpecBase + public class ReverseMapWithInclude : NonValidatingSpecBase { public class Duck : Animal { } public class DuckDto : AnimalDto { } diff --git a/src/UnitTests/MemberNameReplacers.cs b/src/UnitTests/MemberNameReplacers.cs index 4a2fb90909..869d4b360c 100644 --- a/src/UnitTests/MemberNameReplacers.cs +++ b/src/UnitTests/MemberNameReplacers.cs @@ -6,7 +6,7 @@ namespace AutoMapper.UnitTests { - public class When_using_a_member_name_replacer : SpecBase + public class When_using_a_member_name_replacer : NonValidatingSpecBase { public class Source { diff --git a/src/UnitTests/MemberResolution.cs b/src/UnitTests/MemberResolution.cs index 90665eca04..922dcd2079 100644 --- a/src/UnitTests/MemberResolution.cs +++ b/src/UnitTests/MemberResolution.cs @@ -581,9 +581,6 @@ public void Should_map_item_in_any_level_of_depth_in_the_hierarchy() public class When_ignoring_a_dto_property_during_configuration : AutoMapperSpecBase { - private IReadOnlyCollection _allTypeMaps; - private Source _source; - public class Source { public string Value { get; set; } @@ -609,7 +606,8 @@ public bool Ignored [Fact] public void Should_not_report_it_as_unmapped() { - foreach (var typeMap in _allTypeMaps) + var allTypeMaps = Configuration.GetAllTypeMaps(); + foreach (var typeMap in allTypeMaps) { typeMap.GetUnmappedPropertyNames().ShouldBeOfLength(0); } @@ -618,16 +616,10 @@ public void Should_not_report_it_as_unmapped() [Fact] public void Should_map_successfully() { - var destination = Mapper.Map(_source); + var destination = Mapper.Map(new Source {Value = "foo"}); destination.Value.ShouldBe("foo"); destination.Ignored.ShouldBeTrue(); } - - protected override void Establish_context() - { - _source = new Source {Value = "foo"}; - _allTypeMaps = Configuration.GetAllTypeMaps(); - } } public class When_mapping_dto_with_get_methods : AutoMapperSpecBase diff --git a/src/UnitTests/ReverseMapping.cs b/src/UnitTests/ReverseMapping.cs index 37a0ef4e9e..23a7cdbf86 100644 --- a/src/UnitTests/ReverseMapping.cs +++ b/src/UnitTests/ReverseMapping.cs @@ -568,7 +568,7 @@ public class Dest public void Validate() => AssertConfigurationIsValid(); } - public class When_reverse_mapping_and_ignoring : SpecBase + public class When_reverse_mapping_and_ignoring : NonValidatingSpecBase { public class Foo { From 806e73f589baf8956802701e12f6201eabae0015 Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Tue, 23 Aug 2022 07:24:36 +0300 Subject: [PATCH 43/67] cosmetic --- src/AutoMapper/ApiCompatBaseline.txt | 3 +- src/AutoMapper/AutoMapperMappingException.cs | 2 +- src/AutoMapper/Configuration/Conventions.cs | 24 +++---- .../Configuration/MapperConfiguration.cs | 4 +- src/AutoMapper/Configuration/Profile.cs | 2 +- src/AutoMapper/Execution/ExpressionBuilder.cs | 4 +- src/AutoMapper/Internal/TypePair.cs | 1 - src/AutoMapper/Mapper.cs | 1 - src/AutoMapper/MemberMap.cs | 1 - src/AutoMapper/TypeMap.cs | 2 +- src/UnitTests/AutoMapperSpecBase.cs | 69 ++++++++----------- src/UnitTests/BuildExecutionPlan.cs | 1 - 12 files changed, 52 insertions(+), 62 deletions(-) diff --git a/src/AutoMapper/ApiCompatBaseline.txt b/src/AutoMapper/ApiCompatBaseline.txt index 87e6596d25..0eef7863da 100644 --- a/src/AutoMapper/ApiCompatBaseline.txt +++ b/src/AutoMapper/ApiCompatBaseline.txt @@ -100,6 +100,7 @@ CannotChangeAttribute : Attribute 'System.Runtime.CompilerServices.IteratorState MembersMustExist : Member 'public System.Type System.Type AutoMapper.Internal.TypePair.DestinationType' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Type System.Type AutoMapper.Internal.TypePair.SourceType' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Boolean AutoMapper.Internal.TypePair.Equals(AutoMapper.Internal.TypePair)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public System.Boolean AutoMapper.Internal.TypePair.IsGenericTypeDefinition.get()' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Boolean AutoMapper.Internal.TypePair.op_Equality(AutoMapper.Internal.TypePair, AutoMapper.Internal.TypePair)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Boolean AutoMapper.Internal.TypePair.op_Inequality(AutoMapper.Internal.TypePair, AutoMapper.Internal.TypePair)' does not exist in the implementation but it does exist in the contract. CannotRemoveBaseTypeOrInterface : Type 'AutoMapper.Internal.Mappers.CollectionMapper' does not implement interface 'AutoMapper.Internal.Mappers.IObjectMapperInfo' in the implementation but it does in the contract. @@ -113,4 +114,4 @@ MembersMustExist : Member 'public AutoMapper.Internal.TypePair AutoMapper.Intern MembersMustExist : Member 'public System.Linq.IQueryable AutoMapper.QueryableExtensions.Extensions.Map(System.Linq.IQueryable, System.Linq.IQueryable, AutoMapper.IConfigurationProvider)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Collections.Generic.IReadOnlyCollection AutoMapper.QueryableExtensions.MemberVisitor.MemberPath.get()' does not exist in the implementation but it does exist in the contract. TypesMustExist : Type 'AutoMapper.QueryableExtensions.Impl.MemberAccessQueryMapperVisitor' does not exist in the implementation but it does exist in the contract. -Total Issues: 114 +Total Issues: 115 diff --git a/src/AutoMapper/AutoMapperMappingException.cs b/src/AutoMapper/AutoMapperMappingException.cs index 2190465677..85ee5ea676 100644 --- a/src/AutoMapper/AutoMapperMappingException.cs +++ b/src/AutoMapper/AutoMapperMappingException.cs @@ -53,7 +53,7 @@ public override string Message message += newLine + $"{TypeMap.SourceType.Name} -> {TypeMap.DestinationType.Name}"; message += newLine + $"{TypeMap.SourceType.FullName} -> {TypeMap.DestinationType.FullName}"; } - if (MemberMap?.TypeMap != null) + if (MemberMap != null) { message = message + newLine + newLine + "Destination Member:"; message += newLine + $"{MemberMap}" + newLine; diff --git a/src/AutoMapper/Configuration/Conventions.cs b/src/AutoMapper/Configuration/Conventions.cs index 6c30bebc28..70560ac5cc 100644 --- a/src/AutoMapper/Configuration/Conventions.cs +++ b/src/AutoMapper/Configuration/Conventions.cs @@ -9,7 +9,7 @@ namespace AutoMapper.Configuration.Conventions public interface ISourceToDestinationNameMapper { MemberInfo GetSourceMember(TypeDetails sourceTypeDetails, Type destType, Type destMemberType, string nameToSearch); - void Merge(ISourceToDestinationNameMapper otherNamedMapper); + void Merge(ISourceToDestinationNameMapper other); } [EditorBrowsable(EditorBrowsableState.Never)] public class MemberConfiguration @@ -35,9 +35,9 @@ public MemberInfo GetSourceMember(TypeDetails sourceTypeDetails, Type destType, { return sourceMember; } - foreach (var namedMapper in NameToMemberMappers) + foreach (var mapper in NameToMemberMappers) { - if ((sourceMember = namedMapper.GetSourceMember(sourceTypeDetails, destType, destMemberType, nameToSearch)) != null) + if ((sourceMember = mapper.GetSourceMember(sourceTypeDetails, destType, destMemberType, nameToSearch)) != null) { return sourceMember; } @@ -59,17 +59,17 @@ public void Merge(MemberConfiguration other) var initialCount = NameToMemberMappers.Count; for (int index = 0; index < other.NameToMemberMappers.Count; index++) { - var otherNamedMapper = other.NameToMemberMappers[index]; + var otherMapper = other.NameToMemberMappers[index]; if (index < initialCount) { - var namedMapper = NameToMemberMappers[index]; - if (namedMapper.GetType() == otherNamedMapper.GetType()) + var nameToMemberMapper = NameToMemberMappers[index]; + if (nameToMemberMapper.GetType() == otherMapper.GetType()) { - namedMapper.Merge(otherNamedMapper); + nameToMemberMapper.Merge(otherMapper); continue; } } - NameToMemberMappers.Add(otherNamedMapper); + NameToMemberMappers.Add(otherMapper); } } } @@ -89,9 +89,9 @@ public MemberInfo GetSourceMember(TypeDetails sourceTypeDetails, Type destType, } return null; } - public void Merge(ISourceToDestinationNameMapper otherNamedMapper) + public void Merge(ISourceToDestinationNameMapper other) { - var typedOther = (PrePostfixName)otherNamedMapper; + var typedOther = (PrePostfixName)other; DestinationPrefixes.UnionWith(typedOther.DestinationPrefixes); DestinationPostfixes.UnionWith(typedOther.DestinationPostfixes); } @@ -119,9 +119,9 @@ public MemberInfo GetSourceMember(TypeDetails sourceTypeDetails, Type destType, } return null; } - public void Merge(ISourceToDestinationNameMapper otherNamedMapper) + public void Merge(ISourceToDestinationNameMapper other) { - var typedOther = (ReplaceName)otherNamedMapper; + var typedOther = (ReplaceName)other; MemberNameReplacers.UnionWith(typedOther.MemberNameReplacers); } private string[] PossibleNames(string nameToSearch) => diff --git a/src/AutoMapper/Configuration/MapperConfiguration.cs b/src/AutoMapper/Configuration/MapperConfiguration.cs index b2bd46287e..58c4b74b76 100644 --- a/src/AutoMapper/Configuration/MapperConfiguration.cs +++ b/src/AutoMapper/Configuration/MapperConfiguration.cs @@ -177,7 +177,7 @@ static MapperConfigurationExpression Build(Action serviceCtor) => new Mapper(this, serviceCtor); public void CompileMappings() { - foreach (var request in _resolvedMaps.Keys.Where(t => !t.IsGenericTypeDefinition).Select(types => new MapRequest(types, types, MemberMap.Instance)).ToArray()) + foreach (var request in _resolvedMaps.Keys.Where(t => !t.ContainsGenericParameters).Select(types => new MapRequest(types, types, MemberMap.Instance)).ToArray()) { GetExecutionPlan(request); } @@ -234,7 +234,7 @@ LambdaExpression GenerateObjectMapperExpression(in MapRequest mapRequest, IObjec var newException = Call(MappingError, ExceptionParameter, Constant(mapRequest)); fullExpression = TryCatch(ToType(map, destinationType), Catch(ExceptionParameter, Throw(newException, destinationType))); } - var profileMap = mapRequest.MemberMap.Profile ?? Configuration; + var profileMap = mapRequest.MemberMap?.Profile ?? Configuration; fullExpression = this.NullCheckSource(profileMap, source, destination, fullExpression, mapRequest.MemberMap); return Lambda(fullExpression, source, destination, ContextParameter); } diff --git a/src/AutoMapper/Configuration/Profile.cs b/src/AutoMapper/Configuration/Profile.cs index 7c833a021a..62edc20834 100644 --- a/src/AutoMapper/Configuration/Profile.cs +++ b/src/AutoMapper/Configuration/Profile.cs @@ -158,7 +158,7 @@ public IMappingExpression CreateMap(Type sourceType, Type destinationType, Membe var types = new TypePair(sourceType, destinationType); var map = new MappingExpression(types, memberList); _typeMapConfigs.Add(map); - if (types.IsGenericTypeDefinition) + if (types.ContainsGenericParameters) { _openTypeMapConfigs ??= new(); _openTypeMapConfigs.Add(map); diff --git a/src/AutoMapper/Execution/ExpressionBuilder.cs b/src/AutoMapper/Execution/ExpressionBuilder.cs index b80f3022f2..645a8cf0a0 100644 --- a/src/AutoMapper/Execution/ExpressionBuilder.cs +++ b/src/AutoMapper/Execution/ExpressionBuilder.cs @@ -113,7 +113,9 @@ public static Expression NullCheckSource(this IGlobalConfiguration configuration var destinationType = destination.Type; var isCollection = destinationType.IsCollection(); var mustUseDestination = memberMap is { MustUseDestination: true }; - var ifSourceNull = mustUseDestination ? ClearDestinationCollection() : DefaultDestination(); + var ifSourceNull = memberMap == null ? + destination.IfNullElse(DefaultDestination(), ClearDestinationCollection()) : + mustUseDestination ? ClearDestinationCollection() : DefaultDestination(); return source.IfNullElse(ifSourceNull, mapExpression); Expression ClearDestinationCollection() { diff --git a/src/AutoMapper/Internal/TypePair.cs b/src/AutoMapper/Internal/TypePair.cs index 0d2da10037..5aed7ac2c9 100644 --- a/src/AutoMapper/Internal/TypePair.cs +++ b/src/AutoMapper/Internal/TypePair.cs @@ -12,7 +12,6 @@ public readonly record struct MapRequest(TypePair RequestedTypes, TypePair Runti public readonly record struct TypePair(Type SourceType, Type DestinationType) { public bool IsConstructedGenericType => SourceType.IsConstructedGenericType || DestinationType.IsConstructedGenericType; - public bool IsGenericTypeDefinition => SourceType.IsGenericTypeDefinition || DestinationType.IsGenericTypeDefinition; public bool ContainsGenericParameters => SourceType.ContainsGenericParameters || DestinationType.ContainsGenericParameters; public TypePair CloseGenericTypes(TypePair closedTypes) { diff --git a/src/AutoMapper/Mapper.cs b/src/AutoMapper/Mapper.cs index 6aee4c5687..88e79bde89 100644 --- a/src/AutoMapper/Mapper.cs +++ b/src/AutoMapper/Mapper.cs @@ -198,7 +198,6 @@ private TDestination MapCore( { TypePair requestedTypes = new(typeof(TSource), typeof(TDestination)); TypePair runtimeTypes = new(source?.GetType() ?? sourceType ?? typeof(TSource), destination?.GetType() ?? destinationType ?? typeof(TDestination)); - memberMap ??= destination == null ? MemberMap.Instance : MemberMap.InstanceUseDestination; MapRequest mapRequest = new(requestedTypes, runtimeTypes, memberMap); return _configuration.GetExecutionPlan(mapRequest)(source, destination, context); } diff --git a/src/AutoMapper/MemberMap.cs b/src/AutoMapper/MemberMap.cs index f185aeca82..c21ef0e1f3 100644 --- a/src/AutoMapper/MemberMap.cs +++ b/src/AutoMapper/MemberMap.cs @@ -18,7 +18,6 @@ public class MemberMap : IValueResolver { protected MemberMap(TypeMap typeMap = null) => TypeMap = typeMap; internal static readonly MemberMap Instance = new(); - internal static readonly MemberMap InstanceUseDestination = new PropertyMap(default(MemberInfo), null, null) { UseDestinationValue = true }; public TypeMap TypeMap { get; protected set; } public LambdaExpression CustomMapExpression => Resolver?.ProjectToExpression; public bool IsResolveConfigured => Resolver != null && Resolver != this; diff --git a/src/AutoMapper/TypeMap.cs b/src/AutoMapper/TypeMap.cs index 142bcb93b9..81232282f3 100644 --- a/src/AutoMapper/TypeMap.cs +++ b/src/AutoMapper/TypeMap.cs @@ -258,7 +258,7 @@ public void IncludeBaseTypes(TypePair baseTypes) public void AddValueTransformation(ValueTransformerConfiguration config) => Details.AddValueTransformation(config); public void ConstructUsingServiceLocator() => CustomCtorFunction = Lambda(ServiceLocator(DestinationType)); internal LambdaExpression CreateMapperLambda(IGlobalConfiguration configuration) => - Types.IsGenericTypeDefinition ? null : new TypeMapPlanBuilder(configuration, this).CreateMapperLambda(); + Types.ContainsGenericParameters ? null : new TypeMapPlanBuilder(configuration, this).CreateMapperLambda(); private PropertyMap GetPropertyMap(string name) => _propertyMaps?.GetValueOrDefault(name); private PropertyMap GetPropertyMap(PropertyMap propertyMap) => GetPropertyMap(propertyMap.DestinationName); public void AsProxy() => CustomCtorFunction = Lambda(Call(CreateProxyMethod, Constant(DestinationType))); diff --git a/src/UnitTests/AutoMapperSpecBase.cs b/src/UnitTests/AutoMapperSpecBase.cs index 3f65ec1299..edb4554a93 100644 --- a/src/UnitTests/AutoMapperSpecBase.cs +++ b/src/UnitTests/AutoMapperSpecBase.cs @@ -5,44 +5,12 @@ using System.Linq; using System.Linq.Expressions; namespace AutoMapper.UnitTests; -/// -/// Ignore this member for validation and skip during mapping -/// -[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] -public class IgnoreMapAttribute : Attribute -{ -} -static class Utils -{ - public static IMappingExpression Advanced(this IProjectionExpression projection) => - (IMappingExpression)projection; - public static TypeMap FindTypeMapFor(this IConfigurationProvider configurationProvider) => configurationProvider.Internal().FindTypeMapFor(); - public static IReadOnlyCollection GetAllTypeMaps(this IConfigurationProvider configurationProvider) => configurationProvider.Internal().GetAllTypeMaps(); - public static TypeMap ResolveTypeMap(this IConfigurationProvider configurationProvider, Type sourceType, Type destinationType) => configurationProvider.Internal().ResolveTypeMap(sourceType, destinationType); - public static void ForAllMaps(this IMapperConfigurationExpression configurationProvider, Action configuration) => configurationProvider.Internal().ForAllMaps(configuration); - public static void ForAllPropertyMaps(this IMapperConfigurationExpression configurationProvider, Func condition, Action memberOptions) => - configurationProvider.Internal().ForAllPropertyMaps(condition, memberOptions); - public static void AddIgnoreMapAttribute(this IMapperConfigurationExpression configuration) - { - configuration.ForAllMaps((typeMap, mapExpression) => mapExpression.ForAllMembers(memberOptions => - { - if (memberOptions.DestinationMember.Has()) - { - memberOptions.Ignore(); - } - })); - configuration.ForAllPropertyMaps(propertyMap => propertyMap.SourceMember?.Has() == true, - (_, memberOptions) => memberOptions.Ignore()); - } -} - public abstract class AutoMapperSpecBase : NonValidatingSpecBase { protected override void OnConfig(MapperConfiguration mapperConfiguration) => mapperConfiguration.AssertConfigurationIsValid(); - protected override void AssertConfigurationIsValid() => Configuration.Internal(); + protected sealed override void AssertConfigurationIsValid() => Configuration.Internal(); } - -public abstract class NonValidatingSpecBase : IDisposable +public abstract class NonValidatingSpecBase { protected NonValidatingSpecBase() { @@ -74,12 +42,35 @@ protected IQueryable ProjectTo(IQueryable source, ID protected virtual void Because_of() { } - protected virtual void Cleanup() - { - } - public void Dispose() +} +/// +/// Ignore this member for validation and skip during mapping +/// +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] +public class IgnoreMapAttribute : Attribute +{ +} +static class Utils +{ + public static IMappingExpression Advanced(this IProjectionExpression projection) => + (IMappingExpression)projection; + public static TypeMap FindTypeMapFor(this IConfigurationProvider configurationProvider) => configurationProvider.Internal().FindTypeMapFor(); + public static IReadOnlyCollection GetAllTypeMaps(this IConfigurationProvider configurationProvider) => configurationProvider.Internal().GetAllTypeMaps(); + public static TypeMap ResolveTypeMap(this IConfigurationProvider configurationProvider, Type sourceType, Type destinationType) => configurationProvider.Internal().ResolveTypeMap(sourceType, destinationType); + public static void ForAllMaps(this IMapperConfigurationExpression configurationProvider, Action configuration) => configurationProvider.Internal().ForAllMaps(configuration); + public static void ForAllPropertyMaps(this IMapperConfigurationExpression configurationProvider, Func condition, Action memberOptions) => + configurationProvider.Internal().ForAllPropertyMaps(condition, memberOptions); + public static void AddIgnoreMapAttribute(this IMapperConfigurationExpression configuration) { - Cleanup(); + configuration.ForAllMaps((typeMap, mapExpression) => mapExpression.ForAllMembers(memberOptions => + { + if (memberOptions.DestinationMember.Has()) + { + memberOptions.Ignore(); + } + })); + configuration.ForAllPropertyMaps(propertyMap => propertyMap.SourceMember?.Has() == true, + (_, memberOptions) => memberOptions.Ignore()); } } class FirstOrDefaultCounter : ExpressionVisitor diff --git a/src/UnitTests/BuildExecutionPlan.cs b/src/UnitTests/BuildExecutionPlan.cs index fbdef71092..713b888f23 100644 --- a/src/UnitTests/BuildExecutionPlan.cs +++ b/src/UnitTests/BuildExecutionPlan.cs @@ -110,7 +110,6 @@ public void Should_consider_per_member_settings() { var destination = Map(new Source()); destination.Inner.ShouldBeNull(); - new Action(() => Map("")).ShouldThrow().Message.ShouldNotContain("Destination member"); } } public class When_reusing_the_execution_plan : AutoMapperSpecBase From d0e0e24539c407d3ffe1406dc0ea04d682d8b3fe Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Wed, 31 Aug 2022 17:53:22 +0300 Subject: [PATCH 44/67] avoid changing the resolver configuration objects because they're reused by closed generic maps --- .../Execution/TypeMapPlanBuilder.cs | 24 ++++++++++--------- src/UnitTests/OpenGenerics.cs | 3 +++ src/UnitTests/TypeConverters.cs | 22 ++++------------- 3 files changed, 21 insertions(+), 28 deletions(-) diff --git a/src/AutoMapper/Execution/TypeMapPlanBuilder.cs b/src/AutoMapper/Execution/TypeMapPlanBuilder.cs index 35e5935b3d..35f3bb800f 100644 --- a/src/AutoMapper/Execution/TypeMapPlanBuilder.cs +++ b/src/AutoMapper/Execution/TypeMapPlanBuilder.cs @@ -457,26 +457,27 @@ public Expression GetExpression(IGlobalConfiguration configuration, MemberMap me } public abstract class ValueResolverConfig { - private protected Expression _instance; + private protected readonly Expression _instance; public Type ConcreteType { get; } - public Type InterfaceType { get; protected set; } - public LambdaExpression SourceMemberLambda { get; set; } - protected ValueResolverConfig(Type concreteType, Type interfaceType) + public Type InterfaceType { get; } + public LambdaExpression SourceMemberLambda { get; init; } + protected ValueResolverConfig(Type concreteType, Type interfaceType, Expression instance = null) { ConcreteType = concreteType; InterfaceType = interfaceType; + _instance = instance; } protected ValueResolverConfig(object instance, Type interfaceType) { _instance = Constant(instance); InterfaceType = interfaceType; } - public string SourceMemberName { get; set; } + public string SourceMemberName { get; init; } public Type ResolvedType => InterfaceType.GenericTypeArguments[^1]; } public class ValueConverter : ValueResolverConfig, IValueResolver { - public ValueConverter(Type concreteType, Type interfaceType) : base(concreteType, interfaceType) => _instance = ServiceLocator(concreteType); + public ValueConverter(Type concreteType, Type interfaceType) : base(concreteType, interfaceType, ServiceLocator(concreteType)) { } public ValueConverter(object instance, Type interfaceType) : base(instance, interfaceType) { } public Expression GetExpression(IGlobalConfiguration configuration, MemberMap memberMap, Expression source, Expression _, Expression destinationMember) { @@ -508,18 +509,19 @@ public Expression GetExpression(IGlobalConfiguration configuration, MemberMap me var typeMap = memberMap.TypeMap; var resolverInstance = _instance ?? ServiceLocator(typeMap.MakeGenericType(ConcreteType)); var sourceMember = SourceMemberLambda?.ReplaceParameters(source) ?? (SourceMemberName != null ? PropertyOrField(source, SourceMemberName) : null); - if (InterfaceType.ContainsGenericParameters) + var iValueResolver = InterfaceType; + if (iValueResolver.ContainsGenericParameters) { var typeArgs = - InterfaceType.GenericTypeArguments.Zip(new[] { typeMap.SourceType, typeMap.DestinationType, sourceMember?.Type, destinationMember.Type }.Where(t => t != null), + iValueResolver.GenericTypeArguments.Zip(new[] { typeMap.SourceType, typeMap.DestinationType, sourceMember?.Type, destinationMember.Type }.Where(t => t != null), (declaredType, runtimeType) => declaredType.ContainsGenericParameters ? runtimeType : declaredType).ToArray(); - InterfaceType = InterfaceType.GetGenericTypeDefinition().MakeGenericType(typeArgs); + iValueResolver = InterfaceType.GetGenericTypeDefinition().MakeGenericType(typeArgs); } var parameters = new[] { source, destination, sourceMember, destinationMember }.Where(p => p != null) - .Zip(InterfaceType.GenericTypeArguments, ToType) + .Zip(iValueResolver.GenericTypeArguments, ToType) .Append(ContextParameter) .ToArray(); - return Call(ToType(resolverInstance, InterfaceType), "Resolve", parameters); + return Call(ToType(resolverInstance, iValueResolver), "Resolve", parameters); } public MemberInfo GetSourceMember(MemberMap _) => SourceMemberLambda?.GetMember(); } diff --git a/src/UnitTests/OpenGenerics.cs b/src/UnitTests/OpenGenerics.cs index 84049636e1..403e96fa4e 100644 --- a/src/UnitTests/OpenGenerics.cs +++ b/src/UnitTests/OpenGenerics.cs @@ -233,6 +233,9 @@ public void Should_map_generic_destination() var destination = Map>(new KeyValuePair(1, 2)); destination.MyKey.ShouldBe("1"); destination.MyValue.ShouldBe("2"); + var destinationString = Map>(new KeyValuePair("1", "2")); + destinationString.MyKey.ShouldBe("1"); + destinationString.MyValue.ShouldBe("2"); } [Fact] public void Should_map_closed_to_ienumerable_generic_destination() diff --git a/src/UnitTests/TypeConverters.cs b/src/UnitTests/TypeConverters.cs index 53e7f25798..cb698180c6 100644 --- a/src/UnitTests/TypeConverters.cs +++ b/src/UnitTests/TypeConverters.cs @@ -133,43 +133,31 @@ public void Should_use_the_type_converter() public class When_specifying_type_converters_for_object_mapper_types : AutoMapperSpecBase { - Destination _destination; - class Source { public IDictionary Values { get; set; } } - class Destination { public IDictionary Values { get; set; } } - protected override MapperConfiguration CreateConfiguration() => new(cfg => { cfg.CreateMap(typeof(IDictionary<,>), typeof(IDictionary<,>)).ConvertUsing(typeof(DictionaryConverter<,>)); cfg.CreateMap(); }); - - protected override void Because_of() - { - _destination = Mapper.Map(new Source { Values = new Dictionary() }); - } - [Fact] public void Should_override_the_built_in_mapper() { - _destination.Values.ShouldBeSameAs(DictionaryConverter.Instance); + var destination = Mapper.Map(new Source { Values = new Dictionary() }); + destination.Values.ShouldBeSameAs(DictionaryConverter.Instance); + var destinationString = Mapper.Map>(new Dictionary()); + destinationString.ShouldBeSameAs(DictionaryConverter.Instance); } - private class DictionaryConverter : ITypeConverter, IDictionary> { public static readonly IDictionary Instance = new Dictionary(); - - public IDictionary Convert(IDictionary source, IDictionary destination, ResolutionContext context) - { - return Instance; - } + public IDictionary Convert(IDictionary source, IDictionary destination, ResolutionContext context) => Instance; } } From 77e00155e062ace0c4f3bc798f241b3ce4a8ef9c Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Wed, 31 Aug 2022 18:36:57 +0300 Subject: [PATCH 45/67] cosmetic --- src/AutoMapper/ApiCompatBaseline.txt | 3 ++- src/AutoMapper/AutoMapperMappingException.cs | 4 ++-- src/AutoMapper/Configuration/Conventions.cs | 14 ++++++------- src/AutoMapper/Configuration/Profile.cs | 8 ++++---- src/AutoMapper/ConstructorMap.cs | 3 ++- .../Execution/TypeMapPlanBuilder.cs | 20 +++++++++---------- src/UnitTests/ConfigurationValidation.cs | 2 +- src/UnitTests/Constructors.cs | 4 ++-- 8 files changed, 30 insertions(+), 28 deletions(-) diff --git a/src/AutoMapper/ApiCompatBaseline.txt b/src/AutoMapper/ApiCompatBaseline.txt index 0eef7863da..7a93b4f49e 100644 --- a/src/AutoMapper/ApiCompatBaseline.txt +++ b/src/AutoMapper/ApiCompatBaseline.txt @@ -88,6 +88,7 @@ MembersMustExist : Member 'public System.Boolean AutoMapper.Execution.TypeDescri CannotSealType : Type 'AutoMapper.Execution.TypeMapPlanBuilder' is actually (has the sealed modifier) sealed in the implementation but not sealed in the contract. TypeCannotChangeClassification : Type 'AutoMapper.Execution.TypeMapPlanBuilder' is a 'struct' in the implementation but is a 'class' in the contract. MembersMustExist : Member 'public System.Linq.Expressions.LambdaExpression AutoMapper.Execution.TypeMapPlanBuilder.CreateMapperLambda(System.Collections.Generic.HashSet)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public System.Linq.Expressions.ParameterExpression AutoMapper.Execution.TypeMapPlanBuilder.Source.get()' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Reflection.ConstructorInfo System.Reflection.ConstructorInfo AutoMapper.Internal.ConstructorParameters.Constructor' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Reflection.ParameterInfo[] System.Reflection.ParameterInfo[] AutoMapper.Internal.ConstructorParameters.Parameters' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public AutoMapper.Internal.TypePair AutoMapper.Internal.TypePair AutoMapper.Internal.MapRequest.RequestedTypes' does not exist in the implementation but it does exist in the contract. @@ -114,4 +115,4 @@ MembersMustExist : Member 'public AutoMapper.Internal.TypePair AutoMapper.Intern MembersMustExist : Member 'public System.Linq.IQueryable AutoMapper.QueryableExtensions.Extensions.Map(System.Linq.IQueryable, System.Linq.IQueryable, AutoMapper.IConfigurationProvider)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Collections.Generic.IReadOnlyCollection AutoMapper.QueryableExtensions.MemberVisitor.MemberPath.get()' does not exist in the implementation but it does exist in the contract. TypesMustExist : Type 'AutoMapper.QueryableExtensions.Impl.MemberAccessQueryMapperVisitor' does not exist in the implementation but it does exist in the contract. -Total Issues: 115 +Total Issues: 116 diff --git a/src/AutoMapper/AutoMapperMappingException.cs b/src/AutoMapper/AutoMapperMappingException.cs index 85ee5ea676..8bc00f3c19 100644 --- a/src/AutoMapper/AutoMapperMappingException.cs +++ b/src/AutoMapper/AutoMapperMappingException.cs @@ -154,7 +154,7 @@ public override string Message string.Format( "The following member on {0} cannot be mapped: \n\t{2} \nAdd a custom mapping expression, ignore, add a custom resolver, or modify the destination type {1}.", Types.Value.DestinationType.FullName, Types.Value.DestinationType.FullName, - MemberMap?.DestinationName); + MemberMap); message += "\nContext:"; @@ -165,7 +165,7 @@ public override string Message { message += configExc.MemberMap == null ? $"\n\tMapping from type {configExc.Types.Value.SourceType.FullName} to {configExc.Types.Value.DestinationType.FullName}" - : $"\n\tMapping to member {configExc.MemberMap.DestinationName} from {configExc.Types.Value.SourceType.FullName} to {configExc.Types.Value.DestinationType.FullName}"; + : $"\n\tMapping to member {configExc.MemberMap} from {configExc.Types.Value.SourceType.FullName} to {configExc.Types.Value.DestinationType.FullName}"; } exToUse = exToUse.InnerException; diff --git a/src/AutoMapper/Configuration/Conventions.cs b/src/AutoMapper/Configuration/Conventions.cs index 70560ac5cc..2425c841bd 100644 --- a/src/AutoMapper/Configuration/Conventions.cs +++ b/src/AutoMapper/Configuration/Conventions.cs @@ -15,8 +15,8 @@ public interface ISourceToDestinationNameMapper public class MemberConfiguration { NameSplitMember _nameSplitMember; - public INamingConvention SourceMemberNamingConvention { get; set; } = PascalCaseNamingConvention.Instance; - public INamingConvention DestinationMemberNamingConvention { get; set; } = PascalCaseNamingConvention.Instance; + public INamingConvention SourceNamingConvention { get; set; } = PascalCaseNamingConvention.Instance; + public INamingConvention DestinationNamingConvention { get; set; } = PascalCaseNamingConvention.Instance; public List NameToMemberMappers { get; } = new(); public bool IsMatch(ProfileMap options, TypeDetails sourceTypeDetails, Type destType, Type destMemberType, string nameToSearch, List resolvers, bool isReverseMap) { @@ -46,7 +46,7 @@ public MemberInfo GetSourceMember(TypeDetails sourceTypeDetails, Type destType, } public void Seal() { - var isDefault = SourceMemberNamingConvention == PascalCaseNamingConvention.Instance && DestinationMemberNamingConvention == PascalCaseNamingConvention.Instance; + var isDefault = SourceNamingConvention == PascalCaseNamingConvention.Instance && DestinationNamingConvention == PascalCaseNamingConvention.Instance; _nameSplitMember = isDefault ? new DefaultNameSplitMember() : new ConventionsNameSplitMember(); _nameSplitMember.Parent = this; } @@ -177,15 +177,15 @@ public sealed class ConventionsNameSplitMember : NameSplitMember { public sealed override bool IsMatch(ProfileMap options, TypeDetails sourceType, Type destType, Type destMemberType, string nameToSearch, List resolvers, bool isReverseMap) { - var destinationMemberNamingConvention = isReverseMap ? Parent.SourceMemberNamingConvention : Parent.DestinationMemberNamingConvention; - var matches = destinationMemberNamingConvention.Split(nameToSearch); + var destinationNamingConvention = isReverseMap ? Parent.SourceNamingConvention : Parent.DestinationNamingConvention; + var matches = destinationNamingConvention.Split(nameToSearch); var length = matches.Length; if (length < 2) { return false; } - var sourceMemberNamingConvention = isReverseMap ? Parent.DestinationMemberNamingConvention : Parent.SourceMemberNamingConvention; - var separator = sourceMemberNamingConvention.SeparatorCharacter; + var sourceNamingConvention = isReverseMap ? Parent.DestinationNamingConvention : Parent.SourceNamingConvention; + var separator = sourceNamingConvention.SeparatorCharacter; for (var index = 1; index <= length; index++) { var first = string.Join(separator, matches, 0, index); diff --git a/src/AutoMapper/Configuration/Profile.cs b/src/AutoMapper/Configuration/Profile.cs index 62edc20834..08c517f94e 100644 --- a/src/AutoMapper/Configuration/Profile.cs +++ b/src/AutoMapper/Configuration/Profile.cs @@ -108,13 +108,13 @@ IReadOnlyCollection> IProfil public Func ShouldUseConstructor { get; set; } public INamingConvention SourceMemberNamingConvention { - get => _memberConfiguration.SourceMemberNamingConvention; - set => _memberConfiguration.SourceMemberNamingConvention = value; + get => _memberConfiguration.SourceNamingConvention; + set => _memberConfiguration.SourceNamingConvention = value; } public INamingConvention DestinationMemberNamingConvention { - get => _memberConfiguration.DestinationMemberNamingConvention; - set => _memberConfiguration.DestinationMemberNamingConvention = value; + get => _memberConfiguration.DestinationNamingConvention; + set => _memberConfiguration.DestinationNamingConvention = value; } public List ValueTransformers => _valueTransformerConfigs ??= new(); List IProfileExpressionInternal.Prefixes => _prefixes; diff --git a/src/AutoMapper/ConstructorMap.cs b/src/AutoMapper/ConstructorMap.cs index 2755ced3b2..6fa2695608 100644 --- a/src/AutoMapper/ConstructorMap.cs +++ b/src/AutoMapper/ConstructorMap.cs @@ -98,6 +98,7 @@ public ConstructorParameterMap(ConstructorParameterMap parameterMap, IncludedMem public override MemberInfo[] SourceMembers { get; set; } public override string DestinationName => Parameter.Name; public Expression DefaultValue(IGlobalConfiguration configuration) => Parameter.IsOptional ? Parameter.GetDefaultValue(configuration) : configuration.Default(DestinationType); - public override string ToString() => Parameter.Member.DeclaringType + "." + Parameter.Member + ".parameter " + Parameter.Name; + public override string ToString() => $"{Constructor.DeclaringType} {Constructor}, parameter {DestinationName}"; + private MemberInfo Constructor => Parameter.Member; } } \ No newline at end of file diff --git a/src/AutoMapper/Execution/TypeMapPlanBuilder.cs b/src/AutoMapper/Execution/TypeMapPlanBuilder.cs index 35f3bb800f..bf135e2eef 100644 --- a/src/AutoMapper/Execution/TypeMapPlanBuilder.cs +++ b/src/AutoMapper/Execution/TypeMapPlanBuilder.cs @@ -18,6 +18,7 @@ public struct TypeMapPlanBuilder private readonly ParameterExpression _initialDestination; private readonly ParameterExpression[] _parameters; private readonly TypeMap _typeMap; + private readonly ParameterExpression _source; private List _variables; private List _expressions; private CatchBlock[] _catches; @@ -25,20 +26,19 @@ public TypeMapPlanBuilder(IGlobalConfiguration configuration, TypeMap typeMap) { _configuration = configuration; _typeMap = typeMap; - Source = Parameter(typeMap.SourceType, "source"); + _source = Parameter(typeMap.SourceType, "source"); _initialDestination = Parameter(typeMap.DestinationType, "destination"); - _destination = Variable(_initialDestination.Type, "typeMapDestination"); + _destination = Variable(typeMap.DestinationType, "typeMapDestination"); _variables = configuration.Variables; _expressions = configuration.Expressions; _catches = configuration.Catches; _parameters = _configuration.Parameters ?? new ParameterExpression[] { null, null, ContextParameter }; } public Type DestinationType => _destination.Type; - public ParameterExpression Source { get; } private static AutoMapperMappingException MemberMappingError(Exception innerException, MemberMap memberMap) => new("Error mapping types.", innerException, memberMap); ParameterExpression[] GetParameters(ParameterExpression first = null, ParameterExpression second = null) { - _parameters[0] = first ?? Source; + _parameters[0] = first ?? _source; _parameters[1] = second ?? _destination; return _parameters; } @@ -88,7 +88,7 @@ static void Clear(ref HashSet typeMapsPath) void IncludeMembers() { _variables.AddRange(_typeMap.IncludedMembersTypeMaps.Select(i => i.Variable)); - var source = Source; + var source = _source; _expressions.AddRange(_variables.Zip(_typeMap.IncludedMembersTypeMaps, (v, i) => Assign(v, i.MemberExpression.ReplaceParameters(source).NullCheck(null)))); } private static void CheckForCycles(IGlobalConfiguration configuration, TypeMap typeMap, HashSet typeMapsPath) @@ -166,7 +166,7 @@ private Expression CreateDestinationFunc() var getDest = DestinationType.IsValueType ? newDestFunc : Coalesce(_initialDestination, ToType(newDestFunc, DestinationType)); var destinationFunc = Assign(_destination, getDest); return _typeMap.PreserveReferences ? - Block(destinationFunc, Call(ContextParameter, CacheDestinationMethod, Source, Constant(DestinationType), _destination), _destination) : + Block(destinationFunc, Call(ContextParameter, CacheDestinationMethod, _source, Constant(DestinationType), _destination), _destination) : destinationFunc; } private Expression CreateAssignmentFunc(Expression createDestination) @@ -248,7 +248,7 @@ private Expression CreateMapperFunc(Expression assignmentFunc) { mapperFunc = Condition(overMaxDepth, _configuration.Default(DestinationType), mapperFunc); } - mapperFunc = _configuration.NullCheckSource(_typeMap.Profile, Source, _initialDestination, mapperFunc, null); + mapperFunc = _configuration.NullCheckSource(_typeMap.Profile, _source, _initialDestination, mapperFunc, null); return CheckReferencesCache(mapperFunc); } private Expression CheckReferencesCache(Expression valueBuilder) @@ -257,7 +257,7 @@ private Expression CheckReferencesCache(Expression valueBuilder) { return valueBuilder; } - var getCachedDestination = Call(ContextParameter, GetDestinationMethod, Source, Constant(DestinationType)); + var getCachedDestination = Call(ContextParameter, GetDestinationMethod, _source, Constant(DestinationType)); return Coalesce(ToType(getCachedDestination, DestinationType), valueBuilder); } private Expression CreateNewDestinationFunc() => _typeMap switch @@ -402,7 +402,7 @@ private Expression BuildValueResolverFunc(MemberMap memberMap, Expression custom } return valueResolverFunc; } - private ParameterExpression GetCustomSource(MemberMap memberMap) => memberMap.IncludedMember?.Variable ?? Source; + private ParameterExpression GetCustomSource(MemberMap memberMap) => memberMap.IncludedMember?.Variable ?? _source; } public interface IValueResolver { @@ -515,7 +515,7 @@ public Expression GetExpression(IGlobalConfiguration configuration, MemberMap me var typeArgs = iValueResolver.GenericTypeArguments.Zip(new[] { typeMap.SourceType, typeMap.DestinationType, sourceMember?.Type, destinationMember.Type }.Where(t => t != null), (declaredType, runtimeType) => declaredType.ContainsGenericParameters ? runtimeType : declaredType).ToArray(); - iValueResolver = InterfaceType.GetGenericTypeDefinition().MakeGenericType(typeArgs); + iValueResolver = iValueResolver.GetGenericTypeDefinition().MakeGenericType(typeArgs); } var parameters = new[] { source, destination, sourceMember, destinationMember }.Where(p => p != null) .Zip(iValueResolver.GenericTypeArguments, ToType) diff --git a/src/UnitTests/ConfigurationValidation.cs b/src/UnitTests/ConfigurationValidation.cs index 22df1fcf97..d7c36aa70c 100644 --- a/src/UnitTests/ConfigurationValidation.cs +++ b/src/UnitTests/ConfigurationValidation.cs @@ -35,7 +35,7 @@ private ComplexType(int someMember) [Fact] public void Should_fail_validation() => new Action(AssertConfigurationIsValid).ShouldThrowException(ex=> - ex.MemberMap.ToString().ShouldBe("AutoMapper.UnitTests.ConfigurationValidation.ConstructorMappingValidation+Destination.Void .ctor(ComplexType).parameter myComplexMember")); + ex.MemberMap.ToString().ShouldBe("AutoMapper.UnitTests.ConfigurationValidation.ConstructorMappingValidation+Destination Void .ctor(ComplexType), parameter myComplexMember")); } public class When_using_a_type_converter : AutoMapperSpecBase diff --git a/src/UnitTests/Constructors.cs b/src/UnitTests/Constructors.cs index f5630741b6..c5a451479e 100644 --- a/src/UnitTests/Constructors.cs +++ b/src/UnitTests/Constructors.cs @@ -992,8 +992,8 @@ public Dest(Dest foo) [Fact] public void Should_say_what_parameter_fails() { - new Action(AssertConfigurationIsValid).ShouldThrowException(ex => - ex.MemberMap.ToString().ShouldBe("AutoMapper.UnitTests.Constructors.When_mapping_constructor_argument_fails+Dest.Void .ctor(Dest).parameter foo")); + var ex = new Action(AssertConfigurationIsValid).ShouldThrow(); + ex.Message.ShouldContain("AutoMapper.UnitTests.Constructors.When_mapping_constructor_argument_fails+Dest Void .ctor(Dest), parameter foo", Case.Sensitive); } } From 20c283acd65e996dc7dac6ea40c19e9a75f50d29 Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Sat, 3 Sep 2022 13:47:18 +0300 Subject: [PATCH 46/67] less allocations --- .../Configuration/MapperConfiguration.cs | 803 +++++++++--------- src/AutoMapper/Execution/ExpressionBuilder.cs | 69 +- .../Execution/TypeMapPlanBuilder.cs | 42 +- src/AutoMapper/Internal/InternalApi.cs | 3 + .../QueryableExtensions/ProjectionBuilder.cs | 2 +- 5 files changed, 470 insertions(+), 449 deletions(-) diff --git a/src/AutoMapper/Configuration/MapperConfiguration.cs b/src/AutoMapper/Configuration/MapperConfiguration.cs index 58c4b74b76..5b7128a90c 100644 --- a/src/AutoMapper/Configuration/MapperConfiguration.cs +++ b/src/AutoMapper/Configuration/MapperConfiguration.cs @@ -3,486 +3,491 @@ using System.Linq; using System.Linq.Expressions; using System.Reflection; -using AutoMapper.Configuration; -using AutoMapper.Features; -using AutoMapper.Internal; -using AutoMapper.Internal.Mappers; -using AutoMapper.QueryableExtensions.Impl; -namespace AutoMapper +namespace AutoMapper; +using Configuration; +using Execution; +using Features; +using Internal; +using Internal.Mappers; +using QueryableExtensions.Impl; +using static Expression; +using static Execution.ExpressionBuilder; +public interface IConfigurationProvider { - using static Expression; - using static Execution.ExpressionBuilder; - public interface IConfigurationProvider - { - /// - /// Dry run all configured type maps and throw for each problem - /// - void AssertConfigurationIsValid(); - /// - /// Create a mapper instance based on this configuration. Mapper instances are lightweight and can be created as needed. - /// - /// The mapper instance - IMapper CreateMapper(); - /// - /// Create a mapper instance with the specified service constructor to be used for resolvers and type converters. - /// - /// Service factory to create services - /// The mapper instance - IMapper CreateMapper(Func serviceCtor); - /// - /// Builds the execution plan used to map the source to destination. - /// Useful to understand what exactly is happening during mapping. - /// See the wiki for details. - /// - /// the runtime type of the source object - /// the runtime type of the destination object - /// the execution plan - LambdaExpression BuildExecutionPlan(Type sourceType, Type destinationType); - /// - /// Compile all underlying mapping expressions to cached delegates. - /// Use if you want AutoMapper to compile all mappings up front instead of deferring expression compilation for each first map. - /// - void CompileMappings(); - } - public class MapperConfiguration : IGlobalConfiguration + /// + /// Dry run all configured type maps and throw for each problem + /// + void AssertConfigurationIsValid(); + /// + /// Create a mapper instance based on this configuration. Mapper instances are lightweight and can be created as needed. + /// + /// The mapper instance + IMapper CreateMapper(); + /// + /// Create a mapper instance with the specified service constructor to be used for resolvers and type converters. + /// + /// Service factory to create services + /// The mapper instance + IMapper CreateMapper(Func serviceCtor); + /// + /// Builds the execution plan used to map the source to destination. + /// Useful to understand what exactly is happening during mapping. + /// See the wiki for details. + /// + /// the runtime type of the source object + /// the runtime type of the destination object + /// the execution plan + LambdaExpression BuildExecutionPlan(Type sourceType, Type destinationType); + /// + /// Compile all underlying mapping expressions to cached delegates. + /// Use if you want AutoMapper to compile all mappings up front instead of deferring expression compilation for each first map. + /// + void CompileMappings(); +} +public class MapperConfiguration : IGlobalConfiguration +{ + private static readonly MethodInfo MappingError = typeof(MapperConfiguration).GetMethod(nameof(GetMappingError)); + private readonly IObjectMapper[] _mappers; + private readonly Dictionary _configuredMaps; + private readonly Dictionary _resolvedMaps; + private readonly LockingConcurrentDictionary _runtimeMaps; + private readonly ProjectionBuilder _projectionBuilder; + private readonly LockingConcurrentDictionary _executionPlans; + private readonly ConfigurationValidator _validator; + private readonly Features _features = new(); + private readonly int _recursiveQueriesMaxDepth; + private readonly int _maxExecutionPlanDepth; + private readonly bool _enableNullPropagationForQueryMapping; + private readonly Func _serviceCtor; + private readonly bool _sealed; + private readonly bool _hasOpenMaps; + private readonly HashSet _typeMapsPath = new(); + private readonly List _sourceMembers = new(); + private readonly List _variables = new(); + private readonly ParameterExpression[] _parameters = new[] { null, null, ContextParameter }; + private readonly CatchBlock[] _catches = new CatchBlock[1]; + private readonly List _expressions = new(); + private readonly Dictionary _defaults; + private readonly ParameterReplaceVisitor _parameterReplaceVisitor = new(); + private readonly ConvertParameterReplaceVisitor _convertParameterReplaceVisitor = new(); + public MapperConfiguration(MapperConfigurationExpression configurationExpression) { - private static readonly MethodInfo MappingError = typeof(MapperConfiguration).GetMethod(nameof(GetMappingError)); - private readonly IObjectMapper[] _mappers; - private readonly Dictionary _configuredMaps; - private readonly Dictionary _resolvedMaps; - private readonly LockingConcurrentDictionary _runtimeMaps; - private readonly ProjectionBuilder _projectionBuilder; - private readonly LockingConcurrentDictionary _executionPlans; - private readonly ConfigurationValidator _validator; - private readonly Features _features = new(); - private readonly int _recursiveQueriesMaxDepth; - private readonly int _maxExecutionPlanDepth; - private readonly bool _enableNullPropagationForQueryMapping; - private readonly Func _serviceCtor; - private readonly bool _sealed; - private readonly bool _hasOpenMaps; - private readonly HashSet _typeMapsPath = new(); - private readonly List _sourceMembers = new(); - private readonly List _variables = new(); - private readonly ParameterExpression[] _parameters = new[] { null, null, ContextParameter }; - private readonly CatchBlock[] _catches = new CatchBlock[1]; - private readonly List _expressions = new(); - private readonly Dictionary _defaults; - public MapperConfiguration(MapperConfigurationExpression configurationExpression) + var configuration = (IGlobalConfigurationExpression)configurationExpression; + if (configuration.MethodMappingEnabled != false) { - var configuration = (IGlobalConfigurationExpression)configurationExpression; - if (configuration.MethodMappingEnabled != false) - { - configuration.IncludeSourceExtensionMethods(typeof(Enumerable)); - } - _mappers = configuration.Mappers.ToArray(); - _executionPlans = new(CompileExecutionPlan); - _validator = new(configuration); - _projectionBuilder = new(this, configuration.ProjectionMappers.ToArray()); + configuration.IncludeSourceExtensionMethods(typeof(Enumerable)); + } + _mappers = configuration.Mappers.ToArray(); + _executionPlans = new(CompileExecutionPlan); + _validator = new(configuration); + _projectionBuilder = new(this, configuration.ProjectionMappers.ToArray()); - _serviceCtor = configuration.ServiceCtor; - _enableNullPropagationForQueryMapping = configuration.EnableNullPropagationForQueryMapping ?? false; - _maxExecutionPlanDepth = configuration.MaxExecutionPlanDepth + 1; - _recursiveQueriesMaxDepth = configuration.RecursiveQueriesMaxDepth; + _serviceCtor = configuration.ServiceCtor; + _enableNullPropagationForQueryMapping = configuration.EnableNullPropagationForQueryMapping ?? false; + _maxExecutionPlanDepth = configuration.MaxExecutionPlanDepth + 1; + _recursiveQueriesMaxDepth = configuration.RecursiveQueriesMaxDepth; - Configuration = new((IProfileConfiguration)configuration); - int typeMapsCount = Configuration.TypeMapsCount; - int openTypeMapsCount = Configuration.OpenTypeMapsCount; - Profiles = new ProfileMap[configuration.Profiles.Count + 1]; - Profiles[0] = Configuration; - int index = 1; - foreach (var profile in configuration.Profiles) - { - var profileMap = new ProfileMap(profile, configuration); - Profiles[index++] = profileMap; - typeMapsCount += profileMap.TypeMapsCount; - openTypeMapsCount += profileMap.OpenTypeMapsCount; - } - _defaults = new(3 * typeMapsCount); - _configuredMaps = new(typeMapsCount); - _hasOpenMaps = openTypeMapsCount > 0; - _runtimeMaps = new(GetTypeMap, openTypeMapsCount); - _resolvedMaps = new(2 * typeMapsCount); - configuration.Features.Configure(this); + Configuration = new((IProfileConfiguration)configuration); + int typeMapsCount = Configuration.TypeMapsCount; + int openTypeMapsCount = Configuration.OpenTypeMapsCount; + Profiles = new ProfileMap[configuration.Profiles.Count + 1]; + Profiles[0] = Configuration; + int index = 1; + foreach (var profile in configuration.Profiles) + { + var profileMap = new ProfileMap(profile, configuration); + Profiles[index++] = profileMap; + typeMapsCount += profileMap.TypeMapsCount; + openTypeMapsCount += profileMap.OpenTypeMapsCount; + } + _defaults = new(3 * typeMapsCount); + _configuredMaps = new(typeMapsCount); + _hasOpenMaps = openTypeMapsCount > 0; + _runtimeMaps = new(GetTypeMap, openTypeMapsCount); + _resolvedMaps = new(2 * typeMapsCount); + configuration.Features.Configure(this); - Seal(); + Seal(); + foreach (var profile in Profiles) + { + profile.Clear(); + } + _configuredMaps.TrimExcess(); + _resolvedMaps.TrimExcess(); + _typeMapsPath = null; + _sourceMembers = null; + _expressions = null; + _variables = null; + _parameters = null; + _catches = null; + _defaults = null; + _convertParameterReplaceVisitor = null; + _parameterReplaceVisitor = null; + _sealed = true; + return; + void Seal() + { foreach (var profile in Profiles) { - profile.Clear(); + profile.Register(this); } - _configuredMaps.TrimExcess(); - _resolvedMaps.TrimExcess(); - _typeMapsPath = null; - _sourceMembers = null; - _expressions = null; - _variables = null; - _parameters = null; - _catches = null; - _defaults = null; - _sealed = true; - return; - void Seal() + foreach (var profile in Profiles) { - foreach (var profile in Profiles) - { - profile.Register(this); - } - foreach (var profile in Profiles) - { - profile.Configure(this); - } - IGlobalConfiguration globalConfiguration = this; - var derivedMaps = new List(); - foreach (var typeMap in _configuredMaps.Values) - { - _resolvedMaps[typeMap.Types] = typeMap; - derivedMaps.Clear(); - GetDerivedTypeMaps(typeMap, derivedMaps); - foreach (var derivedMap in derivedMaps) - { - var includedPair = new TypePair(derivedMap.SourceType, typeMap.DestinationType); - _resolvedMaps.TryAdd(includedPair, derivedMap); - } - } - foreach (var typeMap in _configuredMaps.Values) - { - typeMap.Seal(this); - } - _features.Seal(this); + profile.Configure(this); } - void GetDerivedTypeMaps(TypeMap typeMap, List typeMaps) + IGlobalConfiguration globalConfiguration = this; + var derivedMaps = new List(); + foreach (var typeMap in _configuredMaps.Values) { - foreach (var derivedMap in this.Internal().GetIncludedTypeMaps(typeMap)) + _resolvedMaps[typeMap.Types] = typeMap; + derivedMaps.Clear(); + GetDerivedTypeMaps(typeMap, derivedMaps); + foreach (var derivedMap in derivedMaps) { - typeMaps.Add(derivedMap); - GetDerivedTypeMaps(derivedMap, typeMaps); + var includedPair = new TypePair(derivedMap.SourceType, typeMap.DestinationType); + _resolvedMaps.TryAdd(includedPair, derivedMap); } } - Delegate CompileExecutionPlan(MapRequest mapRequest) + foreach (var typeMap in _configuredMaps.Values) { - var executionPlan = ((IGlobalConfiguration)this).BuildExecutionPlan(mapRequest); - return executionPlan.Compile(); // breakpoint here to inspect all execution plans + typeMap.Seal(this); } + _features.Seal(this); } - public MapperConfiguration(Action configure) : this(Build(configure)){} - static MapperConfigurationExpression Build(Action configure) - { - MapperConfigurationExpression expr = new(); - configure(expr); - return expr; - } - public void AssertConfigurationIsValid() => _validator.AssertConfigurationExpressionIsValid(this, _configuredMaps.Values); - public IMapper CreateMapper() => new Mapper(this); - public IMapper CreateMapper(Func serviceCtor) => new Mapper(this, serviceCtor); - public void CompileMappings() + void GetDerivedTypeMaps(TypeMap typeMap, List typeMaps) { - foreach (var request in _resolvedMaps.Keys.Where(t => !t.ContainsGenericParameters).Select(types => new MapRequest(types, types, MemberMap.Instance)).ToArray()) + foreach (var derivedMap in this.Internal().GetIncludedTypeMaps(typeMap)) { - GetExecutionPlan(request); + typeMaps.Add(derivedMap); + GetDerivedTypeMaps(derivedMap, typeMaps); } } - public LambdaExpression BuildExecutionPlan(Type sourceType, Type destinationType) + Delegate CompileExecutionPlan(MapRequest mapRequest) + { + var executionPlan = ((IGlobalConfiguration)this).BuildExecutionPlan(mapRequest); + return executionPlan.Compile(); // breakpoint here to inspect all execution plans + } + } + public MapperConfiguration(Action configure) : this(Build(configure)){} + static MapperConfigurationExpression Build(Action configure) + { + MapperConfigurationExpression expr = new(); + configure(expr); + return expr; + } + public void AssertConfigurationIsValid() => _validator.AssertConfigurationExpressionIsValid(this, _configuredMaps.Values); + public IMapper CreateMapper() => new Mapper(this); + public IMapper CreateMapper(Func serviceCtor) => new Mapper(this, serviceCtor); + public void CompileMappings() + { + foreach (var request in _resolvedMaps.Keys.Where(t => !t.ContainsGenericParameters).Select(types => new MapRequest(types, types, MemberMap.Instance)).ToArray()) + { + GetExecutionPlan(request); + } + } + public LambdaExpression BuildExecutionPlan(Type sourceType, Type destinationType) + { + var typePair = new TypePair(sourceType, destinationType); + return this.Internal().BuildExecutionPlan(new(typePair, typePair, MemberMap.Instance)); + } + LambdaExpression IGlobalConfiguration.BuildExecutionPlan(in MapRequest mapRequest) + { + var typeMap = ResolveTypeMap(mapRequest.RuntimeTypes) ?? ResolveTypeMap(mapRequest.RequestedTypes); + if (typeMap != null) { - var typePair = new TypePair(sourceType, destinationType); - return this.Internal().BuildExecutionPlan(new(typePair, typePair, MemberMap.Instance)); + return GenerateTypeMapExpression(mapRequest.RequestedTypes, typeMap); } - LambdaExpression IGlobalConfiguration.BuildExecutionPlan(in MapRequest mapRequest) + var mapperToUse = FindMapper(mapRequest.RuntimeTypes); + return GenerateObjectMapperExpression(mapRequest, mapperToUse); + static LambdaExpression GenerateTypeMapExpression(TypePair requestedTypes, TypeMap typeMap) { - var typeMap = ResolveTypeMap(mapRequest.RuntimeTypes) ?? ResolveTypeMap(mapRequest.RequestedTypes); - if (typeMap != null) + typeMap.CheckProjection(); + if (requestedTypes == typeMap.Types) { - return GenerateTypeMapExpression(mapRequest.RequestedTypes, typeMap); + return typeMap.MapExpression; } - var mapperToUse = FindMapper(mapRequest.RuntimeTypes); - return GenerateObjectMapperExpression(mapRequest, mapperToUse); - static LambdaExpression GenerateTypeMapExpression(TypePair requestedTypes, TypeMap typeMap) + var requestedDestinationType = requestedTypes.DestinationType; + var source = Parameter(requestedTypes.SourceType, "source"); + var destination = Parameter(requestedDestinationType, "typeMapDestination"); + var checkNullValueTypeDest = CheckNullValueType(destination, typeMap.DestinationType); + return Lambda(ToType(typeMap.Invoke(source, checkNullValueTypeDest), requestedDestinationType), source, destination, ContextParameter); + } + static Expression CheckNullValueType(Expression expression, Type runtimeType) => + !expression.Type.IsValueType && runtimeType.IsValueType ? Coalesce(expression, Default(runtimeType)) : expression; + LambdaExpression GenerateObjectMapperExpression(in MapRequest mapRequest, IObjectMapper mapper) + { + var source = Parameter(mapRequest.RequestedTypes.SourceType, "source"); + var destinationType = mapRequest.RequestedTypes.DestinationType; + var destination = Parameter(destinationType, "mapperDestination"); + var runtimeDestinationType = mapRequest.RuntimeTypes.DestinationType; + Expression fullExpression; + if (mapper == null) { - typeMap.CheckProjection(); - if (requestedTypes == typeMap.Types) + var exception = new AutoMapperMappingException("Missing type map configuration or unsupported mapping.", null, mapRequest.RuntimeTypes) { - return typeMap.MapExpression; - } - var requestedDestinationType = requestedTypes.DestinationType; - var source = Parameter(requestedTypes.SourceType, "source"); - var destination = Parameter(requestedDestinationType, "typeMapDestination"); - var checkNullValueTypeDest = CheckNullValueType(destination, typeMap.DestinationType); - return Lambda(ToType(typeMap.Invoke(source, checkNullValueTypeDest), requestedDestinationType), source, destination, ContextParameter); + MemberMap = mapRequest.MemberMap + }; + fullExpression = Throw(Constant(exception), runtimeDestinationType); } - static Expression CheckNullValueType(Expression expression, Type runtimeType) => - !expression.Type.IsValueType && runtimeType.IsValueType ? Coalesce(expression, Default(runtimeType)) : expression; - LambdaExpression GenerateObjectMapperExpression(in MapRequest mapRequest, IObjectMapper mapper) + else { - var source = Parameter(mapRequest.RequestedTypes.SourceType, "source"); - var destinationType = mapRequest.RequestedTypes.DestinationType; - var destination = Parameter(destinationType, "mapperDestination"); - var runtimeDestinationType = mapRequest.RuntimeTypes.DestinationType; - Expression fullExpression; - if (mapper == null) - { - var exception = new AutoMapperMappingException("Missing type map configuration or unsupported mapping.", null, mapRequest.RuntimeTypes) - { - MemberMap = mapRequest.MemberMap - }; - fullExpression = Throw(Constant(exception), runtimeDestinationType); - } - else - { - var checkNullValueTypeDest = CheckNullValueType(destination, runtimeDestinationType); - var mapperSource = ToType(source, mapRequest.RuntimeTypes.SourceType); - var map = mapper.MapExpression(this, Configuration, mapRequest.MemberMap, mapperSource, ToType(checkNullValueTypeDest, runtimeDestinationType)); - var newException = Call(MappingError, ExceptionParameter, Constant(mapRequest)); - fullExpression = TryCatch(ToType(map, destinationType), Catch(ExceptionParameter, Throw(newException, destinationType))); - } - var profileMap = mapRequest.MemberMap?.Profile ?? Configuration; - fullExpression = this.NullCheckSource(profileMap, source, destination, fullExpression, mapRequest.MemberMap); - return Lambda(fullExpression, source, destination, ContextParameter); + var checkNullValueTypeDest = CheckNullValueType(destination, runtimeDestinationType); + var mapperSource = ToType(source, mapRequest.RuntimeTypes.SourceType); + var map = mapper.MapExpression(this, Configuration, mapRequest.MemberMap, mapperSource, ToType(checkNullValueTypeDest, runtimeDestinationType)); + var newException = Call(MappingError, ExceptionParameter, Constant(mapRequest)); + fullExpression = TryCatch(ToType(map, destinationType), Catch(ExceptionParameter, Throw(newException, destinationType))); } + var profileMap = mapRequest.MemberMap?.Profile ?? Configuration; + fullExpression = this.NullCheckSource(profileMap, source, destination, fullExpression, mapRequest.MemberMap); + return Lambda(fullExpression, source, destination, ContextParameter); } - IProjectionBuilder IGlobalConfiguration.ProjectionBuilder => _projectionBuilder; - Func IGlobalConfiguration.ServiceCtor => _serviceCtor; - bool IGlobalConfiguration.EnableNullPropagationForQueryMapping => _enableNullPropagationForQueryMapping; - int IGlobalConfiguration.MaxExecutionPlanDepth => _maxExecutionPlanDepth; - private ProfileMap Configuration { get; } - ProfileMap[] IGlobalConfiguration.Profiles => Profiles; - internal ProfileMap[] Profiles { get; } - int IGlobalConfiguration.RecursiveQueriesMaxDepth => _recursiveQueriesMaxDepth; - Features IGlobalConfiguration.Features => _features; - List IGlobalConfiguration.SourceMembers => _sourceMembers; - List IGlobalConfiguration.Variables => _variables; - List IGlobalConfiguration.Expressions => _expressions; - HashSet IGlobalConfiguration.TypeMapsPath => _typeMapsPath; - ParameterExpression[] IGlobalConfiguration.Parameters => _parameters; - CatchBlock[] IGlobalConfiguration.Catches => _catches; - DefaultExpression IGlobalConfiguration.GetDefault(Type type) + } + IProjectionBuilder IGlobalConfiguration.ProjectionBuilder => _projectionBuilder; + Func IGlobalConfiguration.ServiceCtor => _serviceCtor; + bool IGlobalConfiguration.EnableNullPropagationForQueryMapping => _enableNullPropagationForQueryMapping; + int IGlobalConfiguration.MaxExecutionPlanDepth => _maxExecutionPlanDepth; + private ProfileMap Configuration { get; } + ProfileMap[] IGlobalConfiguration.Profiles => Profiles; + internal ProfileMap[] Profiles { get; } + int IGlobalConfiguration.RecursiveQueriesMaxDepth => _recursiveQueriesMaxDepth; + Features IGlobalConfiguration.Features => _features; + List IGlobalConfiguration.SourceMembers => _sourceMembers; + List IGlobalConfiguration.Variables => _variables; + List IGlobalConfiguration.Expressions => _expressions; + HashSet IGlobalConfiguration.TypeMapsPath => _typeMapsPath; + ParameterExpression[] IGlobalConfiguration.Parameters => _parameters; + CatchBlock[] IGlobalConfiguration.Catches => _catches; + ConvertParameterReplaceVisitor IGlobalConfiguration.ConvertParameterReplaceVisitor() => _convertParameterReplaceVisitor ?? new(); + ParameterReplaceVisitor IGlobalConfiguration.ParameterReplaceVisitor() => _parameterReplaceVisitor ?? new(); + DefaultExpression IGlobalConfiguration.GetDefault(Type type) + { + if (_defaults == null) { - if (_defaults == null) - { - return Default(type); - } - if (!_defaults.TryGetValue(type, out var defaultExpression)) - { - defaultExpression = Default(type); - _defaults.Add(type, defaultExpression); - } - return defaultExpression; + return Default(type); } - Func IGlobalConfiguration.GetExecutionPlan(in MapRequest mapRequest) - => (Func)GetExecutionPlan(mapRequest); - private Delegate GetExecutionPlan(in MapRequest mapRequest) => _executionPlans.GetOrAdd(mapRequest); - TypeMap IGlobalConfiguration.ResolveAssociatedTypeMap(TypePair types) + if (!_defaults.TryGetValue(type, out var defaultExpression)) { - var typeMap = ResolveTypeMap(types); - if (typeMap != null) - { - return typeMap; - } - if (FindMapper(types)?.GetAssociatedTypes(types) is TypePair newTypes) - { - return ResolveTypeMap(newTypes); - } - return null; + defaultExpression = Default(type); + _defaults.Add(type, defaultExpression); } - public static AutoMapperMappingException GetMappingError(Exception innerException, in MapRequest mapRequest) => - new("Error mapping types.", innerException, mapRequest.RuntimeTypes) { MemberMap = mapRequest.MemberMap }; - IReadOnlyCollection IGlobalConfiguration.GetAllTypeMaps() => _configuredMaps.Values; - TypeMap IGlobalConfiguration.FindTypeMapFor(Type sourceType, Type destinationType) => FindTypeMapFor(sourceType, destinationType); - TypeMap IGlobalConfiguration.FindTypeMapFor() => FindTypeMapFor(typeof(TSource), typeof(TDestination)); - TypeMap IGlobalConfiguration.FindTypeMapFor(TypePair typePair) => FindTypeMapFor(typePair); - TypeMap FindTypeMapFor(Type sourceType, Type destinationType) => FindTypeMapFor(new(sourceType, destinationType)); - TypeMap FindTypeMapFor(TypePair typePair) => _configuredMaps.GetValueOrDefault(typePair); - TypeMap IGlobalConfiguration.ResolveTypeMap(Type sourceType, Type destinationType) => ResolveTypeMap(new(sourceType, destinationType)); - TypeMap IGlobalConfiguration.ResolveTypeMap(TypePair typePair) => ResolveTypeMap(typePair); - TypeMap ResolveTypeMap(TypePair typePair) + return defaultExpression; + } + Func IGlobalConfiguration.GetExecutionPlan(in MapRequest mapRequest) + => (Func)GetExecutionPlan(mapRequest); + private Delegate GetExecutionPlan(in MapRequest mapRequest) => _executionPlans.GetOrAdd(mapRequest); + TypeMap IGlobalConfiguration.ResolveAssociatedTypeMap(TypePair types) + { + var typeMap = ResolveTypeMap(types); + if (typeMap != null) { - if (_resolvedMaps.TryGetValue(typePair, out TypeMap typeMap)) - { - return typeMap; - } - if (_sealed) - { - typeMap = _runtimeMaps.GetOrAdd(typePair); - // if it's a dynamically created type map, we need to seal it outside GetTypeMap to handle recursion - if (typeMap != null && typeMap.MapExpression == null) - { - lock (typeMap) - { - typeMap.Seal(this); - } - } - } - else + return typeMap; + } + if (FindMapper(types)?.GetAssociatedTypes(types) is TypePair newTypes) + { + return ResolveTypeMap(newTypes); + } + return null; + } + public static AutoMapperMappingException GetMappingError(Exception innerException, in MapRequest mapRequest) => + new("Error mapping types.", innerException, mapRequest.RuntimeTypes) { MemberMap = mapRequest.MemberMap }; + IReadOnlyCollection IGlobalConfiguration.GetAllTypeMaps() => _configuredMaps.Values; + TypeMap IGlobalConfiguration.FindTypeMapFor(Type sourceType, Type destinationType) => FindTypeMapFor(sourceType, destinationType); + TypeMap IGlobalConfiguration.FindTypeMapFor() => FindTypeMapFor(typeof(TSource), typeof(TDestination)); + TypeMap IGlobalConfiguration.FindTypeMapFor(TypePair typePair) => FindTypeMapFor(typePair); + TypeMap FindTypeMapFor(Type sourceType, Type destinationType) => FindTypeMapFor(new(sourceType, destinationType)); + TypeMap FindTypeMapFor(TypePair typePair) => _configuredMaps.GetValueOrDefault(typePair); + TypeMap IGlobalConfiguration.ResolveTypeMap(Type sourceType, Type destinationType) => ResolveTypeMap(new(sourceType, destinationType)); + TypeMap IGlobalConfiguration.ResolveTypeMap(TypePair typePair) => ResolveTypeMap(typePair); + TypeMap ResolveTypeMap(TypePair typePair) + { + if (_resolvedMaps.TryGetValue(typePair, out TypeMap typeMap)) + { + return typeMap; + } + if (_sealed) + { + typeMap = _runtimeMaps.GetOrAdd(typePair); + // if it's a dynamically created type map, we need to seal it outside GetTypeMap to handle recursion + if (typeMap != null && typeMap.MapExpression == null) { - typeMap = GetTypeMap(typePair); - _resolvedMaps.Add(typePair, typeMap); - if (typeMap != null && typeMap.MapExpression == null) + lock (typeMap) { typeMap.Seal(this); } } - return typeMap; } - private TypeMap GetTypeMap(TypePair initialTypes) + else { - var typeMap = FindClosedGenericTypeMapFor(initialTypes); - if (typeMap != null) + typeMap = GetTypeMap(typePair); + _resolvedMaps.Add(typePair, typeMap); + if (typeMap != null && typeMap.MapExpression == null) { - return typeMap; + typeMap.Seal(this); } - var allSourceTypes = GetTypeInheritance(initialTypes.SourceType); - var allDestinationTypes = GetTypeInheritance(initialTypes.DestinationType); - foreach (var destinationType in allDestinationTypes) + } + return typeMap; + } + private TypeMap GetTypeMap(TypePair initialTypes) + { + var typeMap = FindClosedGenericTypeMapFor(initialTypes); + if (typeMap != null) + { + return typeMap; + } + var allSourceTypes = GetTypeInheritance(initialTypes.SourceType); + var allDestinationTypes = GetTypeInheritance(initialTypes.DestinationType); + foreach (var destinationType in allDestinationTypes) + { + foreach (var sourceType in allSourceTypes) { - foreach (var sourceType in allSourceTypes) + if (sourceType == initialTypes.SourceType && destinationType == initialTypes.DestinationType) { - if (sourceType == initialTypes.SourceType && destinationType == initialTypes.DestinationType) - { - continue; - } - var types = new TypePair(sourceType, destinationType); - if (_resolvedMaps.TryGetValue(types, out typeMap)) - { - return typeMap; - } - typeMap = FindClosedGenericTypeMapFor(types); - if (typeMap != null) - { - return typeMap; - } + continue; } - } - return null; - static List GetTypeInheritance(Type type) - { - var interfaces = type.GetInterfaces(); - var lastIndex = interfaces.Length - 1; - var types = new List(interfaces.Length + 2) { type }; - Type baseType = type; - while ((baseType = baseType.BaseType) != null) + var types = new TypePair(sourceType, destinationType); + if (_resolvedMaps.TryGetValue(types, out typeMap)) { - types.Add(baseType); - foreach (var interfaceType in baseType.GetInterfaces()) - { - var interfaceIndex = Array.LastIndexOf(interfaces, interfaceType); - if (interfaceIndex != lastIndex) - { - interfaces[interfaceIndex] = interfaces[lastIndex]; - interfaces[lastIndex] = interfaceType; - } - } + return typeMap; } - foreach (var interfaceType in interfaces) + typeMap = FindClosedGenericTypeMapFor(types); + if (typeMap != null) { - types.Add(interfaceType); + return typeMap; } - return types; } - TypeMap FindClosedGenericTypeMapFor(TypePair typePair) + } + return null; + static List GetTypeInheritance(Type type) + { + var interfaces = type.GetInterfaces(); + var lastIndex = interfaces.Length - 1; + var types = new List(interfaces.Length + 2) { type }; + Type baseType = type; + while ((baseType = baseType.BaseType) != null) { - if (!_hasOpenMaps || !typePair.IsConstructedGenericType) + types.Add(baseType); + foreach (var interfaceType in baseType.GetInterfaces()) { - return null; - } - return FindClosedGenericMap(typePair); - TypeMap FindClosedGenericMap(TypePair typePair) - { - var genericTypePair = typePair.GetTypeDefinitionIfGeneric(); - var userMap = - FindTypeMapFor(genericTypePair.SourceType, typePair.DestinationType) ?? - FindTypeMapFor(typePair.SourceType, genericTypePair.DestinationType) ?? - FindTypeMapFor(genericTypePair); - TypeMapConfiguration genericMapConfig; - ProfileMap profile; - TypeMap cachedMap; - TypePair closedTypes; - if (userMap != null) - { - genericMapConfig = userMap.Profile.GetGenericMap(userMap.Types); - profile = userMap.Profile; - cachedMap = null; - closedTypes = typePair; - } - else + var interfaceIndex = Array.LastIndexOf(interfaces, interfaceType); + if (interfaceIndex != lastIndex) { - var foundGenericMap = _resolvedMaps.TryGetValue(genericTypePair, out cachedMap) && cachedMap.Types.ContainsGenericParameters; - if (!foundGenericMap) - { - return cachedMap; - } - genericMapConfig = cachedMap.Profile.GetGenericMap(cachedMap.Types); - profile = cachedMap.Profile; - closedTypes = cachedMap.Types.CloseGenericTypes(typePair); + interfaces[interfaceIndex] = interfaces[lastIndex]; + interfaces[lastIndex] = interfaceType; } - if (genericMapConfig == null) - { - return null; - } - var typeMap = profile.CreateClosedGenericTypeMap(genericMapConfig, closedTypes, this); - cachedMap?.CopyInheritedMapsTo(typeMap); - return typeMap; } } - } - IEnumerable IGlobalConfiguration.GetMappers() => _mappers; - TypeMap[] IGlobalConfiguration.GetIncludedTypeMaps(IReadOnlyCollection includedTypes) - { - if (includedTypes.Count == 0) + foreach (var interfaceType in interfaces) { - return Array.Empty(); + types.Add(interfaceType); } - var typeMaps = new TypeMap[includedTypes.Count]; - int index = 0; - foreach (var pair in includedTypes) - { - typeMaps[index] = GetIncludedTypeMap(pair); - index++; - } - return typeMaps; + return types; } - TypeMap IGlobalConfiguration.GetIncludedTypeMap(Type sourceType, Type destinationType) => GetIncludedTypeMap(new(sourceType, destinationType)); - TypeMap IGlobalConfiguration.GetIncludedTypeMap(TypePair pair) => GetIncludedTypeMap(pair); - TypeMap GetIncludedTypeMap(TypePair pair) + TypeMap FindClosedGenericTypeMapFor(TypePair typePair) { - var typeMap = FindTypeMapFor(pair); - if (typeMap != null) + if (!_hasOpenMaps || !typePair.IsConstructedGenericType) { - return typeMap; + return null; } - else + return FindClosedGenericMap(typePair); + TypeMap FindClosedGenericMap(TypePair typePair) { - typeMap = ResolveTypeMap(pair); - // we want the exact map the user included, but we could instantiate an open generic - if (typeMap?.Types != pair) + var genericTypePair = typePair.GetTypeDefinitionIfGeneric(); + var userMap = + FindTypeMapFor(genericTypePair.SourceType, typePair.DestinationType) ?? + FindTypeMapFor(typePair.SourceType, genericTypePair.DestinationType) ?? + FindTypeMapFor(genericTypePair); + TypeMapConfiguration genericMapConfig; + ProfileMap profile; + TypeMap cachedMap; + TypePair closedTypes; + if (userMap != null) + { + genericMapConfig = userMap.Profile.GetGenericMap(userMap.Types); + profile = userMap.Profile; + cachedMap = null; + closedTypes = typePair; + } + else { - throw TypeMap.MissingMapException(pair); + var foundGenericMap = _resolvedMaps.TryGetValue(genericTypePair, out cachedMap) && cachedMap.Types.ContainsGenericParameters; + if (!foundGenericMap) + { + return cachedMap; + } + genericMapConfig = cachedMap.Profile.GetGenericMap(cachedMap.Types); + profile = cachedMap.Profile; + closedTypes = cachedMap.Types.CloseGenericTypes(typePair); } + if (genericMapConfig == null) + { + return null; + } + var typeMap = profile.CreateClosedGenericTypeMap(genericMapConfig, closedTypes, this); + cachedMap?.CopyInheritedMapsTo(typeMap); return typeMap; } } - IObjectMapper IGlobalConfiguration.FindMapper(TypePair types) => FindMapper(types); - IObjectMapper FindMapper(TypePair types) + } + IEnumerable IGlobalConfiguration.GetMappers() => _mappers; + TypeMap[] IGlobalConfiguration.GetIncludedTypeMaps(IReadOnlyCollection includedTypes) + { + if (includedTypes.Count == 0) + { + return Array.Empty(); + } + var typeMaps = new TypeMap[includedTypes.Count]; + int index = 0; + foreach (var pair in includedTypes) + { + typeMaps[index] = GetIncludedTypeMap(pair); + index++; + } + return typeMaps; + } + TypeMap IGlobalConfiguration.GetIncludedTypeMap(Type sourceType, Type destinationType) => GetIncludedTypeMap(new(sourceType, destinationType)); + TypeMap IGlobalConfiguration.GetIncludedTypeMap(TypePair pair) => GetIncludedTypeMap(pair); + TypeMap GetIncludedTypeMap(TypePair pair) + { + var typeMap = FindTypeMapFor(pair); + if (typeMap != null) + { + return typeMap; + } + else { - foreach (var mapper in _mappers) + typeMap = ResolveTypeMap(pair); + // we want the exact map the user included, but we could instantiate an open generic + if (typeMap?.Types != pair) { - if (mapper.IsMatch(types)) - { - return mapper; - } + throw TypeMap.MissingMapException(pair); } - return null; + return typeMap; } - void IGlobalConfiguration.RegisterTypeMap(TypeMap typeMap) => _configuredMaps[typeMap.Types] = typeMap; - void IGlobalConfiguration.AssertConfigurationIsValid(TypeMap typeMap) => _validator.AssertConfigurationIsValid(this, new[] { typeMap }); - void IGlobalConfiguration.AssertConfigurationIsValid(string profileName) + } + IObjectMapper IGlobalConfiguration.FindMapper(TypePair types) => FindMapper(types); + IObjectMapper FindMapper(TypePair types) + { + foreach (var mapper in _mappers) { - if (Profiles.All(x => x.Name != profileName)) + if (mapper.IsMatch(types)) { - throw new ArgumentOutOfRangeException(nameof(profileName), $"Cannot find any profiles with the name '{profileName}'."); + return mapper; } - _validator.AssertConfigurationIsValid(this, _configuredMaps.Values.Where(typeMap => typeMap.Profile.Name == profileName)); } - void IGlobalConfiguration.AssertConfigurationIsValid() => this.Internal().AssertConfigurationIsValid(typeof(TProfile).FullName); - void IGlobalConfiguration.RegisterAsMap(TypeMapConfiguration typeMapConfiguration) => - _resolvedMaps[typeMapConfiguration.Types] = GetIncludedTypeMap(new(typeMapConfiguration.SourceType, typeMapConfiguration.DestinationTypeOverride)); + return null; + } + void IGlobalConfiguration.RegisterTypeMap(TypeMap typeMap) => _configuredMaps[typeMap.Types] = typeMap; + void IGlobalConfiguration.AssertConfigurationIsValid(TypeMap typeMap) => _validator.AssertConfigurationIsValid(this, new[] { typeMap }); + void IGlobalConfiguration.AssertConfigurationIsValid(string profileName) + { + if (Profiles.All(x => x.Name != profileName)) + { + throw new ArgumentOutOfRangeException(nameof(profileName), $"Cannot find any profiles with the name '{profileName}'."); + } + _validator.AssertConfigurationIsValid(this, _configuredMaps.Values.Where(typeMap => typeMap.Profile.Name == profileName)); } + void IGlobalConfiguration.AssertConfigurationIsValid() => this.Internal().AssertConfigurationIsValid(typeof(TProfile).FullName); + void IGlobalConfiguration.RegisterAsMap(TypeMapConfiguration typeMapConfiguration) => + _resolvedMaps[typeMapConfiguration.Types] = GetIncludedTypeMap(new(typeMapConfiguration.SourceType, typeMapConfiguration.DestinationTypeOverride)); } \ No newline at end of file diff --git a/src/AutoMapper/Execution/ExpressionBuilder.cs b/src/AutoMapper/Execution/ExpressionBuilder.cs index 645a8cf0a0..ead369ab4c 100644 --- a/src/AutoMapper/Execution/ExpressionBuilder.cs +++ b/src/AutoMapper/Execution/ExpressionBuilder.cs @@ -41,6 +41,14 @@ public static class ExpressionBuilder private static readonly ParameterExpression Index = Variable(typeof(int), "sourceArrayIndex"); private static readonly BinaryExpression ResetIndex = Assign(Index, Zero); private static readonly UnaryExpression IncrementIndex = PostIncrementAssign(Index); + public static Expression ReplaceParameters(this IGlobalConfiguration configuration, LambdaExpression initialLambda, Expression newParameter) => + configuration.ParameterReplaceVisitor().Replace(initialLambda, newParameter); + public static Expression ReplaceParameters(this IGlobalConfiguration configuration, LambdaExpression initialLambda, Expression[] newParameters) => + configuration.ParameterReplaceVisitor().Replace(initialLambda, newParameters); + public static Expression ConvertReplaceParameters(this IGlobalConfiguration configuration, LambdaExpression initialLambda, Expression newParameter) => + configuration.ConvertParameterReplaceVisitor().Replace(initialLambda, newParameter); + public static Expression ConvertReplaceParameters(this IGlobalConfiguration configuration, LambdaExpression initialLambda, Expression[] newParameters) => + configuration.ConvertParameterReplaceVisitor().Replace(initialLambda, newParameters); public static DefaultExpression Default(this IGlobalConfiguration configuration, Type type) => configuration == null ? Expression.Default(type) : configuration.GetDefault(type); public static (List Variables, List Expressions) Scratchpad(this IGlobalConfiguration configuration) @@ -186,7 +194,7 @@ public static Expression CheckContext(TypeMap typeMap) public static Expression OverMaxDepth(TypeMap typeMap) => typeMap?.MaxDepth > 0 ? Expression.Call(ContextParameter, OverTypeDepthMethod, Constant(typeMap)) : null; public static Expression NullSubstitute(this MemberMap memberMap, Expression sourceExpression) => Coalesce(sourceExpression, ToType(Constant(memberMap.NullSubstitute), sourceExpression.Type)); - public static Expression ApplyTransformers(this MemberMap memberMap, Expression source) + public static Expression ApplyTransformers(this MemberMap memberMap, Expression source, IGlobalConfiguration configuration) { var perMember = memberMap.ValueTransformers; var perMap = memberMap.TypeMap.ValueTransformers; @@ -196,11 +204,11 @@ public static Expression ApplyTransformers(this MemberMap memberMap, Expression return source; } var transformers = perMember.Concat(perMap).Concat(perProfile); - return Apply(transformers, memberMap, source); - static Expression Apply(IEnumerable transformers, MemberMap memberMap, Expression source) => - transformers.Where(vt => vt.IsMatch(memberMap)).Aggregate(source, - (current, vtConfig) => ToType(vtConfig.TransformerExpression.ReplaceParameters(ToType(current, vtConfig.ValueType)), memberMap.DestinationType)); + return memberMap.ApplyTransformers(source, configuration, transformers); } + static Expression ApplyTransformers(this MemberMap memberMap, Expression source, IGlobalConfiguration configuration, IEnumerable transformers) => + transformers.Where(vt => vt.IsMatch(memberMap)).Aggregate(source, (current, vtConfig) => + ToType(configuration.ReplaceParameters(vtConfig.TransformerExpression, ToType(current, vtConfig.ValueType)), memberMap.DestinationType)); public static LambdaExpression Lambda(this MemberInfo member) => new[] { member }.Lambda(); public static LambdaExpression Lambda(this MemberInfo[] members) { @@ -353,12 +361,6 @@ public static MethodCallExpression Call(Expression target, string name, Expressi public static Expression ToType(Expression expression, Type type) => expression.Type == type ? expression : Convert(expression, type); public static Expression ReplaceParameters(this LambdaExpression initialLambda, Expression newParameter) => new ParameterReplaceVisitor().Replace(initialLambda, newParameter); - public static Expression ReplaceParameters(this LambdaExpression initialLambda, Expression[] newParameters) => - new ParameterReplaceVisitor().Replace(initialLambda, newParameters); - public static Expression ConvertReplaceParameters(this LambdaExpression initialLambda, Expression newParameter) => - new ConvertParameterReplaceVisitor().Replace(initialLambda, newParameter); - public static Expression ConvertReplaceParameters(this LambdaExpression initialLambda, Expression[] newParameters) => - new ConvertParameterReplaceVisitor().Replace(initialLambda, newParameters); private static Expression Replace(this ParameterReplaceVisitor visitor, LambdaExpression initialLambda, Expression newParameter) => visitor.Replace(initialLambda.Body, initialLambda.Parameters[0], newParameter); private static Expression Replace(this ParameterReplaceVisitor visitor, LambdaExpression initialLambda, Expression[] newParameters) @@ -432,29 +434,30 @@ static MethodCallExpression ExtensionMethod(MethodInfo method, Expression newTar public static Expression IfNullElse(this Expression expression, Expression then, Expression @else) => expression.Type.IsValueType ? (expression.Type.IsNullableType() ? Condition(Property(expression, "HasValue"), ToType(@else, then.Type), then) : @else) : Condition(ReferenceEqual(expression, Null), then, ToType(@else, then.Type)); - class ReplaceVisitorBase : ExpressionVisitor - { - protected Expression _oldNode; - protected Expression _newNode; - public virtual Expression Replace(Expression target, Expression oldNode, Expression newNode) - { - _oldNode = oldNode; - _newNode = newNode; - return base.Visit(target); - } - } - class ReplaceVisitor : ReplaceVisitorBase - { - public override Expression Visit(Expression node) => _oldNode == node ? _newNode : base.Visit(node); - } - class ParameterReplaceVisitor : ReplaceVisitorBase - { - protected override Expression VisitParameter(ParameterExpression node) => _oldNode == node ? _newNode : base.VisitParameter(node); - } - class ConvertParameterReplaceVisitor : ParameterReplaceVisitor + } + public readonly record struct Member(Expression Expression, MemberInfo MemberInfo, Expression Target); + public class ReplaceVisitorBase : ExpressionVisitor + { + private protected Expression _oldNode; + private protected Expression _newNode; + public virtual Expression Replace(Expression target, Expression oldNode, Expression newNode) { - public override Expression Replace(Expression target, Expression oldNode, Expression newNode) => base.Replace(target, oldNode, ToType(newNode, oldNode.Type)); + _oldNode = oldNode; + _newNode = newNode; + return base.Visit(target); } } - public readonly record struct Member(Expression Expression, MemberInfo MemberInfo, Expression Target); + public class ReplaceVisitor : ReplaceVisitorBase + { + public override Expression Visit(Expression node) => _oldNode == node ? _newNode : base.Visit(node); + } + public class ParameterReplaceVisitor : ReplaceVisitorBase + { + protected override Expression VisitParameter(ParameterExpression node) => _oldNode == node ? _newNode : base.VisitParameter(node); + } + public class ConvertParameterReplaceVisitor : ParameterReplaceVisitor + { + public override Expression Replace(Expression target, Expression oldNode, Expression newNode) => + base.Replace(target, oldNode, ExpressionBuilder.ToType(newNode, oldNode.Type)); + } } \ No newline at end of file diff --git a/src/AutoMapper/Execution/TypeMapPlanBuilder.cs b/src/AutoMapper/Execution/TypeMapPlanBuilder.cs index bf135e2eef..2fc4a9ab32 100644 --- a/src/AutoMapper/Execution/TypeMapPlanBuilder.cs +++ b/src/AutoMapper/Execution/TypeMapPlanBuilder.cs @@ -45,7 +45,7 @@ ParameterExpression[] GetParameters(ParameterExpression first = null, ParameterE public LambdaExpression CreateMapperLambda() { var parameters = GetParameters(second: _initialDestination); - var customExpression = _typeMap.TypeConverter?.GetExpression(parameters); + var customExpression = _typeMap.TypeConverter?.GetExpression(_configuration, parameters); if (customExpression != null) { return Lambda(customExpression, parameters); @@ -87,9 +87,10 @@ static void Clear(ref HashSet typeMapsPath) } void IncludeMembers() { + var configuration = _configuration; _variables.AddRange(_typeMap.IncludedMembersTypeMaps.Select(i => i.Variable)); var source = _source; - _expressions.AddRange(_variables.Zip(_typeMap.IncludedMembersTypeMaps, (v, i) => Assign(v, i.MemberExpression.ReplaceParameters(source).NullCheck(null)))); + _expressions.AddRange(_variables.Zip(_typeMap.IncludedMembersTypeMaps, (v, i) => Assign(v, configuration.ReplaceParameters(i.MemberExpression, source).NullCheck(null)))); } private static void CheckForCycles(IGlobalConfiguration configuration, TypeMap typeMap, HashSet typeMapsPath) { @@ -181,7 +182,7 @@ private Expression CreateAssignmentFunc(Expression createDestination) } foreach (var beforeMapAction in _typeMap.BeforeMapActions) { - actions.Add(beforeMapAction.ReplaceParameters(GetParameters())); + actions.Add(_configuration.ReplaceParameters(beforeMapAction, GetParameters())); } foreach (var propertyMap in _typeMap.OrderedPropertyMaps()) { @@ -204,7 +205,7 @@ private Expression CreateAssignmentFunc(Expression createDestination) } foreach (var afterMapAction in _typeMap.AfterMapActions) { - actions.Add(afterMapAction.ReplaceParameters(GetParameters())); + actions.Add(_configuration.ReplaceParameters(afterMapAction, GetParameters())); } if (hasMaxDepth) { @@ -215,7 +216,7 @@ private Expression CreateAssignmentFunc(Expression createDestination) } private Expression TryPathMap(PathMap pathMap) { - var destination = ((MemberExpression) pathMap.DestinationExpression.ConvertReplaceParameters(_destination)).Expression; + var destination = ((MemberExpression)_configuration.ConvertReplaceParameters(pathMap.DestinationExpression, _destination)).Expression; var configuration = _configuration; var createInnerObjects = CreateInnerObjects(destination); var setFinalValue = CreatePropertyMapFunc(pathMap, destination, pathMap.MemberPath.Last); @@ -262,7 +263,7 @@ private Expression CheckReferencesCache(Expression valueBuilder) } private Expression CreateNewDestinationFunc() => _typeMap switch { - { CustomCtorFunction: LambdaExpression constructUsingFunc } => constructUsingFunc.ReplaceParameters(GetParameters(second: ContextParameter)), + { CustomCtorFunction: LambdaExpression constructUsingFunc } => _configuration.ReplaceParameters(constructUsingFunc, GetParameters(second: ContextParameter)), { ConstructorMap: { CanResolve: true } constructorMap } => ConstructorMapping(constructorMap), { DestinationType: { IsInterface: true } interfaceType } => Throw(Constant(new AutoMapperMappingException("Cannot create interface "+interfaceType, null, _typeMap)), interfaceType), _ => ObjectFactory.GenerateConstructorExpression(DestinationType, _configuration) @@ -327,7 +328,7 @@ private Expression CreatePropertyMapFunc(MemberMap memberMap, Expression destina if (memberMap.Condition != null) { _expressions.Add(IfThen( - memberMap.Condition.ConvertReplaceParameters(new[] { customSource, _destination, mappedMemberVariable, destinationMemberGetter, ContextParameter }), + _configuration.ConvertReplaceParameters(memberMap.Condition, new[] { customSource, _destination, mappedMemberVariable, destinationMemberGetter, ContextParameter }), mapperExpr)); } else if (!destinationMemberReadOnly) @@ -351,7 +352,7 @@ Expression DestinationMemberValue(MemberMap memberMap, Expression destinationMem } void Precondition(MemberMap memberMap, ParameterExpression customSource) { - var preCondition = memberMap.PreCondition.ConvertReplaceParameters(GetParameters(first: customSource)); + var preCondition = _configuration.ConvertReplaceParameters(memberMap.PreCondition, GetParameters(first: customSource)); var ifThen = IfThen(preCondition, Block(_expressions)); _expressions.Clear(); _expressions.Add(ifThen); @@ -382,7 +383,7 @@ Expression MapMember(MemberMap memberMap, Expression destinationMemberValue, Par var mapMember = memberMap.Inline ? _configuration.MapExpression(profile, typePair, resolvedValue, memberMap, destinationMemberValue) : _configuration.NullCheckSource(profile, resolvedValue, destinationMemberValue, ContextMap(typePair, resolvedValue, destinationMemberValue, memberMap), memberMap); - return memberMap.ApplyTransformers(mapMember); + return memberMap.ApplyTransformers(mapMember, _configuration); } private Expression BuildValueResolverFunc(MemberMap memberMap, Expression customSource, Expression destValueExpr) { @@ -435,7 +436,7 @@ public class FuncResolver : LambdaValueResolver, IValueResolver { public FuncResolver(LambdaExpression lambda) : base(lambda) { } public Expression GetExpression(IGlobalConfiguration configuration, MemberMap memberMap, Expression source, Expression destination, Expression destinationMember) => - Lambda.ConvertReplaceParameters(new[] { source, destination, destinationMember, ContextParameter }); + configuration.ConvertReplaceParameters(Lambda, new[] { source, destination, destinationMember, ContextParameter }); public MemberInfo GetSourceMember(MemberMap _) => null; } public class ExpressionResolver : LambdaValueResolver, IValueResolver @@ -443,7 +444,7 @@ public class ExpressionResolver : LambdaValueResolver, IValueResolver public ExpressionResolver(LambdaExpression lambda) : base(lambda) { } public Expression GetExpression(IGlobalConfiguration configuration, MemberMap memberMap, Expression source, Expression _, Expression destinationMember) { - var mapFrom = Lambda.ReplaceParameters(source); + var mapFrom = configuration.ReplaceParameters(Lambda, source); var nullCheckedExpression = mapFrom.NullCheck(configuration, memberMap, destinationMember); if (nullCheckedExpression != mapFrom) { @@ -484,7 +485,7 @@ public Expression GetExpression(IGlobalConfiguration configuration, MemberMap me var sourceMemberType = InterfaceType.GenericTypeArguments[0]; var sourceMember = this switch { - { SourceMemberLambda: { } } => SourceMemberLambda.ReplaceParameters(source), + { SourceMemberLambda: { } } => configuration.ReplaceParameters(SourceMemberLambda, source), { SourceMemberName: { } } => PropertyOrField(source, SourceMemberName), _ when memberMap.SourceMembers.Length > 0 => memberMap.ChainSourceMembers(configuration, source, destinationMember), _ => Throw(Constant(BuildExceptionMessage()), sourceMemberType) @@ -508,7 +509,15 @@ public Expression GetExpression(IGlobalConfiguration configuration, MemberMap me { var typeMap = memberMap.TypeMap; var resolverInstance = _instance ?? ServiceLocator(typeMap.MakeGenericType(ConcreteType)); - var sourceMember = SourceMemberLambda?.ReplaceParameters(source) ?? (SourceMemberName != null ? PropertyOrField(source, SourceMemberName) : null); + Expression sourceMember; + if (SourceMemberLambda == null) + { + sourceMember = SourceMemberName == null ? null : PropertyOrField(source, SourceMemberName); + } + else + { + sourceMember = configuration.ReplaceParameters(SourceMemberLambda, source); + } var iValueResolver = InterfaceType; if (iValueResolver.ContainsGenericParameters) { @@ -527,7 +536,7 @@ public Expression GetExpression(IGlobalConfiguration configuration, MemberMap me } public abstract class TypeConverter { - public abstract Expression GetExpression(ParameterExpression[] parameters); + public abstract Expression GetExpression(IGlobalConfiguration configuration, ParameterExpression[] parameters); public virtual void CloseGenerics(TypeMapConfiguration openMapConfig, TypePair closedTypes) { } public virtual LambdaExpression ProjectToExpression => null; } @@ -535,7 +544,8 @@ public class LambdaTypeConverter : TypeConverter { public LambdaTypeConverter(LambdaExpression lambda) => Lambda = lambda; public LambdaExpression Lambda { get; } - public override Expression GetExpression(ParameterExpression[] parameters) => Lambda.ConvertReplaceParameters(parameters); + public override Expression GetExpression(IGlobalConfiguration configuration, ParameterExpression[] parameters) => + configuration.ConvertReplaceParameters(Lambda, parameters); } public class ExpressionTypeConverter : LambdaTypeConverter { @@ -551,7 +561,7 @@ public ClassTypeConverter(Type converterType, Type converterInterface) } public Type ConverterType { get; private set; } public Type ConverterInterface { get; } - public override Expression GetExpression(ParameterExpression[] parameters) => + public override Expression GetExpression(IGlobalConfiguration configuration, ParameterExpression[] parameters) => Call(ToType(ServiceLocator(ConverterType), ConverterInterface), "Convert", parameters); public override void CloseGenerics(TypeMapConfiguration openMapConfig, TypePair closedTypes) { diff --git a/src/AutoMapper/Internal/InternalApi.cs b/src/AutoMapper/Internal/InternalApi.cs index beaf3a7cf7..37bdb059a3 100644 --- a/src/AutoMapper/Internal/InternalApi.cs +++ b/src/AutoMapper/Internal/InternalApi.cs @@ -5,6 +5,7 @@ using System.Reflection; using AutoMapper.Configuration; using AutoMapper.Configuration.Conventions; +using AutoMapper.Execution; using AutoMapper.Features; using AutoMapper.Internal.Mappers; using AutoMapper.QueryableExtensions.Impl; @@ -162,6 +163,8 @@ public interface IGlobalConfiguration : IConfigurationProvider HashSet TypeMapsPath { get; } CatchBlock[] Catches { get; } DefaultExpression GetDefault(Type type); + ParameterReplaceVisitor ParameterReplaceVisitor(); + ConvertParameterReplaceVisitor ConvertParameterReplaceVisitor(); } [EditorBrowsable(EditorBrowsableState.Never)] public interface IProfileExpressionInternal : IProfileExpression diff --git a/src/AutoMapper/QueryableExtensions/ProjectionBuilder.cs b/src/AutoMapper/QueryableExtensions/ProjectionBuilder.cs index fffd162932..88c013f676 100644 --- a/src/AutoMapper/QueryableExtensions/ProjectionBuilder.cs +++ b/src/AutoMapper/QueryableExtensions/ProjectionBuilder.cs @@ -143,7 +143,7 @@ Expression ProjectMemberCore() var projectionMapper = GetProjectionMapper(); mappedExpression = projectionMapper.Project(_configuration, memberRequest, resolvedSource, letPropertyMaps); } - return mappedExpression == null ? null : memberMap.ApplyTransformers(mappedExpression); + return mappedExpression == null ? null : memberMap.ApplyTransformers(mappedExpression, _configuration); Expression ResolveSource() { var customSource = memberMap.IncludedMember?.ProjectToCustomSource; From 66f0020f4c60d95de0c1797d3ad1443adbdef03b Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Sat, 3 Sep 2022 16:13:00 +0300 Subject: [PATCH 47/67] cosmetic --- .../MapperConfigurationExpression.cs | 17 +++-------------- src/AutoMapper/Configuration/Profile.cs | 6 +++--- src/AutoMapper/Execution/TypeMapPlanBuilder.cs | 5 +++-- 3 files changed, 9 insertions(+), 19 deletions(-) diff --git a/src/AutoMapper/Configuration/MapperConfigurationExpression.cs b/src/AutoMapper/Configuration/MapperConfigurationExpression.cs index 71eb03c9eb..5cef3483f6 100644 --- a/src/AutoMapper/Configuration/MapperConfigurationExpression.cs +++ b/src/AutoMapper/Configuration/MapperConfigurationExpression.cs @@ -133,23 +133,12 @@ void IGlobalConfigurationExpression.Validator(Validator validator) => Func IGlobalConfigurationExpression.ServiceCtor => _serviceCtor; public void CreateProfile(string profileName, Action config) - => AddProfile(new NamedProfile(profileName, config)); + => AddProfile(new Profile(profileName, config)); List IGlobalConfigurationExpression.Mappers => _mappers; Features IGlobalConfigurationExpression.Features { get; } = new Features(); - private class NamedProfile : Profile - { - public NamedProfile(string profileName) : base(profileName) - { - } - - public NamedProfile(string profileName, Action config) : base(profileName, config) - { - } - } - public void AddProfile(Profile profile) => _profiles.Add(profile); public void AddProfile() where TProfile : Profile, new() => AddProfile(new TProfile()); @@ -184,8 +173,8 @@ public void AddMaps(params Type[] typesFromAssembliesContainingMappingDefinition private void AddMapsCore(IEnumerable assembliesToScan) { - var allTypes = assembliesToScan.Where(a => !a.IsDynamic && a != typeof(NamedProfile).Assembly).SelectMany(a => a.DefinedTypes).ToArray(); - var autoMapAttributeProfile = new NamedProfile(nameof(AutoMapAttribute)); + var allTypes = assembliesToScan.Where(a => !a.IsDynamic && a != typeof(Profile).Assembly).SelectMany(a => a.DefinedTypes).ToArray(); + var autoMapAttributeProfile = new Profile(nameof(AutoMapAttribute)); foreach (var type in allTypes) { diff --git a/src/AutoMapper/Configuration/Profile.cs b/src/AutoMapper/Configuration/Profile.cs index 08c517f94e..83bfb8aaa3 100644 --- a/src/AutoMapper/Configuration/Profile.cs +++ b/src/AutoMapper/Configuration/Profile.cs @@ -60,7 +60,7 @@ public interface IProfileConfiguration /// /// Provides a named configuration for maps. Naming conventions become scoped per profile. /// - public abstract class Profile : IProfileExpressionInternal, IProfileConfiguration + public class Profile : IProfileExpressionInternal, IProfileConfiguration { private readonly List _prefixes = new() { "Get" }; private readonly List _postfixes = new(); @@ -75,13 +75,13 @@ public abstract class Profile : IProfileExpressionInternal, IProfileConfiguratio private List _sourceExtensionMethods; private List _valueTransformerConfigs; private bool? _constructorMappingEnabled; - protected Profile(string profileName) : this() => ProfileName = profileName; + protected internal Profile(string profileName) : this() => ProfileName = profileName; protected Profile() { ProfileName = GetType().FullName; _memberConfiguration = new(){ NameToMemberMappers = { _prePostfixName } }; } - protected Profile(string profileName, Action configurationAction) : this(profileName) => configurationAction(this); + protected internal Profile(string profileName, Action configurationAction) : this(profileName) => configurationAction(this); MemberConfiguration IProfileExpressionInternal.MemberConfiguration => _memberConfiguration; bool? IProfileConfiguration.ConstructorMappingEnabled => _constructorMappingEnabled; bool? IProfileExpressionInternal.MethodMappingEnabled { get; set; } diff --git a/src/AutoMapper/Execution/TypeMapPlanBuilder.cs b/src/AutoMapper/Execution/TypeMapPlanBuilder.cs index 2fc4a9ab32..9705804ff2 100644 --- a/src/AutoMapper/Execution/TypeMapPlanBuilder.cs +++ b/src/AutoMapper/Execution/TypeMapPlanBuilder.cs @@ -170,6 +170,7 @@ private Expression CreateDestinationFunc() Block(destinationFunc, Call(ContextParameter, CacheDestinationMethod, _source, Constant(DestinationType), _destination), _destination) : destinationFunc; } + Expression ReplaceParameters(LambdaExpression lambda) => _configuration.ReplaceParameters(lambda, GetParameters()); private Expression CreateAssignmentFunc(Expression createDestination) { List actions = new() { createDestination }; @@ -182,7 +183,7 @@ private Expression CreateAssignmentFunc(Expression createDestination) } foreach (var beforeMapAction in _typeMap.BeforeMapActions) { - actions.Add(_configuration.ReplaceParameters(beforeMapAction, GetParameters())); + actions.Add(ReplaceParameters(beforeMapAction)); } foreach (var propertyMap in _typeMap.OrderedPropertyMaps()) { @@ -205,7 +206,7 @@ private Expression CreateAssignmentFunc(Expression createDestination) } foreach (var afterMapAction in _typeMap.AfterMapActions) { - actions.Add(_configuration.ReplaceParameters(afterMapAction, GetParameters())); + actions.Add(ReplaceParameters(afterMapAction)); } if (hasMaxDepth) { From f1655e1e326bf4c1510806dee5cf613ecc29fdb4 Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Sat, 3 Sep 2022 19:08:54 +0300 Subject: [PATCH 48/67] file scoped namespaces --- .editorconfig | 32 +- src/AutoMapper/AssemblyInfo.cs | 7 +- src/AutoMapper/AutoMapperMappingException.cs | 337 +- .../Annotations/AutoMapAttribute.cs | 171 +- .../Annotations/IgnoreAttribute.cs | 25 +- .../Annotations/MapAtRuntimeAttribute.cs | 27 +- .../Annotations/MappingOrderAttribute.cs | 37 +- .../Annotations/NullSubstituteAttribute.cs | 39 +- .../Annotations/SourceMemberAttribute.cs | 37 +- .../Annotations/UseExistingValueAttribute.cs | 25 +- .../Annotations/ValueConverterAttribute.cs | 51 +- .../Annotations/ValueResolverAttribute.cs | 51 +- .../Configuration/ConfigurationValidator.cs | 197 +- src/AutoMapper/Configuration/Conventions.cs | 295 +- .../CtorParamConfigurationExpression.cs | 131 +- .../Configuration/IMappingExpression.cs | 261 +- .../Configuration/IMappingExpressionBase.cs | 451 ++- .../Configuration/IMappingOperationOptions.cs | 111 +- .../IMemberConfigurationExpression.cs | 677 ++-- .../IMemberConfigurationProvider.cs | 9 +- .../Configuration/INamingConvention.cs | 79 +- .../Configuration/IProfileExpression.cs | 329 +- .../MapperConfigurationExpression.cs | 321 +- .../Configuration/MappingExpression.cs | 355 +- .../MemberConfigurationExpression.cs | 313 +- .../PathConfigurationExpression.cs | 141 +- src/AutoMapper/Configuration/Profile.cs | 329 +- .../Configuration/SourceMappingExpression.cs | 75 +- .../Configuration/TypeMapConfiguration.cs | 647 ++-- src/AutoMapper/ConstructorMap.cs | 153 +- src/AutoMapper/Execution/ExpressionBuilder.cs | 759 ++-- src/AutoMapper/Execution/ObjectFactory.cs | 89 +- src/AutoMapper/Execution/ProxyGenerator.cs | 309 +- .../Execution/TypeMapPlanBuilder.cs | 937 +++-- src/AutoMapper/Features.cs | 149 +- src/AutoMapper/Internal/InternalApi.cs | 371 +- .../Internal/LockingConcurrentDictionary.cs | 33 +- src/AutoMapper/Internal/MemberPath.cs | 57 +- src/AutoMapper/Internal/PrimitiveHelper.cs | 47 +- src/AutoMapper/Internal/ReflectionHelper.cs | 185 +- src/AutoMapper/Internal/TypeDetails.cs | 325 +- src/AutoMapper/Internal/TypeExtensions.cs | 141 +- src/AutoMapper/Internal/TypePair.cs | 55 +- src/AutoMapper/Mapper.cs | 385 +- src/AutoMapper/Mappers/AssignableMapper.cs | 13 +- src/AutoMapper/Mappers/CollectionMapper.cs | 443 ++- src/AutoMapper/Mappers/ConstructorMapper.cs | 21 +- .../Mappers/ConversionOperatorMapper.cs | 35 +- src/AutoMapper/Mappers/ConvertMapper.cs | 23 +- src/AutoMapper/Mappers/EnumToEnumMapper.cs | 37 +- src/AutoMapper/Mappers/FromDynamicMapper.cs | 63 +- .../Mappers/FromStringDictionaryMapper.cs | 129 +- src/AutoMapper/Mappers/IObjectMapper.cs | 119 +- src/AutoMapper/Mappers/KeyValueMapper.cs | 31 +- src/AutoMapper/Mappers/MapperRegistry.cs | 47 +- .../Mappers/NullableDestinationMapper.cs | 17 +- .../Mappers/NullableSourceMapper.cs | 19 +- src/AutoMapper/Mappers/ParseStringMapper.cs | 15 +- src/AutoMapper/Mappers/StringToEnumMapper.cs | 63 +- src/AutoMapper/Mappers/ToDynamicMapper.cs | 69 +- .../Mappers/ToStringDictionaryMapper.cs | 21 +- src/AutoMapper/Mappers/ToStringMapper.cs | 19 +- .../Mappers/UnderlyingEnumTypeMapper.cs | 13 +- src/AutoMapper/MemberMap.cs | 161 +- src/AutoMapper/PathMap.cs | 55 +- src/AutoMapper/ProfileMap.cs | 469 ++- src/AutoMapper/PropertyMap.cs | 155 +- .../QueryableExtensions/Extensions.cs | 163 +- .../NullsafeQueryRewriter.cs | 201 +- .../QueryableExtensions/ProjectionBuilder.cs | 695 ++-- .../AssignableProjectionMapper.cs | 15 +- .../ProjectionMappers/EnumProjectionMapper.cs | 17 +- .../EnumerableProjectionMapper.cs | 77 +- .../NullableSourceProjectionMapper.cs | 17 +- .../StringProjectionMapper.cs | 15 +- src/AutoMapper/ResolutionContext.cs | 177 +- src/AutoMapper/TypeMap.cs | 805 ++-- src/Benchmark/BenchEngine.cs | 43 +- src/Benchmark/FlatteningMapper.cs | 890 +++-- src/Benchmark/HiPerfTimer.cs | 79 +- src/Benchmark/IObjectToObjectMapper.cs | 13 +- src/Benchmark/Program.cs | 33 +- src/UnitTests/AddProfiles.cs | 29 +- src/UnitTests/ArraysAndLists.cs | 1453 ++++---- src/UnitTests/AssertionExtensions.cs | 47 +- src/UnitTests/AutoMapperTester.cs | 65 +- src/UnitTests/BasicFlattening.cs | 383 +- src/UnitTests/BeforeAfterMapping.cs | 455 ++- src/UnitTests/BidirectionalRelationships.cs | 783 ++-- .../BidirectionalRelationshipsWithoutPR.cs | 1209 +++--- src/UnitTests/Bug/AfterMapNestedObjects.cs | 81 +- .../AllowNullCollectionsAssignableArray.cs | 57 +- .../Bug/AllowNullDestinationValuesBugs.cs | 111 +- .../AssertConfigurationIsValidNullables.cs | 33 +- .../Bug/AutoMapperInheritanceProblemDemo.cs | 169 +- ...aseMapWithIncludesAndUnincludedMappings.cs | 179 +- .../Bug/CannotConvertEnumToNullable.cs | 47 +- ...MapICollectionToAggregateSumDestination.cs | 73 +- ...ojectIEnumerableToAggregateDestinations.cs | 57 +- .../Bug/CannotProjectStringToNullableEnum.cs | 53 +- src/UnitTests/Bug/CaseSensitivityBug.cs | 35 +- .../Bug/CollectionBaseClassGetConvention.cs | 59 +- .../CollectionMapperMapsISetIncorrectly.cs | 63 +- src/UnitTests/Bug/CollectionWhere.cs | 73 +- src/UnitTests/Bug/CollectionsNullability.cs | 53 +- .../Bug/ConstructUsingReturnsNull.cs | 39 +- .../Bug/ConstructorParameterNamedType.cs | 35 +- src/UnitTests/Bug/ConvertMapperThreading.cs | 59 +- ...eateMapExpressionWithIgnoredPropertyBug.cs | 37 +- src/UnitTests/Bug/CustomConverters.cs | 207 +- src/UnitTests/Bug/CustomIEnumerableBug.cs | 79 +- src/UnitTests/Bug/DeepCloningBug.cs | 81 +- src/UnitTests/Bug/DeepInheritanceIssue.cs | 113 +- .../DestinationValueInitializedByCtorBug.cs | 89 +- .../Bug/DuplicateExtensionMethods.cs | 65 +- .../Bug/DuplicateValuesBugWithoutPR.cs | 95 +- src/UnitTests/Bug/EFCollections.cs | 79 +- src/UnitTests/Bug/EmptyNullSubstituteBug.cs | 89 +- src/UnitTests/Bug/EnumCaseSensitivityBug.cs | 69 +- src/UnitTests/Bug/EnumMatchingOnValue.cs | 76 +- src/UnitTests/Bug/ExistingArrays.cs | 83 +- ...orAllMembersAndDoNotUseDestinationValue.cs | 55 +- .../GenericCreateMapWithCircularReferences.cs | 117 +- src/UnitTests/Bug/GenericTypeConverter.cs | 247 +- src/UnitTests/Bug/GuidTryExpression.cs | 57 +- src/UnitTests/Bug/IgnoreAll.cs | 112 +- src/UnitTests/Bug/IncludeBaseInheritance.cs | 109 +- src/UnitTests/Bug/IncludeInheritance.cs | 109 +- src/UnitTests/Bug/InitializeNRE.cs | 89 +- src/UnitTests/Bug/IntToNullableDecimal.cs | 55 +- src/UnitTests/Bug/InterfaceSelfMappingBug.cs | 69 +- src/UnitTests/Bug/InternalProperties.cs | 53 +- src/UnitTests/Bug/JsonNet.cs | 259 +- src/UnitTests/Bug/LazyCollectionMapping.cs | 95 +- src/UnitTests/Bug/ListSourceMapperBug.cs | 63 +- src/UnitTests/Bug/MapAtRuntime/BaseEntity.cs | 9 +- .../Bug/MapAtRuntime/BaseEntityDTO.cs | 9 +- src/UnitTests/Bug/MapAtRuntime/Entity1.cs | 39 +- src/UnitTests/Bug/MapAtRuntime/Entity10.cs | 13 +- src/UnitTests/Bug/MapAtRuntime/Entity11.cs | 17 +- src/UnitTests/Bug/MapAtRuntime/Entity12.cs | 21 +- src/UnitTests/Bug/MapAtRuntime/Entity13.cs | 15 +- src/UnitTests/Bug/MapAtRuntime/Entity14.cs | 19 +- src/UnitTests/Bug/MapAtRuntime/Entity15.cs | 11 +- src/UnitTests/Bug/MapAtRuntime/Entity16.cs | 15 +- src/UnitTests/Bug/MapAtRuntime/Entity17.cs | 27 +- src/UnitTests/Bug/MapAtRuntime/Entity18.cs | 15 +- src/UnitTests/Bug/MapAtRuntime/Entity19.cs | 11 +- src/UnitTests/Bug/MapAtRuntime/Entity2.cs | 11 +- src/UnitTests/Bug/MapAtRuntime/Entity20.cs | 43 +- src/UnitTests/Bug/MapAtRuntime/Entity21.cs | 11 +- src/UnitTests/Bug/MapAtRuntime/Entity22.cs | 17 +- src/UnitTests/Bug/MapAtRuntime/Entity23.cs | 11 +- src/UnitTests/Bug/MapAtRuntime/Entity24.cs | 15 +- src/UnitTests/Bug/MapAtRuntime/Entity25.cs | 23 +- src/UnitTests/Bug/MapAtRuntime/Entity26.cs | 15 +- src/UnitTests/Bug/MapAtRuntime/Entity3.cs | 17 +- src/UnitTests/Bug/MapAtRuntime/Entity4.cs | 11 +- src/UnitTests/Bug/MapAtRuntime/Entity5.cs | 35 +- src/UnitTests/Bug/MapAtRuntime/Entity6.cs | 23 +- src/UnitTests/Bug/MapAtRuntime/Entity7.cs | 15 +- src/UnitTests/Bug/MapAtRuntime/Entity8.cs | 31 +- src/UnitTests/Bug/MapAtRuntime/Entity9.cs | 11 +- src/UnitTests/Bug/MapAtRuntime/EntityDTO1.cs | 39 +- src/UnitTests/Bug/MapAtRuntime/EntityDTO10.cs | 13 +- src/UnitTests/Bug/MapAtRuntime/EntityDTO11.cs | 17 +- src/UnitTests/Bug/MapAtRuntime/EntityDTO12.cs | 21 +- src/UnitTests/Bug/MapAtRuntime/EntityDTO13.cs | 15 +- src/UnitTests/Bug/MapAtRuntime/EntityDTO14.cs | 21 +- src/UnitTests/Bug/MapAtRuntime/EntityDTO15.cs | 13 +- src/UnitTests/Bug/MapAtRuntime/EntityDTO16.cs | 15 +- src/UnitTests/Bug/MapAtRuntime/EntityDTO17.cs | 27 +- src/UnitTests/Bug/MapAtRuntime/EntityDTO18.cs | 15 +- src/UnitTests/Bug/MapAtRuntime/EntityDTO19.cs | 11 +- src/UnitTests/Bug/MapAtRuntime/EntityDTO2.cs | 11 +- src/UnitTests/Bug/MapAtRuntime/EntityDTO20.cs | 45 +- src/UnitTests/Bug/MapAtRuntime/EntityDTO21.cs | 11 +- src/UnitTests/Bug/MapAtRuntime/EntityDTO22.cs | 17 +- src/UnitTests/Bug/MapAtRuntime/EntityDTO23.cs | 11 +- src/UnitTests/Bug/MapAtRuntime/EntityDTO24.cs | 15 +- src/UnitTests/Bug/MapAtRuntime/EntityDTO25.cs | 23 +- src/UnitTests/Bug/MapAtRuntime/EntityDTO26.cs | 15 +- src/UnitTests/Bug/MapAtRuntime/EntityDTO3.cs | 17 +- src/UnitTests/Bug/MapAtRuntime/EntityDTO4.cs | 11 +- src/UnitTests/Bug/MapAtRuntime/EntityDTO5.cs | 35 +- src/UnitTests/Bug/MapAtRuntime/EntityDTO6.cs | 23 +- src/UnitTests/Bug/MapAtRuntime/EntityDTO7.cs | 15 +- src/UnitTests/Bug/MapAtRuntime/EntityDTO8.cs | 31 +- src/UnitTests/Bug/MapAtRuntime/EntityDTO9.cs | 11 +- .../Bug/MapAtRuntime/MapAtRuntime.cs | 205 +- .../MapAtRuntimeWithCollections/BaseEntity.cs | 9 +- .../BaseEntityDTO.cs | 9 +- .../MapAtRuntimeWithCollections/Entity1.cs | 41 +- .../MapAtRuntimeWithCollections/Entity10.cs | 13 +- .../MapAtRuntimeWithCollections/Entity11.cs | 19 +- .../MapAtRuntimeWithCollections/Entity12.cs | 21 +- .../MapAtRuntimeWithCollections/Entity13.cs | 15 +- .../MapAtRuntimeWithCollections/Entity14.cs | 19 +- .../MapAtRuntimeWithCollections/Entity15.cs | 11 +- .../MapAtRuntimeWithCollections/Entity16.cs | 15 +- .../MapAtRuntimeWithCollections/Entity17.cs | 27 +- .../MapAtRuntimeWithCollections/Entity18.cs | 15 +- .../MapAtRuntimeWithCollections/Entity19.cs | 11 +- .../MapAtRuntimeWithCollections/Entity2.cs | 11 +- .../MapAtRuntimeWithCollections/Entity20.cs | 47 +- .../MapAtRuntimeWithCollections/Entity21.cs | 11 +- .../MapAtRuntimeWithCollections/Entity22.cs | 17 +- .../MapAtRuntimeWithCollections/Entity23.cs | 11 +- .../MapAtRuntimeWithCollections/Entity24.cs | 15 +- .../MapAtRuntimeWithCollections/Entity25.cs | 23 +- .../MapAtRuntimeWithCollections/Entity26.cs | 15 +- .../MapAtRuntimeWithCollections/Entity3.cs | 17 +- .../MapAtRuntimeWithCollections/Entity4.cs | 11 +- .../MapAtRuntimeWithCollections/Entity5.cs | 35 +- .../MapAtRuntimeWithCollections/Entity6.cs | 23 +- .../MapAtRuntimeWithCollections/Entity7.cs | 15 +- .../MapAtRuntimeWithCollections/Entity8.cs | 37 +- .../MapAtRuntimeWithCollections/Entity9.cs | 11 +- .../MapAtRuntimeWithCollections/EntityDTO1.cs | 39 +- .../EntityDTO10.cs | 13 +- .../EntityDTO11.cs | 17 +- .../EntityDTO12.cs | 21 +- .../EntityDTO13.cs | 15 +- .../EntityDTO14.cs | 21 +- .../EntityDTO15.cs | 13 +- .../EntityDTO16.cs | 15 +- .../EntityDTO17.cs | 27 +- .../EntityDTO18.cs | 15 +- .../EntityDTO19.cs | 11 +- .../MapAtRuntimeWithCollections/EntityDTO2.cs | 11 +- .../EntityDTO20.cs | 43 +- .../EntityDTO21.cs | 11 +- .../EntityDTO22.cs | 17 +- .../EntityDTO23.cs | 11 +- .../EntityDTO24.cs | 15 +- .../EntityDTO25.cs | 23 +- .../EntityDTO26.cs | 15 +- .../MapAtRuntimeWithCollections/EntityDTO3.cs | 17 +- .../MapAtRuntimeWithCollections/EntityDTO4.cs | 11 +- .../MapAtRuntimeWithCollections/EntityDTO5.cs | 35 +- .../MapAtRuntimeWithCollections/EntityDTO6.cs | 23 +- .../MapAtRuntimeWithCollections/EntityDTO7.cs | 15 +- .../MapAtRuntimeWithCollections/EntityDTO8.cs | 33 +- .../MapAtRuntimeWithCollections/EntityDTO9.cs | 11 +- .../MapAtRuntimeWithCollections.cs | 233 +- src/UnitTests/Bug/MapExpandoObjectProperty.cs | 41 +- src/UnitTests/Bug/MapFromClosureBug.cs | 103 +- src/UnitTests/Bug/MapOverloadsWithDynamic.cs | 91 +- src/UnitTests/Bug/MappingInheritance.cs | 159 +- .../Bug/MappingToAReadOnlyCollection.cs | 91 +- .../Bug/MemberListSourceAndForPath.cs | 83 +- src/UnitTests/Bug/MemberNamedTypeBug.cs | 85 +- src/UnitTests/Bug/MissingMapping.cs | 45 +- src/UnitTests/Bug/MultiThreadingIssues.cs | 2163 ++++++----- src/UnitTests/Bug/MultidimensionalArrays.cs | 111 +- .../Bug/MultipleInterfaceInheritance.cs | 95 +- .../Bug/MultipleTypeConverterInterfaces.cs | 101 +- src/UnitTests/Bug/NamingConventions.cs | 167 +- ...stedMappingProjectionsExplicitExpanding.cs | 107 +- src/UnitTests/Bug/NonExistingProperty.cs | 25 +- src/UnitTests/Bug/NullArrayBug.cs | 87 +- .../Bug/NullConstructorParameterName.cs | 57 +- src/UnitTests/Bug/NullSubstituteInnerClass.cs | 77 +- src/UnitTests/Bug/NullSubstituteType.cs | 49 +- src/UnitTests/Bug/NullToString.cs | 55 +- src/UnitTests/Bug/NullableBytesAndEnums.cs | 187 +- src/UnitTests/Bug/NullableDateTime.cs | 179 +- .../Bug/NullableEnumToNullableValueType.cs | 69 +- src/UnitTests/Bug/NullableEnums.cs | 33 +- .../Bug/NullableIntToNullableDecimal.cs | 107 +- .../Bug/NullableIntToNullableEnum.cs | 71 +- src/UnitTests/Bug/NullablePropertiesBug.cs | 23 +- src/UnitTests/Bug/NullableResolveUsing.cs | 49 +- src/UnitTests/Bug/NullableToInvalid.cs | 43 +- src/UnitTests/Bug/NullableUntypedMapFrom.cs | 49 +- src/UnitTests/Bug/ObjectEnumToObjectEnum.cs | 83 +- src/UnitTests/Bug/ObjectTypeMapFailure.cs | 49 +- ...ltipleDestinationsAndPreserveReferences.cs | 65 +- ...SourceWithMultipleDestinationsWithoutPR.cs | 61 +- .../Bug/PreserveReferencesSameDestination.cs | 127 +- .../Bug/ProjectConstructorParameters.cs | 75 +- .../Bug/ProjectUsingTheQueriedEntity.cs | 49 +- src/UnitTests/Bug/PropertyNamedType.cs | 33 +- .../Bug/ReadOnlyCollectionMappingBug.cs | 31 +- src/UnitTests/Bug/ReadOnlyFieldMappingBug.cs | 49 +- .../Bug/RecognizeDestinationPostfixes.cs | 49 +- src/UnitTests/Bug/RemovePrefixes.cs | 39 +- .../Bug/RepeatedMappingConfigurationTest.cs | 59 +- src/UnitTests/Bug/ReportMissingInclude.cs | 105 +- .../Bug/ReverseMapReplaceMemberName.cs | 147 +- .../Bug/SelectiveConfigurationValidation.cs | 73 +- .../Bug/SequenceContainsNoElementsTest.cs | 59 +- src/UnitTests/Bug/StructMapping.cs | 83 +- src/UnitTests/Bug/SubclassMappings.cs | 53 +- src/UnitTests/Bug/TargetISet.cs | 71 +- src/UnitTests/Bug/TypeMapIncludeBaseTypes.cs | 107 +- src/UnitTests/Bug/UseDestinationValue.cs | 287 +- ...ithoutPreserveReferencesSameDestination.cs | 127 +- src/UnitTests/CollectionMapping.cs | 1755 +++++---- src/UnitTests/ConditionalMapping.cs | 465 ++- src/UnitTests/ConfigCompilation.cs | 43 +- src/UnitTests/ConfigurationFeatureTest.cs | 201 +- src/UnitTests/ConfigurationRules.cs | 131 +- src/UnitTests/ConfigurationValidation.cs | 1223 +++--- src/UnitTests/Constructors.cs | 2593 +++++++------ src/UnitTests/CustomCollectionTester.cs | 31 +- src/UnitTests/CustomMapping.cs | 2475 +++++++------ src/UnitTests/CustomValidations.cs | 301 +- src/UnitTests/EnumToNullableEnum.cs | 51 +- src/UnitTests/Enumerations.cs | 1063 +++--- src/UnitTests/ExtensionMethods.cs | 479 ++- src/UnitTests/FillingExistingDestination.cs | 385 +- src/UnitTests/ForAllMaps.cs | 157 +- src/UnitTests/ForAllMembers.cs | 129 +- src/UnitTests/ForPath.cs | 661 ++-- .../IMappingExpression/ForCtorParam.cs | 265 +- .../IMappingExpression/IncludeMembers.cs | 3265 ++++++++--------- .../NonGenericConstructorTests.cs | 85 +- .../NonGenericProjectEnumTest.cs | 183 +- .../NonGenericResolveUsing.cs | 47 +- ...PropertiesWithAnInaccessibleSetterTests.cs | 65 +- src/UnitTests/IgnoreAllTests.cs | 357 +- src/UnitTests/InterfaceMapping.cs | 1171 +++--- .../Internal/CreateProxyThreading.cs | 49 +- src/UnitTests/Internal/GenerateSimilarType.cs | 103 +- src/UnitTests/Internal/MapperTests.cs | 33 +- src/UnitTests/Internal/ObjectFactoryTests.cs | 25 +- .../Internal/PrimitiveExtensionsTester.cs | 65 +- src/UnitTests/Internal/TypeMapFactorySpecs.cs | 277 +- src/UnitTests/MapToAttributeTest.cs | 129 +- .../Mappers/ConstructorMapperTests.cs | 21 +- src/UnitTests/Mappers/ConversionOperators.cs | 271 +- src/UnitTests/Mappers/ConvertMapperTests.cs | 123 +- src/UnitTests/Mappers/CustomMapperTests.cs | 309 +- src/UnitTests/Mappers/DynamicMapperTests.cs | 351 +- .../Mappers/NameValueCollectionMapperTests.cs | 63 +- .../Mappers/ReadOnlyDictionaryMapperTests.cs | 117 +- .../Mappers/StringDictionaryMapperTests.cs | 509 ++- src/UnitTests/Mappers/TypeHelperTests.cs | 31 +- src/UnitTests/MappingExceptions.cs | 141 +- ...MappingExpressionFeatureWithReverseTest.cs | 417 ++- ...pingExpressionFeatureWithoutReverseTest.cs | 511 ++- .../ApplyIncludeBaseRecursively.cs | 233 +- ...ntionMappedCollectionShouldMapBaseTypes.cs | 133 +- .../IgnoreShouldBeInherited.cs | 173 +- ...eShouldBeInheritedIfConventionCannotMap.cs | 69 +- .../MappingInheritance/IncludeAllDerived.cs | 65 +- .../MappingInheritance/IncludeBaseBug.cs | 327 +- .../IncludeBaseShouldNotCreateMaps.cs | 49 +- .../IncludeBaseShouldValidateTypes.cs | 23 +- .../IncludeBaseWithNonGenericUsage.cs | 107 +- ...dedBaseMappingShouldInheritBaseMappings.cs | 621 ++-- ...ncludedMappingShouldInheritBaseMappings.cs | 623 ++-- .../InheritanceWithoutIncludeShouldWork.cs | 53 +- .../MappingInheritance/MapToBaseClass.cs | 135 +- ...pleInheritedBaseMappingsOfSameTypeFails.cs | 57 +- .../OpenGenericsWithInheritance.cs | 437 ++- .../MappingInheritance/OverrideIgnore.cs | 69 +- ...yOnMappingShouldResolveMostSpecificType.cs | 337 +- .../ReverseMapWithInclude.cs | 111 +- .../ShouldInheritBeforeAndAfterMap.cs | 227 +- ...dSupportOnlyDestinationTypeBeingDerived.cs | 337 +- .../SourceValidationWithInheritance.cs | 233 +- src/UnitTests/MaxDepthTests.cs | 149 +- src/UnitTests/MaxExecutionPlanDepth.cs | 641 ++-- src/UnitTests/MemberNameReplacers.cs | 77 +- src/UnitTests/NullBehavior.cs | 1775 +++++---- src/UnitTests/OpenGenerics.cs | 915 +++-- src/UnitTests/Projection/ConstructorTests.cs | 395 +- src/UnitTests/Projection/ExplicitExpansion.cs | 123 +- .../ExplicitExpansionWithInheritance.cs | 211 +- src/UnitTests/Projection/ExplicitValues.cs | 73 +- src/UnitTests/Projection/GenericsTests.cs | 67 +- src/UnitTests/Projection/MapFromTest.cs | 187 +- .../MoreExplanatoryExceptionTests.cs | 43 +- .../Projection/NonGenericQueryableTests.cs | 89 +- src/UnitTests/Projection/NullSubstitutes.cs | 115 +- .../Projection/ParameterizedQueriesTests.cs | 305 +- .../ProjectCollectionEnumerableTest.cs | 113 +- .../Projection/ProjectCollectionListTest.cs | 143 +- src/UnitTests/Projection/ProjectEnumTest.cs | 113 +- .../ProjectEnumerableToArrayTest.cs | 81 +- .../Projection/ProjectIReadOnlyCollection.cs | 95 +- src/UnitTests/Projection/ProjectTest.cs | 159 +- src/UnitTests/Projection/ProjectionMappers.cs | 59 +- src/UnitTests/Projection/ProjectionTests.cs | 121 +- src/UnitTests/Projection/RecursiveQuery.cs | 57 +- src/UnitTests/Projection/ToStringTests.cs | 125 +- .../ReverseMapWithPreserveReferences.cs | 111 +- .../ReverseMapWithoutPreserveReferences.cs | 111 +- src/UnitTests/ReverseMapping.cs | 1093 +++--- src/UnitTests/SeparateConfiguration.cs | 53 +- src/UnitTests/ShouldUseConstructor.cs | 267 +- src/UnitTests/TesterExtensions.cs | 13 +- src/UnitTests/TypeConverters.cs | 561 ++- src/UnitTests/TypeExtensionsTests.cs | 45 +- src/UnitTests/UsingEngineInsideMap.cs | 103 +- src/UnitTests/ValueConverters.cs | 1109 +++--- src/UnitTests/ValueTypes.cs | 317 +- 399 files changed, 33659 insertions(+), 34034 deletions(-) diff --git a/.editorconfig b/.editorconfig index 8b620e3e4c..129050fb9c 100644 --- a/.editorconfig +++ b/.editorconfig @@ -2,7 +2,7 @@ root = true [*] -end_of_line = LF +end_of_line = lf indent_style = space indent_size = 4 @@ -21,7 +21,7 @@ dotnet_naming_style.constant_style.capitalization = pascal_case # Static fields are PascalCase dotnet_naming_rule.static_fields_should_be_pascal_case.severity = suggestion dotnet_naming_rule.static_fields_should_be_pascal_case.symbols = static_fields -dotnet_naming_rule.static_fields_should_be_pascal_case.style = static_field_style +dotnet_naming_rule.static_fields_should_be_pascal_case.style = constant_style dotnet_naming_symbols.static_fields.applicable_kinds = field dotnet_naming_symbols.static_fields.applicable_accessibilities = * @@ -32,7 +32,7 @@ dotnet_naming_style.static_field_style.capitalization = pascal_case # Public and internal fields are PascalCase dotnet_naming_rule.public_and_internal_should_be_pascal_case.severity = suggestion dotnet_naming_rule.public_and_internal_should_be_pascal_case.symbols = public_internal_fields -dotnet_naming_rule.public_and_internal_should_be_pascal_case.style = public_internal_fields_style +dotnet_naming_rule.public_and_internal_should_be_pascal_case.style = constant_style dotnet_naming_symbols.public_internal_fields.applicable_kinds = field dotnet_naming_symbols.public_internal_fields.applicable_accessibilities = public, internal @@ -58,6 +58,32 @@ dotnet_naming_rule.locals_should_be_camel_case.style = camel_case_style dotnet_naming_symbols.locals_and_parameters.applicable_kinds = parameter, local dotnet_naming_style.camel_case_style.capitalization = camel_case +dotnet_style_operator_placement_when_wrapping = beginning_of_line +tab_width = 4 +csharp_indent_labels = one_less_than_current +dotnet_style_coalesce_expression = true:suggestion +dotnet_style_null_propagation = true:suggestion +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion +dotnet_style_prefer_auto_properties = true:silent +csharp_using_directive_placement = outside_namespace:silent +csharp_prefer_simple_using_statement = true:suggestion +csharp_prefer_braces = true:silent +csharp_style_namespace_declarations = block_scoped:silent +csharp_style_prefer_method_group_conversion = true:silent +csharp_style_prefer_top_level_statements = true:silent +csharp_style_expression_bodied_methods = false:silent +csharp_style_expression_bodied_constructors = false:silent +csharp_style_expression_bodied_operators = false:silent +csharp_style_expression_bodied_properties = true:silent +csharp_style_expression_bodied_indexers = true:silent +csharp_style_expression_bodied_accessors = true:silent +csharp_style_expression_bodied_lambdas = true:silent +csharp_style_expression_bodied_local_functions = false:silent +dotnet_style_object_initializer = true:suggestion +dotnet_style_namespace_match_folder = true:silent +dotnet_style_explicit_tuple_names = true:suggestion +dotnet_style_prefer_inferred_tuple_names = true:suggestion +dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion [*.xml] indent_size = 2 diff --git a/src/AutoMapper/AssemblyInfo.cs b/src/AutoMapper/AssemblyInfo.cs index 40bb836e5c..0f468a9a17 100644 --- a/src/AutoMapper/AssemblyInfo.cs +++ b/src/AutoMapper/AssemblyInfo.cs @@ -6,7 +6,6 @@ [assembly: ComVisible(false)] [assembly: NeutralResourcesLanguage("en")] -namespace System.Runtime.CompilerServices -{ - static class IsExternalInit { } -} \ No newline at end of file +namespace System.Runtime.CompilerServices; + +static class IsExternalInit { } \ No newline at end of file diff --git a/src/AutoMapper/AutoMapperMappingException.cs b/src/AutoMapper/AutoMapperMappingException.cs index 8bc00f3c19..9a0b262310 100644 --- a/src/AutoMapper/AutoMapperMappingException.cs +++ b/src/AutoMapper/AutoMapperMappingException.cs @@ -3,228 +3,227 @@ using System.Linq; using AutoMapper.Internal; -namespace AutoMapper +namespace AutoMapper; + +/// +/// Wraps mapping exceptions. Check exception.ToString() for the full error message. +/// +public class AutoMapperMappingException : Exception { - /// - /// Wraps mapping exceptions. Check exception.ToString() for the full error message. - /// - public class AutoMapperMappingException : Exception - { - private readonly string _message; + private readonly string _message; - public AutoMapperMappingException() - { - } + public AutoMapperMappingException() + { + } - public AutoMapperMappingException(string message) - : base(message) => _message = message; + public AutoMapperMappingException(string message) + : base(message) => _message = message; - public AutoMapperMappingException(string message, Exception innerException) - : base(message, innerException) => _message = message; + public AutoMapperMappingException(string message, Exception innerException) + : base(message, innerException) => _message = message; - public AutoMapperMappingException(string message, Exception innerException, TypePair types) - : this(message, innerException) => Types = types; + public AutoMapperMappingException(string message, Exception innerException, TypePair types) + : this(message, innerException) => Types = types; - public AutoMapperMappingException(string message, Exception innerException, TypeMap typeMap) - : this(message, innerException, typeMap.Types) => TypeMap = typeMap; + public AutoMapperMappingException(string message, Exception innerException, TypeMap typeMap) + : this(message, innerException, typeMap.Types) => TypeMap = typeMap; - public AutoMapperMappingException(string message, Exception innerException, MemberMap memberMap) - : this(message, innerException, memberMap.TypeMap) => MemberMap = memberMap; + public AutoMapperMappingException(string message, Exception innerException, MemberMap memberMap) + : this(message, innerException, memberMap.TypeMap) => MemberMap = memberMap; - public TypePair? Types { get; set; } - public TypeMap TypeMap { get; set; } - public MemberMap MemberMap { get; set; } + public TypePair? Types { get; set; } + public TypeMap TypeMap { get; set; } + public MemberMap MemberMap { get; set; } - public override string Message + public override string Message + { + get { - get + var message = _message; + var newLine = Environment.NewLine; + if (Types.HasValue && Types.Value.SourceType != null && Types.Value.DestinationType != null) { - var message = _message; - var newLine = Environment.NewLine; - if (Types.HasValue && Types.Value.SourceType != null && Types.Value.DestinationType != null) - { - message = message + newLine + newLine + "Mapping types:"; - message += newLine + $"{Types.Value.SourceType.Name} -> {Types.Value.DestinationType.Name}"; - message += newLine + $"{Types.Value.SourceType.FullName} -> {Types.Value.DestinationType.FullName}"; - } - if (TypeMap != null) - { - message = message + newLine + newLine + "Type Map configuration:"; - message += newLine + $"{TypeMap.SourceType.Name} -> {TypeMap.DestinationType.Name}"; - message += newLine + $"{TypeMap.SourceType.FullName} -> {TypeMap.DestinationType.FullName}"; - } - if (MemberMap != null) - { - message = message + newLine + newLine + "Destination Member:"; - message += newLine + $"{MemberMap}" + newLine; - } - - return message; + message = message + newLine + newLine + "Mapping types:"; + message += newLine + $"{Types.Value.SourceType.Name} -> {Types.Value.DestinationType.Name}"; + message += newLine + $"{Types.Value.SourceType.FullName} -> {Types.Value.DestinationType.FullName}"; } - } - -#if !DEBUG - public override string StackTrace - { - get + if (TypeMap != null) { - return string.Join(Environment.NewLine, - base.StackTrace - .Split(new[] {Environment.NewLine}, StringSplitOptions.None) - .Where(str => !str.TrimStart().StartsWith("at AutoMapper."))); + message = message + newLine + newLine + "Type Map configuration:"; + message += newLine + $"{TypeMap.SourceType.Name} -> {TypeMap.DestinationType.Name}"; + message += newLine + $"{TypeMap.SourceType.FullName} -> {TypeMap.DestinationType.FullName}"; } - } -#endif - } - public class DuplicateTypeMapConfigurationException : Exception - { - public TypeMapConfigErrors[] Errors { get; } - - public DuplicateTypeMapConfigurationException(TypeMapConfigErrors[] errors) - { - Errors = errors; - var builder = new StringBuilder(); - builder.AppendLine("The following type maps were found in multiple profiles:"); - foreach (var error in Errors) + if (MemberMap != null) { - builder.AppendLine($"{error.Types.SourceType.FullName} to {error.Types.DestinationType.FullName} defined in profiles:"); - builder.AppendLine(string.Join(Environment.NewLine, error.ProfileNames)); + message = message + newLine + newLine + "Destination Member:"; + message += newLine + $"{MemberMap}" + newLine; } - builder.AppendLine("This can cause configuration collisions and inconsistent mapping."); - builder.AppendLine("Consolidate the CreateMap calls into one profile, or set the root Internal().AllowAdditiveTypeMapCreation configuration value to 'true'."); - Message = builder.ToString(); + return message; } + } - public class TypeMapConfigErrors +#if !DEBUG + public override string StackTrace + { + get { - public string[] ProfileNames { get; } - public TypePair Types { get; } + return string.Join(Environment.NewLine, + base.StackTrace + .Split(new[] {Environment.NewLine}, StringSplitOptions.None) + .Where(str => !str.TrimStart().StartsWith("at AutoMapper."))); + } + } +#endif +} +public class DuplicateTypeMapConfigurationException : Exception +{ + public TypeMapConfigErrors[] Errors { get; } - public TypeMapConfigErrors(TypePair types, string[] profileNames) - { - Types = types; - ProfileNames = profileNames; - } + public DuplicateTypeMapConfigurationException(TypeMapConfigErrors[] errors) + { + Errors = errors; + var builder = new StringBuilder(); + builder.AppendLine("The following type maps were found in multiple profiles:"); + foreach (var error in Errors) + { + builder.AppendLine($"{error.Types.SourceType.FullName} to {error.Types.DestinationType.FullName} defined in profiles:"); + builder.AppendLine(string.Join(Environment.NewLine, error.ProfileNames)); } + builder.AppendLine("This can cause configuration collisions and inconsistent mapping."); + builder.AppendLine("Consolidate the CreateMap calls into one profile, or set the root Internal().AllowAdditiveTypeMapCreation configuration value to 'true'."); - public override string Message { get; } + Message = builder.ToString(); } - public class AutoMapperConfigurationException : Exception + + public class TypeMapConfigErrors { - public TypeMapConfigErrors[] Errors { get; } - public TypePair? Types { get; } - public MemberMap MemberMap { get; set; } + public string[] ProfileNames { get; } + public TypePair Types { get; } - public class TypeMapConfigErrors + public TypeMapConfigErrors(TypePair types, string[] profileNames) { - public TypeMap TypeMap { get; } - public string[] UnmappedPropertyNames { get; } - public bool CanConstruct { get; } - - public TypeMapConfigErrors(TypeMap typeMap, string[] unmappedPropertyNames, bool canConstruct) - { - TypeMap = typeMap; - UnmappedPropertyNames = unmappedPropertyNames; - CanConstruct = canConstruct; - } + Types = types; + ProfileNames = profileNames; } + } - public AutoMapperConfigurationException(string message) - : base(message) - { - } + public override string Message { get; } +} +public class AutoMapperConfigurationException : Exception +{ + public TypeMapConfigErrors[] Errors { get; } + public TypePair? Types { get; } + public MemberMap MemberMap { get; set; } - public AutoMapperConfigurationException(string message, Exception inner) - : base(message, inner) + public class TypeMapConfigErrors + { + public TypeMap TypeMap { get; } + public string[] UnmappedPropertyNames { get; } + public bool CanConstruct { get; } + + public TypeMapConfigErrors(TypeMap typeMap, string[] unmappedPropertyNames, bool canConstruct) { + TypeMap = typeMap; + UnmappedPropertyNames = unmappedPropertyNames; + CanConstruct = canConstruct; } + } - public AutoMapperConfigurationException(TypeMapConfigErrors[] errors) => Errors = errors; + public AutoMapperConfigurationException(string message) + : base(message) + { + } + + public AutoMapperConfigurationException(string message, Exception inner) + : base(message, inner) + { + } - public AutoMapperConfigurationException(TypePair types) => Types = types; + public AutoMapperConfigurationException(TypeMapConfigErrors[] errors) => Errors = errors; - public override string Message + public AutoMapperConfigurationException(TypePair types) => Types = types; + + public override string Message + { + get { - get + if (Types.HasValue) { - if (Types.HasValue) - { - var message = - string.Format( - "The following member on {0} cannot be mapped: \n\t{2} \nAdd a custom mapping expression, ignore, add a custom resolver, or modify the destination type {1}.", - Types.Value.DestinationType.FullName, Types.Value.DestinationType.FullName, - MemberMap); + var message = + string.Format( + "The following member on {0} cannot be mapped: \n\t{2} \nAdd a custom mapping expression, ignore, add a custom resolver, or modify the destination type {1}.", + Types.Value.DestinationType.FullName, Types.Value.DestinationType.FullName, + MemberMap); - message += "\nContext:"; + message += "\nContext:"; - Exception exToUse = this; - while (exToUse != null) + Exception exToUse = this; + while (exToUse != null) + { + if (exToUse is AutoMapperConfigurationException configExc) { - if (exToUse is AutoMapperConfigurationException configExc) - { - message += configExc.MemberMap == null - ? $"\n\tMapping from type {configExc.Types.Value.SourceType.FullName} to {configExc.Types.Value.DestinationType.FullName}" - : $"\n\tMapping to member {configExc.MemberMap} from {configExc.Types.Value.SourceType.FullName} to {configExc.Types.Value.DestinationType.FullName}"; - } - - exToUse = exToUse.InnerException; + message += configExc.MemberMap == null + ? $"\n\tMapping from type {configExc.Types.Value.SourceType.FullName} to {configExc.Types.Value.DestinationType.FullName}" + : $"\n\tMapping to member {configExc.MemberMap} from {configExc.Types.Value.SourceType.FullName} to {configExc.Types.Value.DestinationType.FullName}"; } - return message + "\n" + base.Message; + exToUse = exToUse.InnerException; } - if (Errors != null) - { - var message = - new StringBuilder( - "\nUnmapped members were found. Review the types and members below.\nAdd a custom mapping expression, ignore, add a custom resolver, or modify the source/destination type\nFor no matching constructor, add a no-arg ctor, add optional arguments, or map all of the constructor parameters\n"); - foreach (var error in Errors) + return message + "\n" + base.Message; + } + if (Errors != null) + { + var message = + new StringBuilder( + "\nUnmapped members were found. Review the types and members below.\nAdd a custom mapping expression, ignore, add a custom resolver, or modify the source/destination type\nFor no matching constructor, add a no-arg ctor, add optional arguments, or map all of the constructor parameters\n"); + + foreach (var error in Errors) + { + var len = error.TypeMap.SourceType.FullName.Length + + error.TypeMap.DestinationType.FullName.Length + 5; + + message.AppendLine(new string('=', len)); + message.AppendLine(error.TypeMap.SourceType.Name + " -> " + error.TypeMap.DestinationType.Name + + " (" + + error.TypeMap.ConfiguredMemberList + " member list)"); + message.AppendLine(error.TypeMap.SourceType.FullName + " -> " + + error.TypeMap.DestinationType.FullName + " (" + + error.TypeMap.ConfiguredMemberList + " member list)"); + message.AppendLine(); + + if (error.UnmappedPropertyNames.Any()) { - var len = error.TypeMap.SourceType.FullName.Length + - error.TypeMap.DestinationType.FullName.Length + 5; - - message.AppendLine(new string('=', len)); - message.AppendLine(error.TypeMap.SourceType.Name + " -> " + error.TypeMap.DestinationType.Name + - " (" + - error.TypeMap.ConfiguredMemberList + " member list)"); - message.AppendLine(error.TypeMap.SourceType.FullName + " -> " + - error.TypeMap.DestinationType.FullName + " (" + - error.TypeMap.ConfiguredMemberList + " member list)"); - message.AppendLine(); - - if (error.UnmappedPropertyNames.Any()) - { - message.AppendLine("Unmapped properties:"); - foreach (var name in error.UnmappedPropertyNames) - { - message.AppendLine(name); - } - } - if (!error.CanConstruct) + message.AppendLine("Unmapped properties:"); + foreach (var name in error.UnmappedPropertyNames) { - message.AppendLine("No available constructor."); + message.AppendLine(name); } } - return message.ToString(); + if (!error.CanConstruct) + { + message.AppendLine("No available constructor."); + } } - return base.Message; + return message.ToString(); } + return base.Message; } + } - public override string StackTrace + public override string StackTrace + { + get { - get - { - if (Errors != null) - return string.Join(Environment.NewLine, - base.StackTrace - .Split(new[] { Environment.NewLine }, StringSplitOptions.None) - .Where(str => !str.TrimStart().StartsWith("at AutoMapper.")) - .ToArray()); - - return base.StackTrace; - } + if (Errors != null) + return string.Join(Environment.NewLine, + base.StackTrace + .Split(new[] { Environment.NewLine }, StringSplitOptions.None) + .Where(str => !str.TrimStart().StartsWith("at AutoMapper.")) + .ToArray()); + + return base.StackTrace; } } } \ No newline at end of file diff --git a/src/AutoMapper/Configuration/Annotations/AutoMapAttribute.cs b/src/AutoMapper/Configuration/Annotations/AutoMapAttribute.cs index cfa836ed65..325a52789a 100644 --- a/src/AutoMapper/Configuration/Annotations/AutoMapAttribute.cs +++ b/src/AutoMapper/Configuration/Annotations/AutoMapAttribute.cs @@ -1,96 +1,95 @@ using System; -namespace AutoMapper +namespace AutoMapper; + +/// +/// Auto map to this destination type from the specified source type. +/// Discovered during scanning assembly scanning for configuration when calling +/// +[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Struct, AllowMultiple = true)] +public sealed class AutoMapAttribute : Attribute { + public AutoMapAttribute(Type sourceType) + => SourceType = sourceType; + + public Type SourceType { get; } + public bool ReverseMap { get; set; } + + /// + /// If set to true, construct the destination object using the service locator. + /// + public bool ConstructUsingServiceLocator { get; set; } + + /// + /// For self-referential types, limit recurse depth. + /// + public int MaxDepth { get; set; } + + /// + /// If set to true, preserve object identity. Useful for circular references. + /// + public bool PreserveReferences { get; set; } + /// - /// Auto map to this destination type from the specified source type. - /// Discovered during scanning assembly scanning for configuration when calling + /// If set to true, disable constructor validation. /// - [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Struct, AllowMultiple = true)] - public sealed class AutoMapAttribute : Attribute + public bool DisableCtorValidation { get; set; } + + /// + /// If set to true, include this configuration in all derived types' maps. + /// + public bool IncludeAllDerived { get; set; } + + /// + /// Skip normal member mapping and convert using a instantiated during mapping. + /// + public Type TypeConverter { get; set; } + + /// + /// If set to true, proxy will be created. + /// + public bool AsProxy { get; set; } + + public void ApplyConfiguration(IMappingExpression mappingExpression) { - public AutoMapAttribute(Type sourceType) - => SourceType = sourceType; - - public Type SourceType { get; } - public bool ReverseMap { get; set; } - - /// - /// If set to true, construct the destination object using the service locator. - /// - public bool ConstructUsingServiceLocator { get; set; } - - /// - /// For self-referential types, limit recurse depth. - /// - public int MaxDepth { get; set; } - - /// - /// If set to true, preserve object identity. Useful for circular references. - /// - public bool PreserveReferences { get; set; } - - /// - /// If set to true, disable constructor validation. - /// - public bool DisableCtorValidation { get; set; } - - /// - /// If set to true, include this configuration in all derived types' maps. - /// - public bool IncludeAllDerived { get; set; } - - /// - /// Skip normal member mapping and convert using a instantiated during mapping. - /// - public Type TypeConverter { get; set; } - - /// - /// If set to true, proxy will be created. - /// - public bool AsProxy { get; set; } - - public void ApplyConfiguration(IMappingExpression mappingExpression) + if (ReverseMap) + { + mappingExpression.ReverseMap(); + } + + if (ConstructUsingServiceLocator) + { + mappingExpression.ConstructUsingServiceLocator(); + } + + if (MaxDepth > 0) + { + mappingExpression.MaxDepth(MaxDepth); + } + + if (PreserveReferences) + { + mappingExpression.PreserveReferences(); + } + + if (DisableCtorValidation) + { + mappingExpression.DisableCtorValidation(); + } + + if (IncludeAllDerived) + { + mappingExpression.IncludeAllDerived(); + } + + if (TypeConverter != null) + { + mappingExpression.ConvertUsing(TypeConverter); + } + + if (AsProxy) { - if (ReverseMap) - { - mappingExpression.ReverseMap(); - } - - if (ConstructUsingServiceLocator) - { - mappingExpression.ConstructUsingServiceLocator(); - } - - if (MaxDepth > 0) - { - mappingExpression.MaxDepth(MaxDepth); - } - - if (PreserveReferences) - { - mappingExpression.PreserveReferences(); - } - - if (DisableCtorValidation) - { - mappingExpression.DisableCtorValidation(); - } - - if (IncludeAllDerived) - { - mappingExpression.IncludeAllDerived(); - } - - if (TypeConverter != null) - { - mappingExpression.ConvertUsing(TypeConverter); - } - - if (AsProxy) - { - mappingExpression.AsProxy(); - } + mappingExpression.AsProxy(); } } } diff --git a/src/AutoMapper/Configuration/Annotations/IgnoreAttribute.cs b/src/AutoMapper/Configuration/Annotations/IgnoreAttribute.cs index de5ec40ade..79c8e78d99 100644 --- a/src/AutoMapper/Configuration/Annotations/IgnoreAttribute.cs +++ b/src/AutoMapper/Configuration/Annotations/IgnoreAttribute.cs @@ -1,19 +1,18 @@ using System; -namespace AutoMapper.Configuration.Annotations +namespace AutoMapper.Configuration.Annotations; + +/// +/// Ignore this member for configuration validation and skip during mapping. +/// +/// +/// Must be used in combination with +/// +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] +public sealed class IgnoreAttribute : Attribute, IMemberConfigurationProvider { - /// - /// Ignore this member for configuration validation and skip during mapping. - /// - /// - /// Must be used in combination with - /// - [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] - public sealed class IgnoreAttribute : Attribute, IMemberConfigurationProvider + public void ApplyConfiguration(IMemberConfigurationExpression memberConfigurationExpression) { - public void ApplyConfiguration(IMemberConfigurationExpression memberConfigurationExpression) - { - memberConfigurationExpression.Ignore(); - } + memberConfigurationExpression.Ignore(); } } \ No newline at end of file diff --git a/src/AutoMapper/Configuration/Annotations/MapAtRuntimeAttribute.cs b/src/AutoMapper/Configuration/Annotations/MapAtRuntimeAttribute.cs index 5d178b276f..1bc23fe0fa 100644 --- a/src/AutoMapper/Configuration/Annotations/MapAtRuntimeAttribute.cs +++ b/src/AutoMapper/Configuration/Annotations/MapAtRuntimeAttribute.cs @@ -1,20 +1,19 @@ using System; -namespace AutoMapper.Configuration.Annotations +namespace AutoMapper.Configuration.Annotations; + +/// +/// Do not precompute the execution plan for this member, just map it at runtime. +/// Simplifies the execution plan by not inlining. +/// +/// +/// Must be used in combination with +/// +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] +public sealed class MapAtRuntimeAttribute : Attribute, IMemberConfigurationProvider { - /// - /// Do not precompute the execution plan for this member, just map it at runtime. - /// Simplifies the execution plan by not inlining. - /// - /// - /// Must be used in combination with - /// - [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] - public sealed class MapAtRuntimeAttribute : Attribute, IMemberConfigurationProvider + public void ApplyConfiguration(IMemberConfigurationExpression memberConfigurationExpression) { - public void ApplyConfiguration(IMemberConfigurationExpression memberConfigurationExpression) - { - memberConfigurationExpression.MapAtRuntime(); - } + memberConfigurationExpression.MapAtRuntime(); } } \ No newline at end of file diff --git a/src/AutoMapper/Configuration/Annotations/MappingOrderAttribute.cs b/src/AutoMapper/Configuration/Annotations/MappingOrderAttribute.cs index fd66142983..e80e6db64f 100644 --- a/src/AutoMapper/Configuration/Annotations/MappingOrderAttribute.cs +++ b/src/AutoMapper/Configuration/Annotations/MappingOrderAttribute.cs @@ -1,26 +1,25 @@ using System; -namespace AutoMapper.Configuration.Annotations +namespace AutoMapper.Configuration.Annotations; + +/// +/// Supply a custom mapping order instead of what the .NET runtime returns +/// +/// +/// Must be used in combination with +/// +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] +public sealed class MappingOrderAttribute : Attribute, IMemberConfigurationProvider { - /// - /// Supply a custom mapping order instead of what the .NET runtime returns - /// - /// - /// Must be used in combination with - /// - [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] - public sealed class MappingOrderAttribute : Attribute, IMemberConfigurationProvider - { - public int Value { get; } + public int Value { get; } - public MappingOrderAttribute(int value) - { - Value = value; - } + public MappingOrderAttribute(int value) + { + Value = value; + } - public void ApplyConfiguration(IMemberConfigurationExpression memberConfigurationExpression) - { - memberConfigurationExpression.SetMappingOrder(Value); - } + public void ApplyConfiguration(IMemberConfigurationExpression memberConfigurationExpression) + { + memberConfigurationExpression.SetMappingOrder(Value); } } \ No newline at end of file diff --git a/src/AutoMapper/Configuration/Annotations/NullSubstituteAttribute.cs b/src/AutoMapper/Configuration/Annotations/NullSubstituteAttribute.cs index a673520904..a6b69a46e1 100644 --- a/src/AutoMapper/Configuration/Annotations/NullSubstituteAttribute.cs +++ b/src/AutoMapper/Configuration/Annotations/NullSubstituteAttribute.cs @@ -1,29 +1,28 @@ using System; -namespace AutoMapper.Configuration.Annotations +namespace AutoMapper.Configuration.Annotations; + +/// +/// Substitute a custom value when the source member resolves as null +/// +/// +/// Must be used in combination with +/// +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] +public sealed class NullSubstituteAttribute : Attribute, IMemberConfigurationProvider { /// - /// Substitute a custom value when the source member resolves as null + /// Value to use if source value is null /// - /// - /// Must be used in combination with - /// - [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] - public sealed class NullSubstituteAttribute : Attribute, IMemberConfigurationProvider - { - /// - /// Value to use if source value is null - /// - public object Value { get; } + public object Value { get; } - public NullSubstituteAttribute(object value) - { - Value = value; - } + public NullSubstituteAttribute(object value) + { + Value = value; + } - public void ApplyConfiguration(IMemberConfigurationExpression memberConfigurationExpression) - { - memberConfigurationExpression.NullSubstitute(Value); - } + public void ApplyConfiguration(IMemberConfigurationExpression memberConfigurationExpression) + { + memberConfigurationExpression.NullSubstitute(Value); } } \ No newline at end of file diff --git a/src/AutoMapper/Configuration/Annotations/SourceMemberAttribute.cs b/src/AutoMapper/Configuration/Annotations/SourceMemberAttribute.cs index de1d7cbcdf..03d9ce31aa 100644 --- a/src/AutoMapper/Configuration/Annotations/SourceMemberAttribute.cs +++ b/src/AutoMapper/Configuration/Annotations/SourceMemberAttribute.cs @@ -2,29 +2,28 @@ using System; using System.Reflection; -namespace AutoMapper.Configuration.Annotations +namespace AutoMapper.Configuration.Annotations; + +/// +/// Specify the source member to map from. Can only reference a member on the type +/// +/// +/// Must be used in combination with +/// +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] +public sealed class SourceMemberAttribute : Attribute, IMemberConfigurationProvider { - /// - /// Specify the source member to map from. Can only reference a member on the type - /// - /// - /// Must be used in combination with - /// - [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] - public sealed class SourceMemberAttribute : Attribute, IMemberConfigurationProvider - { - public string Name { get; } + public string Name { get; } - public SourceMemberAttribute(string name) => Name = name; + public SourceMemberAttribute(string name) => Name = name; - public void ApplyConfiguration(IMemberConfigurationExpression memberConfigurationExpression) + public void ApplyConfiguration(IMemberConfigurationExpression memberConfigurationExpression) + { + var destinationMember = memberConfigurationExpression.DestinationMember; + if (destinationMember.Has() || destinationMember.Has()) { - var destinationMember = memberConfigurationExpression.DestinationMember; - if (destinationMember.Has() || destinationMember.Has()) - { - return; - } - memberConfigurationExpression.MapFrom(Name); + return; } + memberConfigurationExpression.MapFrom(Name); } } \ No newline at end of file diff --git a/src/AutoMapper/Configuration/Annotations/UseExistingValueAttribute.cs b/src/AutoMapper/Configuration/Annotations/UseExistingValueAttribute.cs index defd4131e1..b822bf5bf0 100644 --- a/src/AutoMapper/Configuration/Annotations/UseExistingValueAttribute.cs +++ b/src/AutoMapper/Configuration/Annotations/UseExistingValueAttribute.cs @@ -1,19 +1,18 @@ using System; -namespace AutoMapper.Configuration.Annotations +namespace AutoMapper.Configuration.Annotations; + +/// +/// Use the destination value instead of mapping from the source value or creating a new instance +/// +/// +/// Must be used in combination with +/// +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] +public sealed class UseExistingValueAttribute : Attribute, IMemberConfigurationProvider { - /// - /// Use the destination value instead of mapping from the source value or creating a new instance - /// - /// - /// Must be used in combination with - /// - [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] - public sealed class UseExistingValueAttribute : Attribute, IMemberConfigurationProvider + public void ApplyConfiguration(IMemberConfigurationExpression memberConfigurationExpression) { - public void ApplyConfiguration(IMemberConfigurationExpression memberConfigurationExpression) - { - memberConfigurationExpression.UseDestinationValue(); - } + memberConfigurationExpression.UseDestinationValue(); } } \ No newline at end of file diff --git a/src/AutoMapper/Configuration/Annotations/ValueConverterAttribute.cs b/src/AutoMapper/Configuration/Annotations/ValueConverterAttribute.cs index 6d3759782d..2c02e92600 100644 --- a/src/AutoMapper/Configuration/Annotations/ValueConverterAttribute.cs +++ b/src/AutoMapper/Configuration/Annotations/ValueConverterAttribute.cs @@ -1,40 +1,39 @@ using System; using System.Reflection; -namespace AutoMapper.Configuration.Annotations +namespace AutoMapper.Configuration.Annotations; + +/// +/// Specify a value converter type to convert from the matching source member to the destination member +/// Use with to specify a separate source member to supply to the value converter +/// +/// +/// Must be used in combination with +/// +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] +public sealed class ValueConverterAttribute : Attribute, IMemberConfigurationProvider { /// - /// Specify a value converter type to convert from the matching source member to the destination member - /// Use with to specify a separate source member to supply to the value converter + /// type /// - /// - /// Must be used in combination with - /// - [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] - public sealed class ValueConverterAttribute : Attribute, IMemberConfigurationProvider + public Type Type { get; } + + public ValueConverterAttribute(Type type) { - /// - /// type - /// - public Type Type { get; } + Type = type; + } - public ValueConverterAttribute(Type type) + public void ApplyConfiguration(IMemberConfigurationExpression memberConfigurationExpression) + { + var sourceMemberAttribute = memberConfigurationExpression.DestinationMember.GetCustomAttribute(); + + if (sourceMemberAttribute != null) { - Type = type; + memberConfigurationExpression.ConvertUsing(Type, sourceMemberAttribute.Name); } - - public void ApplyConfiguration(IMemberConfigurationExpression memberConfigurationExpression) + else { - var sourceMemberAttribute = memberConfigurationExpression.DestinationMember.GetCustomAttribute(); - - if (sourceMemberAttribute != null) - { - memberConfigurationExpression.ConvertUsing(Type, sourceMemberAttribute.Name); - } - else - { - memberConfigurationExpression.ConvertUsing(Type); - } + memberConfigurationExpression.ConvertUsing(Type); } } } \ No newline at end of file diff --git a/src/AutoMapper/Configuration/Annotations/ValueResolverAttribute.cs b/src/AutoMapper/Configuration/Annotations/ValueResolverAttribute.cs index 5fd5bb4719..8748d6bed4 100644 --- a/src/AutoMapper/Configuration/Annotations/ValueResolverAttribute.cs +++ b/src/AutoMapper/Configuration/Annotations/ValueResolverAttribute.cs @@ -1,40 +1,39 @@ using System; using System.Reflection; -namespace AutoMapper.Configuration.Annotations +namespace AutoMapper.Configuration.Annotations; + +/// +/// Map destination member using a custom value resolver. +/// Use with to specify an type. +/// +/// +/// Must be used in combination with +/// +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] +public sealed class ValueResolverAttribute : Attribute, IMemberConfigurationProvider { /// - /// Map destination member using a custom value resolver. - /// Use with to specify an type. + /// or type /// - /// - /// Must be used in combination with - /// - [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] - public sealed class ValueResolverAttribute : Attribute, IMemberConfigurationProvider + public Type Type { get; } + + public ValueResolverAttribute(Type type) { - /// - /// or type - /// - public Type Type { get; } + Type = type; + } - public ValueResolverAttribute(Type type) + public void ApplyConfiguration(IMemberConfigurationExpression memberConfigurationExpression) + { + var sourceMemberAttribute = memberConfigurationExpression.DestinationMember.GetCustomAttribute(); + + if (sourceMemberAttribute != null) { - Type = type; + memberConfigurationExpression.MapFrom(Type, sourceMemberAttribute.Name); } - - public void ApplyConfiguration(IMemberConfigurationExpression memberConfigurationExpression) + else { - var sourceMemberAttribute = memberConfigurationExpression.DestinationMember.GetCustomAttribute(); - - if (sourceMemberAttribute != null) - { - memberConfigurationExpression.MapFrom(Type, sourceMemberAttribute.Name); - } - else - { - memberConfigurationExpression.MapFrom(Type); - } + memberConfigurationExpression.MapFrom(Type); } } } \ No newline at end of file diff --git a/src/AutoMapper/Configuration/ConfigurationValidator.cs b/src/AutoMapper/Configuration/ConfigurationValidator.cs index 9f8776a36f..5b399f5a3a 100644 --- a/src/AutoMapper/Configuration/ConfigurationValidator.cs +++ b/src/AutoMapper/Configuration/ConfigurationValidator.cs @@ -4,131 +4,130 @@ using System.Linq; using AutoMapper.Internal; using AutoMapper.Internal.Mappers; -namespace AutoMapper.Configuration +namespace AutoMapper.Configuration; + +[EditorBrowsable(EditorBrowsableState.Never)] +public readonly record struct ConfigurationValidator(IGlobalConfigurationExpression Expression) { - [EditorBrowsable(EditorBrowsableState.Never)] - public readonly record struct ConfigurationValidator(IGlobalConfigurationExpression Expression) + private void Validate(ValidationContext context) { - private void Validate(ValidationContext context) + foreach (var validator in Expression.Validators) { - foreach (var validator in Expression.Validators) - { - validator(context); - } + validator(context); } - public void AssertConfigurationExpressionIsValid(IGlobalConfiguration config, IEnumerable typeMaps) + } + public void AssertConfigurationExpressionIsValid(IGlobalConfiguration config, IEnumerable typeMaps) + { + if (!Expression.AllowAdditiveTypeMapCreation) { - if (!Expression.AllowAdditiveTypeMapCreation) + var duplicateTypeMapConfigs = Expression.Profiles.Append((Profile)Expression) + .SelectMany(p => p.TypeMapConfigs, (profile, typeMap) => (profile, typeMap)) + .GroupBy(x => x.typeMap.Types) + .Where(g => g.Count() > 1) + .Select(g => (TypePair : g.Key, ProfileNames : g.Select(tmc => tmc.profile.ProfileName).ToArray())) + .Select(g => new DuplicateTypeMapConfigurationException.TypeMapConfigErrors(g.TypePair, g.ProfileNames)) + .ToArray(); + if (duplicateTypeMapConfigs.Any()) { - var duplicateTypeMapConfigs = Expression.Profiles.Append((Profile)Expression) - .SelectMany(p => p.TypeMapConfigs, (profile, typeMap) => (profile, typeMap)) - .GroupBy(x => x.typeMap.Types) - .Where(g => g.Count() > 1) - .Select(g => (TypePair : g.Key, ProfileNames : g.Select(tmc => tmc.profile.ProfileName).ToArray())) - .Select(g => new DuplicateTypeMapConfigurationException.TypeMapConfigErrors(g.TypePair, g.ProfileNames)) - .ToArray(); - if (duplicateTypeMapConfigs.Any()) - { - throw new DuplicateTypeMapConfigurationException(duplicateTypeMapConfigs); - } + throw new DuplicateTypeMapConfigurationException(duplicateTypeMapConfigs); } - AssertConfigurationIsValid(config, typeMaps); } - public void AssertConfigurationIsValid(IGlobalConfiguration config, IEnumerable typeMaps) - { - var maps = typeMaps as TypeMap[] ?? typeMaps.ToArray(); - var badTypeMaps = - (from typeMap in maps - where typeMap.ShouldCheckForValid - let unmappedPropertyNames = typeMap.GetUnmappedPropertyNames() - let canConstruct = typeMap.PassesCtorValidation - where unmappedPropertyNames.Length > 0 || !canConstruct - select new AutoMapperConfigurationException.TypeMapConfigErrors(typeMap, unmappedPropertyNames, canConstruct) - ).ToArray(); + AssertConfigurationIsValid(config, typeMaps); + } + public void AssertConfigurationIsValid(IGlobalConfiguration config, IEnumerable typeMaps) + { + var maps = typeMaps as TypeMap[] ?? typeMaps.ToArray(); + var badTypeMaps = + (from typeMap in maps + where typeMap.ShouldCheckForValid + let unmappedPropertyNames = typeMap.GetUnmappedPropertyNames() + let canConstruct = typeMap.PassesCtorValidation + where unmappedPropertyNames.Length > 0 || !canConstruct + select new AutoMapperConfigurationException.TypeMapConfigErrors(typeMap, unmappedPropertyNames, canConstruct) + ).ToArray(); - if (badTypeMaps.Any()) - { - throw new AutoMapperConfigurationException(badTypeMaps); - } - var typeMapsChecked = new List(); - var configExceptions = new List(); - foreach (var typeMap in maps) + if (badTypeMaps.Any()) + { + throw new AutoMapperConfigurationException(badTypeMaps); + } + var typeMapsChecked = new List(); + var configExceptions = new List(); + foreach (var typeMap in maps) + { + try { - try - { - DryRunTypeMap(config, typeMapsChecked, typeMap.Types, typeMap, null); - } - catch (Exception e) - { - configExceptions.Add(e); - } + DryRunTypeMap(config, typeMapsChecked, typeMap.Types, typeMap, null); } - if (configExceptions.Count > 1) + catch (Exception e) { - throw new AggregateException(configExceptions); + configExceptions.Add(e); } - if (configExceptions.Count > 0) + } + if (configExceptions.Count > 1) + { + throw new AggregateException(configExceptions); + } + if (configExceptions.Count > 0) + { + throw configExceptions[0]; + } + } + private void DryRunTypeMap(IGlobalConfiguration config, ICollection typeMapsChecked, TypePair types, TypeMap typeMap, MemberMap memberMap) + { + if(typeMap == null) + { + if (types.ContainsGenericParameters) { - throw configExceptions[0]; + return; } + typeMap = config.ResolveTypeMap(types.SourceType, types.DestinationType); } - private void DryRunTypeMap(IGlobalConfiguration config, ICollection typeMapsChecked, TypePair types, TypeMap typeMap, MemberMap memberMap) + if (typeMap != null) { - if(typeMap == null) + if (typeMapsChecked.Contains(typeMap)) + { + return; + } + typeMapsChecked.Add(typeMap); + var context = new ValidationContext(types, memberMap, typeMap); + Validate(context); + if(!typeMap.ShouldCheckForValid) { - if (types.ContainsGenericParameters) - { - return; - } - typeMap = config.ResolveTypeMap(types.SourceType, types.DestinationType); + return; } - if (typeMap != null) + CheckPropertyMaps(config, typeMapsChecked, typeMap); + } + else + { + var mapperToUse = config.FindMapper(types); + if (mapperToUse == null) { - if (typeMapsChecked.Contains(typeMap)) - { - return; - } - typeMapsChecked.Add(typeMap); - var context = new ValidationContext(types, memberMap, typeMap); - Validate(context); - if(!typeMap.ShouldCheckForValid) - { - return; - } - CheckPropertyMaps(config, typeMapsChecked, typeMap); + throw new AutoMapperConfigurationException(memberMap.TypeMap.Types) { MemberMap = memberMap }; } - else + var context = new ValidationContext(types, memberMap, ObjectMapper: mapperToUse); + Validate(context); + if (mapperToUse.GetAssociatedTypes(types) is TypePair newTypes && newTypes != types) { - var mapperToUse = config.FindMapper(types); - if (mapperToUse == null) - { - throw new AutoMapperConfigurationException(memberMap.TypeMap.Types) { MemberMap = memberMap }; - } - var context = new ValidationContext(types, memberMap, ObjectMapper: mapperToUse); - Validate(context); - if (mapperToUse.GetAssociatedTypes(types) is TypePair newTypes && newTypes != types) - { - DryRunTypeMap(config, typeMapsChecked, newTypes, null, memberMap); - } + DryRunTypeMap(config, typeMapsChecked, newTypes, null, memberMap); } } - private void CheckPropertyMaps(IGlobalConfiguration config, ICollection typeMapsChecked, TypeMap typeMap) + } + private void CheckPropertyMaps(IGlobalConfiguration config, ICollection typeMapsChecked, TypeMap typeMap) + { + foreach (var memberMap in typeMap.MemberMaps) { - foreach (var memberMap in typeMap.MemberMaps) + if(memberMap.Ignored) + { + continue; + } + var sourceType = memberMap.SourceType; + // when we don't know what the source type is, bail + if (sourceType.IsGenericParameter || sourceType == typeof(object)) { - if(memberMap.Ignored) - { - continue; - } - var sourceType = memberMap.SourceType; - // when we don't know what the source type is, bail - if (sourceType.IsGenericParameter || sourceType == typeof(object)) - { - return; - } - DryRunTypeMap(config, typeMapsChecked, new(sourceType, memberMap.DestinationType), null, memberMap); + return; } + DryRunTypeMap(config, typeMapsChecked, new(sourceType, memberMap.DestinationType), null, memberMap); } } - public readonly record struct ValidationContext(TypePair Types, MemberMap MemberMap, TypeMap TypeMap = null, IObjectMapper ObjectMapper = null); -} \ No newline at end of file +} +public readonly record struct ValidationContext(TypePair Types, MemberMap MemberMap, TypeMap TypeMap = null, IObjectMapper ObjectMapper = null); \ No newline at end of file diff --git a/src/AutoMapper/Configuration/Conventions.cs b/src/AutoMapper/Configuration/Conventions.cs index 2425c841bd..deb94dcfee 100644 --- a/src/AutoMapper/Configuration/Conventions.cs +++ b/src/AutoMapper/Configuration/Conventions.cs @@ -4,205 +4,204 @@ using System.ComponentModel; using System.Linq; using System.Reflection; -namespace AutoMapper.Configuration.Conventions +namespace AutoMapper.Configuration.Conventions; + +public interface ISourceToDestinationNameMapper { - public interface ISourceToDestinationNameMapper + MemberInfo GetSourceMember(TypeDetails sourceTypeDetails, Type destType, Type destMemberType, string nameToSearch); + void Merge(ISourceToDestinationNameMapper other); +} +[EditorBrowsable(EditorBrowsableState.Never)] +public class MemberConfiguration +{ + NameSplitMember _nameSplitMember; + public INamingConvention SourceNamingConvention { get; set; } = PascalCaseNamingConvention.Instance; + public INamingConvention DestinationNamingConvention { get; set; } = PascalCaseNamingConvention.Instance; + public List NameToMemberMappers { get; } = new(); + public bool IsMatch(ProfileMap options, TypeDetails sourceTypeDetails, Type destType, Type destMemberType, string nameToSearch, List resolvers, bool isReverseMap) { - MemberInfo GetSourceMember(TypeDetails sourceTypeDetails, Type destType, Type destMemberType, string nameToSearch); - void Merge(ISourceToDestinationNameMapper other); + var matchingMemberInfo = GetSourceMember(sourceTypeDetails, destType, destMemberType, nameToSearch); + if (matchingMemberInfo != null) + { + resolvers.Add(matchingMemberInfo); + return true; + } + return nameToSearch.Length == 0 || _nameSplitMember.IsMatch(options, sourceTypeDetails, destType, destMemberType, nameToSearch, resolvers, isReverseMap); } - [EditorBrowsable(EditorBrowsableState.Never)] - public class MemberConfiguration + public MemberInfo GetSourceMember(TypeDetails sourceTypeDetails, Type destType, Type destMemberType, string nameToSearch) { - NameSplitMember _nameSplitMember; - public INamingConvention SourceNamingConvention { get; set; } = PascalCaseNamingConvention.Instance; - public INamingConvention DestinationNamingConvention { get; set; } = PascalCaseNamingConvention.Instance; - public List NameToMemberMappers { get; } = new(); - public bool IsMatch(ProfileMap options, TypeDetails sourceTypeDetails, Type destType, Type destMemberType, string nameToSearch, List resolvers, bool isReverseMap) + var sourceMember = sourceTypeDetails.GetMember(nameToSearch); + if (sourceMember != null) { - var matchingMemberInfo = GetSourceMember(sourceTypeDetails, destType, destMemberType, nameToSearch); - if (matchingMemberInfo != null) - { - resolvers.Add(matchingMemberInfo); - return true; - } - return nameToSearch.Length == 0 || _nameSplitMember.IsMatch(options, sourceTypeDetails, destType, destMemberType, nameToSearch, resolvers, isReverseMap); + return sourceMember; } - public MemberInfo GetSourceMember(TypeDetails sourceTypeDetails, Type destType, Type destMemberType, string nameToSearch) + foreach (var mapper in NameToMemberMappers) { - var sourceMember = sourceTypeDetails.GetMember(nameToSearch); - if (sourceMember != null) + if ((sourceMember = mapper.GetSourceMember(sourceTypeDetails, destType, destMemberType, nameToSearch)) != null) { return sourceMember; } - foreach (var mapper in NameToMemberMappers) - { - if ((sourceMember = mapper.GetSourceMember(sourceTypeDetails, destType, destMemberType, nameToSearch)) != null) - { - return sourceMember; - } - } - return null; } - public void Seal() + return null; + } + public void Seal() + { + var isDefault = SourceNamingConvention == PascalCaseNamingConvention.Instance && DestinationNamingConvention == PascalCaseNamingConvention.Instance; + _nameSplitMember = isDefault ? new DefaultNameSplitMember() : new ConventionsNameSplitMember(); + _nameSplitMember.Parent = this; + } + public void Merge(MemberConfiguration other) + { + if (other == null) { - var isDefault = SourceNamingConvention == PascalCaseNamingConvention.Instance && DestinationNamingConvention == PascalCaseNamingConvention.Instance; - _nameSplitMember = isDefault ? new DefaultNameSplitMember() : new ConventionsNameSplitMember(); - _nameSplitMember.Parent = this; + return; } - public void Merge(MemberConfiguration other) + var initialCount = NameToMemberMappers.Count; + for (int index = 0; index < other.NameToMemberMappers.Count; index++) { - if (other == null) - { - return; - } - var initialCount = NameToMemberMappers.Count; - for (int index = 0; index < other.NameToMemberMappers.Count; index++) + var otherMapper = other.NameToMemberMappers[index]; + if (index < initialCount) { - var otherMapper = other.NameToMemberMappers[index]; - if (index < initialCount) + var nameToMemberMapper = NameToMemberMappers[index]; + if (nameToMemberMapper.GetType() == otherMapper.GetType()) { - var nameToMemberMapper = NameToMemberMappers[index]; - if (nameToMemberMapper.GetType() == otherMapper.GetType()) - { - nameToMemberMapper.Merge(otherMapper); - continue; - } + nameToMemberMapper.Merge(otherMapper); + continue; } - NameToMemberMappers.Add(otherMapper); } + NameToMemberMappers.Add(otherMapper); } } - public class PrePostfixName : ISourceToDestinationNameMapper +} +public class PrePostfixName : ISourceToDestinationNameMapper +{ + public HashSet DestinationPrefixes { get; } = new(); + public HashSet DestinationPostfixes { get; } = new(); + public MemberInfo GetSourceMember(TypeDetails sourceTypeDetails, Type destType, Type destMemberType, string nameToSearch) { - public HashSet DestinationPrefixes { get; } = new(); - public HashSet DestinationPostfixes { get; } = new(); - public MemberInfo GetSourceMember(TypeDetails sourceTypeDetails, Type destType, Type destMemberType, string nameToSearch) + MemberInfo member; + foreach (var possibleSourceName in TypeDetails.PossibleNames(nameToSearch, DestinationPrefixes, DestinationPostfixes)) { - MemberInfo member; - foreach (var possibleSourceName in TypeDetails.PossibleNames(nameToSearch, DestinationPrefixes, DestinationPostfixes)) + if ((member = sourceTypeDetails.GetMember(possibleSourceName)) != null) { - if ((member = sourceTypeDetails.GetMember(possibleSourceName)) != null) - { - return member; - } + return member; } - return null; - } - public void Merge(ISourceToDestinationNameMapper other) - { - var typedOther = (PrePostfixName)other; - DestinationPrefixes.UnionWith(typedOther.DestinationPrefixes); - DestinationPostfixes.UnionWith(typedOther.DestinationPostfixes); } + return null; + } + public void Merge(ISourceToDestinationNameMapper other) + { + var typedOther = (PrePostfixName)other; + DestinationPrefixes.UnionWith(typedOther.DestinationPrefixes); + DestinationPostfixes.UnionWith(typedOther.DestinationPostfixes); } - public class ReplaceName : ISourceToDestinationNameMapper +} +public class ReplaceName : ISourceToDestinationNameMapper +{ + public HashSet MemberNameReplacers { get; } = new(); + public MemberInfo GetSourceMember(TypeDetails sourceTypeDetails, Type destType, Type destMemberType, string nameToSearch) { - public HashSet MemberNameReplacers { get; } = new(); - public MemberInfo GetSourceMember(TypeDetails sourceTypeDetails, Type destType, Type destMemberType, string nameToSearch) + var possibleSourceNames = PossibleNames(nameToSearch); + if (possibleSourceNames.Length == 0) { - var possibleSourceNames = PossibleNames(nameToSearch); - if (possibleSourceNames.Length == 0) - { - return null; - } - var possibleDestNames = sourceTypeDetails.ReadAccessors.Select(mi => (mi, possibles : PossibleNames(mi.Name))).ToArray(); - foreach (var sourceName in possibleSourceNames) + return null; + } + var possibleDestNames = sourceTypeDetails.ReadAccessors.Select(mi => (mi, possibles : PossibleNames(mi.Name))).ToArray(); + foreach (var sourceName in possibleSourceNames) + { + foreach (var (mi, possibles) in possibleDestNames) { - foreach (var (mi, possibles) in possibleDestNames) + if (possibles.Contains(sourceName, StringComparer.OrdinalIgnoreCase)) { - if (possibles.Contains(sourceName, StringComparer.OrdinalIgnoreCase)) - { - return mi; - } + return mi; } } - return null; - } - public void Merge(ISourceToDestinationNameMapper other) - { - var typedOther = (ReplaceName)other; - MemberNameReplacers.UnionWith(typedOther.MemberNameReplacers); } - private string[] PossibleNames(string nameToSearch) => - MemberNameReplacers.Select(r => nameToSearch.Replace(r.OriginalValue, r.NewValue)) - .Concat(new[] { MemberNameReplacers.Aggregate(nameToSearch, (s, r) => s.Replace(r.OriginalValue, r.NewValue)), nameToSearch }) - .ToArray(); + return null; } - [EditorBrowsable(EditorBrowsableState.Never)] - public readonly record struct MemberNameReplacer(string OriginalValue, string NewValue); - [EditorBrowsable(EditorBrowsableState.Never)] - public abstract class NameSplitMember + public void Merge(ISourceToDestinationNameMapper other) { - public MemberConfiguration Parent { get; set; } - public abstract bool IsMatch(ProfileMap options, TypeDetails sourceType, Type destType, Type destMemberType, string nameToSearch, List resolvers, bool isReverseMap); + var typedOther = (ReplaceName)other; + MemberNameReplacers.UnionWith(typedOther.MemberNameReplacers); } - [EditorBrowsable(EditorBrowsableState.Never)] - public sealed class DefaultNameSplitMember : NameSplitMember + private string[] PossibleNames(string nameToSearch) => + MemberNameReplacers.Select(r => nameToSearch.Replace(r.OriginalValue, r.NewValue)) + .Concat(new[] { MemberNameReplacers.Aggregate(nameToSearch, (s, r) => s.Replace(r.OriginalValue, r.NewValue)), nameToSearch }) + .ToArray(); +} +[EditorBrowsable(EditorBrowsableState.Never)] +public readonly record struct MemberNameReplacer(string OriginalValue, string NewValue); +[EditorBrowsable(EditorBrowsableState.Never)] +public abstract class NameSplitMember +{ + public MemberConfiguration Parent { get; set; } + public abstract bool IsMatch(ProfileMap options, TypeDetails sourceType, Type destType, Type destMemberType, string nameToSearch, List resolvers, bool isReverseMap); +} +[EditorBrowsable(EditorBrowsableState.Never)] +public sealed class DefaultNameSplitMember : NameSplitMember +{ + public sealed override bool IsMatch(ProfileMap options, TypeDetails sourceType, Type destType, Type destMemberType, string nameToSearch, List resolvers, bool isReverseMap) { - public sealed override bool IsMatch(ProfileMap options, TypeDetails sourceType, Type destType, Type destMemberType, string nameToSearch, List resolvers, bool isReverseMap) + MemberInfo matchingMemberInfo = null; + int index = 1; + for (; index < nameToSearch.Length; index++) { - MemberInfo matchingMemberInfo = null; - int index = 1; - for (; index < nameToSearch.Length; index++) + if (char.IsUpper(nameToSearch[index]) && Found()) { - if (char.IsUpper(nameToSearch[index]) && Found()) - { - return true; - } + return true; } - return matchingMemberInfo != null && Found(); - bool Found() + } + return matchingMemberInfo != null && Found(); + bool Found() + { + var first = nameToSearch[..index]; + matchingMemberInfo = Parent.GetSourceMember(sourceType, destType, destMemberType, first); + if (matchingMemberInfo == null) { - var first = nameToSearch[..index]; - matchingMemberInfo = Parent.GetSourceMember(sourceType, destType, destMemberType, first); - if (matchingMemberInfo == null) - { - return false; - } - resolvers.Add(matchingMemberInfo); - var second = nameToSearch[index..]; - var details = options.CreateTypeDetails(matchingMemberInfo.GetMemberType()); - if (Parent.IsMatch(options, details, destType, destMemberType, second, resolvers, isReverseMap)) - { - return true; - } - resolvers.RemoveAt(resolvers.Count - 1); return false; } + resolvers.Add(matchingMemberInfo); + var second = nameToSearch[index..]; + var details = options.CreateTypeDetails(matchingMemberInfo.GetMemberType()); + if (Parent.IsMatch(options, details, destType, destMemberType, second, resolvers, isReverseMap)) + { + return true; + } + resolvers.RemoveAt(resolvers.Count - 1); + return false; } } - [EditorBrowsable(EditorBrowsableState.Never)] - public sealed class ConventionsNameSplitMember : NameSplitMember +} +[EditorBrowsable(EditorBrowsableState.Never)] +public sealed class ConventionsNameSplitMember : NameSplitMember +{ + public sealed override bool IsMatch(ProfileMap options, TypeDetails sourceType, Type destType, Type destMemberType, string nameToSearch, List resolvers, bool isReverseMap) { - public sealed override bool IsMatch(ProfileMap options, TypeDetails sourceType, Type destType, Type destMemberType, string nameToSearch, List resolvers, bool isReverseMap) + var destinationNamingConvention = isReverseMap ? Parent.SourceNamingConvention : Parent.DestinationNamingConvention; + var matches = destinationNamingConvention.Split(nameToSearch); + var length = matches.Length; + if (length < 2) { - var destinationNamingConvention = isReverseMap ? Parent.SourceNamingConvention : Parent.DestinationNamingConvention; - var matches = destinationNamingConvention.Split(nameToSearch); - var length = matches.Length; - if (length < 2) - { - return false; - } - var sourceNamingConvention = isReverseMap ? Parent.DestinationNamingConvention : Parent.SourceNamingConvention; - var separator = sourceNamingConvention.SeparatorCharacter; - for (var index = 1; index <= length; index++) + return false; + } + var sourceNamingConvention = isReverseMap ? Parent.DestinationNamingConvention : Parent.SourceNamingConvention; + var separator = sourceNamingConvention.SeparatorCharacter; + for (var index = 1; index <= length; index++) + { + var first = string.Join(separator, matches, 0, index); + var matchingMemberInfo = Parent.GetSourceMember(sourceType, destType, destMemberType, first); + if (matchingMemberInfo != null) { - var first = string.Join(separator, matches, 0, index); - var matchingMemberInfo = Parent.GetSourceMember(sourceType, destType, destMemberType, first); - if (matchingMemberInfo != null) + resolvers.Add(matchingMemberInfo); + var second = string.Join(separator, matches, index, length - index); + var details = options.CreateTypeDetails(matchingMemberInfo.GetMemberType()); + if (Parent.IsMatch(options, details, destType, destMemberType, second, resolvers, isReverseMap)) { - resolvers.Add(matchingMemberInfo); - var second = string.Join(separator, matches, index, length - index); - var details = options.CreateTypeDetails(matchingMemberInfo.GetMemberType()); - if (Parent.IsMatch(options, details, destType, destMemberType, second, resolvers, isReverseMap)) - { - return true; - } - resolvers.RemoveAt(resolvers.Count - 1); + return true; } + resolvers.RemoveAt(resolvers.Count - 1); } - return false; } + return false; } } \ No newline at end of file diff --git a/src/AutoMapper/Configuration/CtorParamConfigurationExpression.cs b/src/AutoMapper/Configuration/CtorParamConfigurationExpression.cs index 5bd1ff09e8..4daca5bef6 100644 --- a/src/AutoMapper/Configuration/CtorParamConfigurationExpression.cs +++ b/src/AutoMapper/Configuration/CtorParamConfigurationExpression.cs @@ -6,85 +6,84 @@ using System.Linq.Expressions; using System.Reflection; using System.Runtime.CompilerServices; -namespace AutoMapper.Configuration +namespace AutoMapper.Configuration; + +public interface ICtorParamConfigurationExpression { - public interface ICtorParamConfigurationExpression - { - /// - /// Specify the source member(s) to map from. - /// - /// Property name referencing the source member to map against. Or a dot separated member path. - void MapFrom(string sourceMembersPath); - } - public interface ICtorParamConfigurationExpression : ICtorParamConfigurationExpression - { - /// - /// Map constructor parameter from member expression - /// - /// Member type - /// Member expression - void MapFrom(Expression> sourceMember); + /// + /// Specify the source member(s) to map from. + /// + /// Property name referencing the source member to map against. Or a dot separated member path. + void MapFrom(string sourceMembersPath); +} +public interface ICtorParamConfigurationExpression : ICtorParamConfigurationExpression +{ + /// + /// Map constructor parameter from member expression + /// + /// Member type + /// Member expression + void MapFrom(Expression> sourceMember); - /// - /// Map constructor parameter from custom func that has access to - /// - /// Not used for LINQ projection (ProjectTo) - /// Custom func - void MapFrom(Func resolver); - } - public interface ICtorParameterConfiguration + /// + /// Map constructor parameter from custom func that has access to + /// + /// Not used for LINQ projection (ProjectTo) + /// Custom func + void MapFrom(Func resolver); +} +public interface ICtorParameterConfiguration +{ + string CtorParamName { get; } + void Configure(TypeMap typeMap); +} +[EditorBrowsable(EditorBrowsableState.Never)] +public class CtorParamConfigurationExpression : ICtorParamConfigurationExpression, ICtorParameterConfiguration +{ + public string CtorParamName { get; } + public Type SourceType { get; } + + private readonly List> _ctorParamActions = new List>(); + + public CtorParamConfigurationExpression(string ctorParamName, Type sourceType) { - string CtorParamName { get; } - void Configure(TypeMap typeMap); + CtorParamName = ctorParamName; + SourceType = sourceType; } - [EditorBrowsable(EditorBrowsableState.Never)] - public class CtorParamConfigurationExpression : ICtorParamConfigurationExpression, ICtorParameterConfiguration - { - public string CtorParamName { get; } - public Type SourceType { get; } - private readonly List> _ctorParamActions = new List>(); + public void MapFrom(Expression> sourceMember) => + _ctorParamActions.Add(cpm => cpm.SetResolver(sourceMember)); - public CtorParamConfigurationExpression(string ctorParamName, Type sourceType) - { - CtorParamName = ctorParamName; - SourceType = sourceType; - } + public void MapFrom(Func resolver) + { + Expression> resolverExpression = (src, dest, destMember, ctxt) => resolver(src, ctxt); + _ctorParamActions.Add(cpm => cpm.Resolver = new FuncResolver(resolverExpression)); + } - public void MapFrom(Expression> sourceMember) => - _ctorParamActions.Add(cpm => cpm.SetResolver(sourceMember)); + public void MapFrom(string sourceMembersPath) + { + var sourceMembers = ReflectionHelper.GetMemberPath(SourceType, sourceMembersPath); + _ctorParamActions.Add(cpm => cpm.MapFrom(sourceMembersPath, sourceMembers)); + } - public void MapFrom(Func resolver) + public void Configure(TypeMap typeMap) + { + var ctorMap = typeMap.ConstructorMap; + if (ctorMap == null) { - Expression> resolverExpression = (src, dest, destMember, ctxt) => resolver(src, ctxt); - _ctorParamActions.Add(cpm => cpm.Resolver = new FuncResolver(resolverExpression)); + throw new AutoMapperConfigurationException($"The type {typeMap.DestinationType.Name} does not have a constructor.\n{typeMap.DestinationType.FullName}"); } - - public void MapFrom(string sourceMembersPath) + var parameter = ctorMap[CtorParamName]; + if (parameter == null) { - var sourceMembers = ReflectionHelper.GetMemberPath(SourceType, sourceMembersPath); - _ctorParamActions.Add(cpm => cpm.MapFrom(sourceMembersPath, sourceMembers)); + throw new AutoMapperConfigurationException($"{typeMap.DestinationType.Name} does not have a matching constructor with a parameter named '{CtorParamName}'.\n{typeMap.DestinationType.FullName}.{CheckRecord(ctorMap.Ctor)}"); } - - public void Configure(TypeMap typeMap) + foreach (var action in _ctorParamActions) { - var ctorMap = typeMap.ConstructorMap; - if (ctorMap == null) - { - throw new AutoMapperConfigurationException($"The type {typeMap.DestinationType.Name} does not have a constructor.\n{typeMap.DestinationType.FullName}"); - } - var parameter = ctorMap[CtorParamName]; - if (parameter == null) - { - throw new AutoMapperConfigurationException($"{typeMap.DestinationType.Name} does not have a matching constructor with a parameter named '{CtorParamName}'.\n{typeMap.DestinationType.FullName}.{CheckRecord(ctorMap.Ctor)}"); - } - foreach (var action in _ctorParamActions) - { - action(parameter); - } - return; - static string CheckRecord(ConstructorInfo ctor) => ctor.IsFamily && ctor.Has() ? - " When mapping to records, consider excluding non-public constructors. See https://docs.automapper.org/en/latest/Construction.html." : null; + action(parameter); } + return; + static string CheckRecord(ConstructorInfo ctor) => ctor.IsFamily && ctor.Has() ? + " When mapping to records, consider excluding non-public constructors. See https://docs.automapper.org/en/latest/Construction.html." : null; } } \ No newline at end of file diff --git a/src/AutoMapper/Configuration/IMappingExpression.cs b/src/AutoMapper/Configuration/IMappingExpression.cs index 56d05765ff..f5a17d3c98 100644 --- a/src/AutoMapper/Configuration/IMappingExpression.cs +++ b/src/AutoMapper/Configuration/IMappingExpression.cs @@ -2,137 +2,136 @@ using System; using System.Linq.Expressions; -namespace AutoMapper +namespace AutoMapper; + +/// +/// Mapping configuration options for non-generic maps +/// +public interface IMappingExpression : IMappingExpressionBase +{ + /// + /// Add extra configuration to the current map by also mapping the specified child objects to the destination object. + /// The maps from the child types to the destination need to be created explicitly. + /// + /// the names of child object properties to map to the destination + /// + IMappingExpression IncludeMembers(params string[] memberNames); + /// + /// Create a type mapping from the destination to the source type, with validation disabled. + /// This allows for two-way mapping. + /// + /// Itself + IMappingExpression ReverseMap(); + /// + /// Customize configuration for all members + /// + /// Callback for member options + void ForAllMembers(Action memberOptions); + /// + /// Customize individual members + /// + /// Name of the member + /// Callback for configuring member + /// Itself + IMappingExpression ForMember(string name, Action memberOptions); +} +/// +/// Mapping configuration options +/// +/// Source type +/// Destination type +public interface IMappingExpression : IMappingExpressionBase>, + IProjectionExpression> { /// - /// Mapping configuration options for non-generic maps - /// - public interface IMappingExpression : IMappingExpressionBase - { - /// - /// Add extra configuration to the current map by also mapping the specified child objects to the destination object. - /// The maps from the child types to the destination need to be created explicitly. - /// - /// the names of child object properties to map to the destination - /// - IMappingExpression IncludeMembers(params string[] memberNames); - /// - /// Create a type mapping from the destination to the source type, with validation disabled. - /// This allows for two-way mapping. - /// - /// Itself - IMappingExpression ReverseMap(); - /// - /// Customize configuration for all members - /// - /// Callback for member options - void ForAllMembers(Action memberOptions); - /// - /// Customize individual members - /// - /// Name of the member - /// Callback for configuring member - /// Itself - IMappingExpression ForMember(string name, Action memberOptions); - } - /// - /// Mapping configuration options - /// - /// Source type - /// Destination type - public interface IMappingExpression : IMappingExpressionBase>, - IProjectionExpression> - { - /// - /// Customize configuration for a path inside the destination object. - /// - /// Expression to the destination sub object - /// Callback for member options - /// Itself - IMappingExpression ForPath(Expression> destinationMember, - Action> memberOptions); - /// - /// Customize configuration for individual member - /// - /// Expression to the top-level destination member. This must be a member on the TDestination type - /// Callback for member options - /// Itself - IMappingExpression ForMember(Expression> destinationMember, - Action> memberOptions); - /// - /// Customize configuration for individual member. Used when the name isn't known at compile-time - /// - /// Destination member name - /// Callback for member options - /// Itself - IMappingExpression ForMember(string name, - Action> memberOptions); - /// - /// Customize configuration for all members - /// - /// Callback for member options - void ForAllMembers(Action> memberOptions); - /// - /// Include this configuration in derived types' maps - /// - /// Derived source type - /// Derived destination type - /// Itself - IMappingExpression Include() where TOtherSource : TSource where TOtherDestination : TDestination; - /// - /// Include the base type map's configuration in this map - /// - /// Base source type - /// Base destination type - /// Itself - IMappingExpression IncludeBase(); - /// - /// Customize configuration for an individual source member - /// - /// Expression to source member. Must be a member of the type - /// Callback for member configuration options - /// Itself - IMappingExpression ForSourceMember(Expression> sourceMember, - Action memberOptions); - /// - /// Create a type mapping from the destination to the source type, with validation disabled. - /// This allows for two-way mapping. - /// - /// Itself - IMappingExpression ReverseMap(); - /// - /// Override the destination type mapping for looking up configuration and instantiation - /// - /// Destination type to use - void As() where T : TDestination; - } - public interface IProjectionExpression : IProjectionExpressionBase - where TMappingExpression : IProjectionExpressionBase - { - /// - /// Apply a transformation function after any resolved destination member value with the given type - /// - /// Value type to match and transform - /// Transformation expression - /// Itself - TMappingExpression AddTransform(Expression> transformer); - /// - /// Add extra configuration to the current map by also mapping the specified child objects to the destination object. - /// The maps from the child types to the destination need to be created explicitly. - /// - /// the child objects to map to the destination - /// - TMappingExpression IncludeMembers(params Expression>[] memberExpressions); - } - public interface IProjectionExpression : IProjectionExpression> - { - /// - /// Customize configuration for individual member - /// - /// Expression to the top-level destination member. This must be a member on the TDestination type - /// Callback for member options - /// Itself - IProjectionExpression ForMember(Expression> destinationMember, - Action> memberOptions); - } + /// Customize configuration for a path inside the destination object. + /// + /// Expression to the destination sub object + /// Callback for member options + /// Itself + IMappingExpression ForPath(Expression> destinationMember, + Action> memberOptions); + /// + /// Customize configuration for individual member + /// + /// Expression to the top-level destination member. This must be a member on the TDestination type + /// Callback for member options + /// Itself + IMappingExpression ForMember(Expression> destinationMember, + Action> memberOptions); + /// + /// Customize configuration for individual member. Used when the name isn't known at compile-time + /// + /// Destination member name + /// Callback for member options + /// Itself + IMappingExpression ForMember(string name, + Action> memberOptions); + /// + /// Customize configuration for all members + /// + /// Callback for member options + void ForAllMembers(Action> memberOptions); + /// + /// Include this configuration in derived types' maps + /// + /// Derived source type + /// Derived destination type + /// Itself + IMappingExpression Include() where TOtherSource : TSource where TOtherDestination : TDestination; + /// + /// Include the base type map's configuration in this map + /// + /// Base source type + /// Base destination type + /// Itself + IMappingExpression IncludeBase(); + /// + /// Customize configuration for an individual source member + /// + /// Expression to source member. Must be a member of the type + /// Callback for member configuration options + /// Itself + IMappingExpression ForSourceMember(Expression> sourceMember, + Action memberOptions); + /// + /// Create a type mapping from the destination to the source type, with validation disabled. + /// This allows for two-way mapping. + /// + /// Itself + IMappingExpression ReverseMap(); + /// + /// Override the destination type mapping for looking up configuration and instantiation + /// + /// Destination type to use + void As() where T : TDestination; +} +public interface IProjectionExpression : IProjectionExpressionBase + where TMappingExpression : IProjectionExpressionBase +{ + /// + /// Apply a transformation function after any resolved destination member value with the given type + /// + /// Value type to match and transform + /// Transformation expression + /// Itself + TMappingExpression AddTransform(Expression> transformer); + /// + /// Add extra configuration to the current map by also mapping the specified child objects to the destination object. + /// The maps from the child types to the destination need to be created explicitly. + /// + /// the child objects to map to the destination + /// + TMappingExpression IncludeMembers(params Expression>[] memberExpressions); +} +public interface IProjectionExpression : IProjectionExpression> +{ + /// + /// Customize configuration for individual member + /// + /// Expression to the top-level destination member. This must be a member on the TDestination type + /// Callback for member options + /// Itself + IProjectionExpression ForMember(Expression> destinationMember, + Action> memberOptions); } \ No newline at end of file diff --git a/src/AutoMapper/Configuration/IMappingExpressionBase.cs b/src/AutoMapper/Configuration/IMappingExpressionBase.cs index 3c8e4dd0f2..8362126667 100644 --- a/src/AutoMapper/Configuration/IMappingExpressionBase.cs +++ b/src/AutoMapper/Configuration/IMappingExpressionBase.cs @@ -4,232 +4,231 @@ using AutoMapper.Configuration; using AutoMapper.Features; -namespace AutoMapper +namespace AutoMapper; + +/// +/// Common mapping configuration options between generic and non-generic mapping configuration +/// +/// Source type +/// Destination type +/// Concrete return type for fluent interface +public interface IProjectionExpressionBase where TMappingExpression : IProjectionExpressionBase { + Features Features { get; } + /// + /// For self-referential types, limit recurse depth. + /// Enables PreserveReferences. + /// + /// Number of levels to limit to + /// Itself + TMappingExpression MaxDepth(int depth); + /// + /// Value transformers, typically configured through explicit or extension methods. + /// + List ValueTransformers { get; } + /// + /// Specify which member list to validate + /// + /// Member list to validate + /// Itself + TMappingExpression ValidateMemberList(MemberList memberList); + /// + /// Supply a custom instantiation expression for the destination type + /// + /// Expression to create the destination type given the source object + /// Itself + TMappingExpression ConstructUsing(Expression> ctor); /// - /// Common mapping configuration options between generic and non-generic mapping configuration - /// - /// Source type - /// Destination type - /// Concrete return type for fluent interface - public interface IProjectionExpressionBase where TMappingExpression : IProjectionExpressionBase - { - Features Features { get; } - /// - /// For self-referential types, limit recurse depth. - /// Enables PreserveReferences. - /// - /// Number of levels to limit to - /// Itself - TMappingExpression MaxDepth(int depth); - /// - /// Value transformers, typically configured through explicit or extension methods. - /// - List ValueTransformers { get; } - /// - /// Specify which member list to validate - /// - /// Member list to validate - /// Itself - TMappingExpression ValidateMemberList(MemberList memberList); - /// - /// Supply a custom instantiation expression for the destination type - /// - /// Expression to create the destination type given the source object - /// Itself - TMappingExpression ConstructUsing(Expression> ctor); - /// - /// Customize configuration for individual constructor parameter - /// - /// Constructor parameter name - /// Options - /// Itself - TMappingExpression ForCtorParam(string ctorParamName, Action> paramOptions); - /// - /// Skip member mapping and use a custom expression to convert to the destination type - /// - /// Callback to convert from source type to destination type - void ConvertUsing(Expression> mappingExpression); - } - /// - /// Common mapping configuration options between generic and non-generic mapping configuration - /// - /// Source type - /// Destination type - /// Concrete return type for fluent interface - public interface IMappingExpressionBase : IProjectionExpressionBase - where TMappingExpression : IMappingExpressionBase - { - /// - /// Disable constructor validation. During mapping this map is used against an existing destination object and never constructed itself. - /// - /// Itself - TMappingExpression DisableCtorValidation(); - /// - /// Construct the destination object using the service locator - /// - /// Itself - TMappingExpression ConstructUsingServiceLocator(); - /// - /// Preserve object identity. Useful for circular references. - /// - /// Itself - TMappingExpression PreserveReferences(); - /// - /// Execute a custom function to the source and/or destination types before member mapping - /// - /// Not used for LINQ projection (ProjectTo) - /// Callback for the source/destination types - /// Itself - TMappingExpression BeforeMap(Action beforeFunction); - /// - /// Execute a custom function to the source and/or destination types before member mapping - /// - /// Not used for LINQ projection (ProjectTo) - /// Callback for the source/destination types - /// Itself - TMappingExpression BeforeMap(Action beforeFunction); - /// - /// Execute a custom mapping action before member mapping - /// - /// Not used for LINQ projection (ProjectTo) - /// Mapping action type instantiated during mapping - /// Itself - TMappingExpression BeforeMap() where TMappingAction : IMappingAction; - /// - /// Execute a custom function to the source and/or destination types after member mapping - /// - /// Not used for LINQ projection (ProjectTo) - /// Callback for the source/destination types - /// Itself - TMappingExpression AfterMap(Action afterFunction); - /// - /// Execute a custom function to the source and/or destination types after member mapping - /// - /// Not used for LINQ projection (ProjectTo) - /// Callback for the source/destination types - /// Itself - TMappingExpression AfterMap(Action afterFunction); - /// - /// Execute a custom mapping action after member mapping - /// - /// Not used for LINQ projection (ProjectTo) - /// Mapping action type instantiated during mapping - /// Itself - TMappingExpression AfterMap() where TMappingAction : IMappingAction; - /// - /// Include this configuration in all derived types' maps. Works by scanning all type maps for matches during configuration. - /// - /// Itself - TMappingExpression IncludeAllDerived(); - /// - /// Include this configuration in derived types' maps - /// - /// Derived source type - /// Derived destination type - /// Itself - TMappingExpression Include(Type derivedSourceType, Type derivedDestinationType); - /// - /// Include the base type map's configuration in this map - /// - /// Base source type - /// Base destination type - /// - TMappingExpression IncludeBase(Type sourceBase, Type destinationBase); - /// - /// Customize configuration for an individual source member. Member name not known until runtime - /// - /// Expression to source member. Must be a member of the type - /// Callback for member configuration options - /// Itself - TMappingExpression ForSourceMember(string sourceMemberName, Action memberOptions); - /// - /// Ignores all properties that have either a private or protected setter, forcing the mapper to respect encapsulation (note: order matters, so place this before explicit configuration of any properties with an inaccessible setter) - /// - /// Itself - TMappingExpression IgnoreAllPropertiesWithAnInaccessibleSetter(); - /// - /// When using ReverseMap, ignores all properties that have either a private or protected setter, keeping the reverse mapping consistent with the forward mapping (note: properties with an inaccessible setter may still be mapped unless IgnoreAllPropertiesWithAnInaccessibleSetter is also used) - /// - /// Itself - TMappingExpression IgnoreAllSourcePropertiesWithAnInaccessibleSetter(); - /// - /// Supply a custom instantiation function for the destination type, based on the entire resolution context - /// - /// Not used for LINQ projection (ProjectTo) - /// Callback to create the destination type given the current resolution context - /// Itself - TMappingExpression ConstructUsing(Func ctor); - /// - /// Override the destination type mapping for looking up configuration and instantiation - /// - /// - void As(Type typeOverride); - /// - /// Create at runtime a proxy type implementing the destination interface. - /// - /// Itself - TMappingExpression AsProxy(); - /// - /// Skip normal member mapping and convert using a instantiated during mapping - /// Use this method if you need to specify the converter type at runtime - /// - /// Type converter type - void ConvertUsing(Type typeConverterType); - /// - /// Skip member mapping and use a custom function to convert to the destination type - /// - /// Not used for LINQ projection (ProjectTo) - /// Callback to convert from source type to destination type, including destination object - void ConvertUsing(Func mappingFunction); - /// - /// Skip member mapping and use a custom function to convert to the destination type - /// - /// Not used for LINQ projection (ProjectTo) - /// Callback to convert from source type to destination type, with source, destination and context - void ConvertUsing(Func mappingFunction); - /// - /// Skip member mapping and use a custom type converter instance to convert to the destination type - /// - /// Not used for LINQ projection (ProjectTo) - /// Type converter instance - void ConvertUsing(ITypeConverter converter); - /// - /// Skip member mapping and use a custom type converter instance to convert to the destination type - /// - /// Not used for LINQ projection (ProjectTo) - /// Type converter type - void ConvertUsing() where TTypeConverter : ITypeConverter; - } - /// - /// Custom mapping action - /// - /// Source type - /// Destination type - public interface IMappingAction - { - /// - /// Implementors can modify both the source and destination objects - /// - /// Source object - /// Destination object - /// Resolution context - void Process(TSource source, TDestination destination, ResolutionContext context); - } - /// - /// Converts source type to destination type instead of normal member mapping - /// - /// Source type - /// Destination type - public interface ITypeConverter - { - /// - /// Performs conversion from source to destination type - /// - /// Source object - /// Destination object - /// Resolution context - /// Destination object - TDestination Convert(TSource source, TDestination destination, ResolutionContext context); - } + /// Customize configuration for individual constructor parameter + /// + /// Constructor parameter name + /// Options + /// Itself + TMappingExpression ForCtorParam(string ctorParamName, Action> paramOptions); + /// + /// Skip member mapping and use a custom expression to convert to the destination type + /// + /// Callback to convert from source type to destination type + void ConvertUsing(Expression> mappingExpression); +} +/// +/// Common mapping configuration options between generic and non-generic mapping configuration +/// +/// Source type +/// Destination type +/// Concrete return type for fluent interface +public interface IMappingExpressionBase : IProjectionExpressionBase + where TMappingExpression : IMappingExpressionBase +{ + /// + /// Disable constructor validation. During mapping this map is used against an existing destination object and never constructed itself. + /// + /// Itself + TMappingExpression DisableCtorValidation(); + /// + /// Construct the destination object using the service locator + /// + /// Itself + TMappingExpression ConstructUsingServiceLocator(); + /// + /// Preserve object identity. Useful for circular references. + /// + /// Itself + TMappingExpression PreserveReferences(); + /// + /// Execute a custom function to the source and/or destination types before member mapping + /// + /// Not used for LINQ projection (ProjectTo) + /// Callback for the source/destination types + /// Itself + TMappingExpression BeforeMap(Action beforeFunction); + /// + /// Execute a custom function to the source and/or destination types before member mapping + /// + /// Not used for LINQ projection (ProjectTo) + /// Callback for the source/destination types + /// Itself + TMappingExpression BeforeMap(Action beforeFunction); + /// + /// Execute a custom mapping action before member mapping + /// + /// Not used for LINQ projection (ProjectTo) + /// Mapping action type instantiated during mapping + /// Itself + TMappingExpression BeforeMap() where TMappingAction : IMappingAction; + /// + /// Execute a custom function to the source and/or destination types after member mapping + /// + /// Not used for LINQ projection (ProjectTo) + /// Callback for the source/destination types + /// Itself + TMappingExpression AfterMap(Action afterFunction); + /// + /// Execute a custom function to the source and/or destination types after member mapping + /// + /// Not used for LINQ projection (ProjectTo) + /// Callback for the source/destination types + /// Itself + TMappingExpression AfterMap(Action afterFunction); + /// + /// Execute a custom mapping action after member mapping + /// + /// Not used for LINQ projection (ProjectTo) + /// Mapping action type instantiated during mapping + /// Itself + TMappingExpression AfterMap() where TMappingAction : IMappingAction; + /// + /// Include this configuration in all derived types' maps. Works by scanning all type maps for matches during configuration. + /// + /// Itself + TMappingExpression IncludeAllDerived(); + /// + /// Include this configuration in derived types' maps + /// + /// Derived source type + /// Derived destination type + /// Itself + TMappingExpression Include(Type derivedSourceType, Type derivedDestinationType); + /// + /// Include the base type map's configuration in this map + /// + /// Base source type + /// Base destination type + /// + TMappingExpression IncludeBase(Type sourceBase, Type destinationBase); + /// + /// Customize configuration for an individual source member. Member name not known until runtime + /// + /// Expression to source member. Must be a member of the type + /// Callback for member configuration options + /// Itself + TMappingExpression ForSourceMember(string sourceMemberName, Action memberOptions); + /// + /// Ignores all properties that have either a private or protected setter, forcing the mapper to respect encapsulation (note: order matters, so place this before explicit configuration of any properties with an inaccessible setter) + /// + /// Itself + TMappingExpression IgnoreAllPropertiesWithAnInaccessibleSetter(); + /// + /// When using ReverseMap, ignores all properties that have either a private or protected setter, keeping the reverse mapping consistent with the forward mapping (note: properties with an inaccessible setter may still be mapped unless IgnoreAllPropertiesWithAnInaccessibleSetter is also used) + /// + /// Itself + TMappingExpression IgnoreAllSourcePropertiesWithAnInaccessibleSetter(); + /// + /// Supply a custom instantiation function for the destination type, based on the entire resolution context + /// + /// Not used for LINQ projection (ProjectTo) + /// Callback to create the destination type given the current resolution context + /// Itself + TMappingExpression ConstructUsing(Func ctor); + /// + /// Override the destination type mapping for looking up configuration and instantiation + /// + /// + void As(Type typeOverride); + /// + /// Create at runtime a proxy type implementing the destination interface. + /// + /// Itself + TMappingExpression AsProxy(); + /// + /// Skip normal member mapping and convert using a instantiated during mapping + /// Use this method if you need to specify the converter type at runtime + /// + /// Type converter type + void ConvertUsing(Type typeConverterType); + /// + /// Skip member mapping and use a custom function to convert to the destination type + /// + /// Not used for LINQ projection (ProjectTo) + /// Callback to convert from source type to destination type, including destination object + void ConvertUsing(Func mappingFunction); + /// + /// Skip member mapping and use a custom function to convert to the destination type + /// + /// Not used for LINQ projection (ProjectTo) + /// Callback to convert from source type to destination type, with source, destination and context + void ConvertUsing(Func mappingFunction); + /// + /// Skip member mapping and use a custom type converter instance to convert to the destination type + /// + /// Not used for LINQ projection (ProjectTo) + /// Type converter instance + void ConvertUsing(ITypeConverter converter); + /// + /// Skip member mapping and use a custom type converter instance to convert to the destination type + /// + /// Not used for LINQ projection (ProjectTo) + /// Type converter type + void ConvertUsing() where TTypeConverter : ITypeConverter; +} +/// +/// Custom mapping action +/// +/// Source type +/// Destination type +public interface IMappingAction +{ + /// + /// Implementors can modify both the source and destination objects + /// + /// Source object + /// Destination object + /// Resolution context + void Process(TSource source, TDestination destination, ResolutionContext context); +} +/// +/// Converts source type to destination type instead of normal member mapping +/// +/// Source type +/// Destination type +public interface ITypeConverter +{ + /// + /// Performs conversion from source to destination type + /// + /// Source object + /// Destination object + /// Resolution context + /// Destination object + TDestination Convert(TSource source, TDestination destination, ResolutionContext context); } \ No newline at end of file diff --git a/src/AutoMapper/Configuration/IMappingOperationOptions.cs b/src/AutoMapper/Configuration/IMappingOperationOptions.cs index 00d0fe3f13..9371278b21 100644 --- a/src/AutoMapper/Configuration/IMappingOperationOptions.cs +++ b/src/AutoMapper/Configuration/IMappingOperationOptions.cs @@ -1,69 +1,68 @@ using System; using System.Collections.Generic; -namespace AutoMapper +namespace AutoMapper; + +using StringDictionary = Dictionary; +/// +/// Options for a single map operation +/// +public interface IMappingOperationOptions { - using StringDictionary = Dictionary; + Func ServiceCtor { get; } + /// - /// Options for a single map operation + /// Construct services using this callback. Use this for child/nested containers /// - public interface IMappingOperationOptions - { - Func ServiceCtor { get; } + /// + void ConstructServicesUsing(Func constructor); - /// - /// Construct services using this callback. Use this for child/nested containers - /// - /// - void ConstructServicesUsing(Func constructor); - - /// - /// Add context items to be accessed at map time inside an or - /// - IDictionary Items { get; } + /// + /// Add context items to be accessed at map time inside an or + /// + IDictionary Items { get; } - /// - /// Execute a custom function to the source and/or destination types before member mapping - /// - /// Callback for the source/destination types - void BeforeMap(Action beforeFunction); + /// + /// Execute a custom function to the source and/or destination types before member mapping + /// + /// Callback for the source/destination types + void BeforeMap(Action beforeFunction); - /// - /// Execute a custom function to the source and/or destination types after member mapping - /// - /// Callback for the source/destination types - void AfterMap(Action afterFunction); - } - public interface IMappingOperationOptions : IMappingOperationOptions - { - /// - /// Execute a custom function to the source and/or destination types before member mapping - /// - /// Callback for the source/destination types - void BeforeMap(Action beforeFunction); + /// + /// Execute a custom function to the source and/or destination types after member mapping + /// + /// Callback for the source/destination types + void AfterMap(Action afterFunction); +} +public interface IMappingOperationOptions : IMappingOperationOptions +{ + /// + /// Execute a custom function to the source and/or destination types before member mapping + /// + /// Callback for the source/destination types + void BeforeMap(Action beforeFunction); - /// - /// Execute a custom function to the source and/or destination types after member mapping - /// - /// Callback for the source/destination types - void AfterMap(Action afterFunction); - } - public class MappingOperationOptions : IMappingOperationOptions + /// + /// Execute a custom function to the source and/or destination types after member mapping + /// + /// Callback for the source/destination types + void AfterMap(Action afterFunction); +} +public class MappingOperationOptions : IMappingOperationOptions +{ + private StringDictionary _items; + public MappingOperationOptions(Func serviceCtor) => ServiceCtor = serviceCtor; + public Func ServiceCtor { get; private set; } + public IDictionary Items => _items ??= new StringDictionary(); + public Action BeforeMapAction { get; protected set; } + public Action AfterMapAction { get; protected set; } + public void BeforeMap(Action beforeFunction) => BeforeMapAction = beforeFunction; + public void AfterMap(Action afterFunction) => AfterMapAction = afterFunction; + public void ConstructServicesUsing(Func constructor) { - private StringDictionary _items; - public MappingOperationOptions(Func serviceCtor) => ServiceCtor = serviceCtor; - public Func ServiceCtor { get; private set; } - public IDictionary Items => _items ??= new StringDictionary(); - public Action BeforeMapAction { get; protected set; } - public Action AfterMapAction { get; protected set; } - public void BeforeMap(Action beforeFunction) => BeforeMapAction = beforeFunction; - public void AfterMap(Action afterFunction) => AfterMapAction = afterFunction; - public void ConstructServicesUsing(Func constructor) - { - var ctor = ServiceCtor; - ServiceCtor = t => constructor(t) ?? ctor(t); - } - void IMappingOperationOptions.BeforeMap(Action beforeFunction) => BeforeMapAction = (s, d) => beforeFunction(s, d); - void IMappingOperationOptions.AfterMap(Action afterFunction) => AfterMapAction = (s, d) => afterFunction(s, d); + var ctor = ServiceCtor; + ServiceCtor = t => constructor(t) ?? ctor(t); } + void IMappingOperationOptions.BeforeMap(Action beforeFunction) => BeforeMapAction = (s, d) => beforeFunction(s, d); + void IMappingOperationOptions.AfterMap(Action afterFunction) => AfterMapAction = (s, d) => afterFunction(s, d); } \ No newline at end of file diff --git a/src/AutoMapper/Configuration/IMemberConfigurationExpression.cs b/src/AutoMapper/Configuration/IMemberConfigurationExpression.cs index bdf38d7729..6a0951ec70 100644 --- a/src/AutoMapper/Configuration/IMemberConfigurationExpression.cs +++ b/src/AutoMapper/Configuration/IMemberConfigurationExpression.cs @@ -2,350 +2,349 @@ using System.Linq.Expressions; using System.Reflection; -namespace AutoMapper +namespace AutoMapper; + +/// +/// Member configuration options +/// +/// Source type for this member +/// Type for this member +/// Destination type for this map +public interface IMemberConfigurationExpression : IProjectionMemberConfiguration { /// - /// Member configuration options - /// - /// Source type for this member - /// Type for this member - /// Destination type for this map - public interface IMemberConfigurationExpression : IProjectionMemberConfiguration - { - /// - /// Do not precompute the execution plan for this member, just map it at runtime. - /// Simplifies the execution plan by not inlining. - /// - void MapAtRuntime(); - /// - /// Map destination member using a custom value resolver - /// - /// Not used for LINQ projection (ProjectTo) - /// Value resolver type - void MapFrom() where TValueResolver : IValueResolver; - /// - /// Map destination member using a custom member value resolver supplied with a source member - /// - /// Not used for LINQ projection (ProjectTo) - /// Value resolver type - /// Source member to supply - void MapFrom(Expression> sourceMember) - where TValueResolver : IMemberValueResolver; - /// - /// Map destination member using a custom member value resolver supplied from a source member name - /// - /// Not used for LINQ projection (ProjectTo) - /// Value resolver type - /// Source member to supply - /// Source member name - void MapFrom(string sourceMemberName) - where TValueResolver : IMemberValueResolver; - /// - /// Map destination member using a custom value resolver instance - /// - /// Not used for LINQ projection (ProjectTo) - /// Value resolver instance to use - void MapFrom(IValueResolver valueResolver); - /// - /// Map destination member using a custom value resolver instance - /// - /// Not used for LINQ projection (ProjectTo) - /// Value resolver instance to use - /// Source member to supply to value resolver - void MapFrom(IMemberValueResolver valueResolver, Expression> sourceMember); - /// - /// Map destination member using a custom function. Access both the source and destination object. - /// - /// Not used for LINQ projection (ProjectTo) - /// Function to map to destination member - void MapFrom(Func mappingFunction); - /// - /// Map destination member using a custom function. Access the source, destination object, and destination member. - /// - /// Not used for LINQ projection (ProjectTo) - /// Function to map to destination member - void MapFrom(Func mappingFunction); - /// - /// Map destination member using a custom function. Access the source, destination object, destination member, and context. - /// - /// Not used for LINQ projection (ProjectTo) - /// Function to map to destination member - void MapFrom(Func mappingFunction); - /// - /// Specify the source member(s) to map from. - /// - /// Property name referencing the source member to map against. Or a dot separated member path. - void MapFrom(string sourceMembersPath); - /// - /// Supply a custom mapping order instead of what the .NET runtime returns - /// - /// Mapping order value - void SetMappingOrder(int mappingOrder); - /// - /// Reset UseDestinationValue. - /// - void DoNotUseDestinationValue(); - /// - /// Use the destination value instead of mapping from the source value or creating a new instance - /// - void UseDestinationValue(); - /// - /// Conditionally map this member against the source, destination, source and destination members - /// - /// Condition to evaluate using the source object - void Condition(Func condition); - /// - /// Conditionally map this member - /// - /// Condition to evaluate using the source object - void Condition(Func condition); - /// - /// Conditionally map this member - /// - /// Condition to evaluate using the source object - void Condition(Func condition); - /// - /// Conditionally map this member - /// - /// Condition to evaluate using the source object - void Condition(Func condition); - /// - /// Conditionally map this member - /// - /// Condition to evaluate using the source object - void Condition(Func condition); - /// - /// Conditionally map this member, evaluated before accessing the source value - /// - /// Condition to evaluate using the source object - void PreCondition(Func condition); - /// - /// Conditionally map this member, evaluated before accessing the source value - /// - /// Condition to evaluate using the current resolution context - void PreCondition(Func condition); - /// - /// Conditionally map this member, evaluated before accessing the source value - /// - /// Condition to evaluate using the source object and the current resolution context - void PreCondition(Func condition); - /// - /// Conditionally map this member, evaluated before accessing the source value - /// - /// Condition to evaluate using the source object, the destination object, and the current resolution context - void PreCondition(Func condition); - /// - /// The destination member being configured. - /// - MemberInfo DestinationMember { get; } - /// - /// Specify a value converter to convert from the matching source member to the destination member - /// - /// - /// Value converters are similar to type converters, but scoped to a single member. Value resolvers receive the enclosed source/destination objects as parameters. - /// Value converters do not. This makes it possible to reuse value converters across multiple members and multiple maps. - /// - /// Value converter type - /// Source member type - void ConvertUsing() where TValueConverter : IValueConverter; - /// - /// Specify a value converter to convert from the specified source member to the destination member - /// - /// - /// Value converters are similar to type converters, but scoped to a single member. Value resolvers receive the enclosed source/destination objects as parameters. - /// Value converters do not. This makes it possible to reuse value converters across multiple members and multiple maps. - /// - /// Value converter type - /// Source member type - /// Source member to supply to the value converter - void ConvertUsing(Expression> sourceMember) where TValueConverter : IValueConverter; - /// - /// Specify a value converter to convert from the specified source member name to the destination member - /// - /// - /// Value converters are similar to type converters, but scoped to a single member. Value resolvers receive the enclosed source/destination objects as parameters. - /// Value converters do not. This makes it possible to reuse value converters across multiple members and multiple maps. - /// - /// Value converter type - /// Source member type - /// Source member name to supply to the value converter - void ConvertUsing(string sourceMemberName) where TValueConverter : IValueConverter; - /// - /// Specify a value converter instance to convert from the matching source member to the destination member - /// - /// - /// Value converters are similar to type converters, but scoped to a single member. Value resolvers receive the enclosed source/destination objects as parameters. - /// Value converters do not. This makes it possible to reuse value converters across multiple members and multiple maps. - /// - /// Source member type - /// Value converter instance - void ConvertUsing(IValueConverter valueConverter); - /// - /// Specify a value converter instance from the specified source member to the destination member - /// - /// - /// Value converters are similar to type converters, but scoped to a single member. Value resolvers receive the enclosed source/destination objects as parameters. - /// Value converters do not. This makes it possible to reuse value converters across multiple members and multiple maps. - /// - /// Source member type - /// Value converter instance - /// Source member to supply to the value converter - void ConvertUsing(IValueConverter valueConverter, Expression> sourceMember); - /// - /// Specify a value converter instance to convert from the specified source member name to the destination member - /// - /// - /// Value converters are similar to type converters, but scoped to a single member. Value resolvers receive the enclosed source/destination objects as parameters. - /// Value converters do not. This makes it possible to reuse value converters across multiple members and multiple maps. - /// - /// Source member type - /// Value converter instance - /// Source member name to supply to the value converter - void ConvertUsing(IValueConverter valueConverter, string sourceMemberName); - } - /// - /// Configuration options for an individual member - /// - public interface IMemberConfigurationExpression : IMemberConfigurationExpression - { - /// - /// Map destination member using a custom value resolver. Used when the value resolver is not known at compile-time - /// - /// Not used for LINQ projection (ProjectTo) - /// Value resolver type - void MapFrom(Type valueResolverType); - /// - /// Map destination member using a custom value resolver. Used when the value resolver is not known at compile-time - /// - /// Not used for LINQ projection (ProjectTo) - /// Value resolver type - /// Member to supply to value resolver - void MapFrom(Type valueResolverType, string sourceMemberName); - /// - /// Map destination member using a custom value resolver instance - /// - /// Not used for LINQ projection (ProjectTo) - /// Value resolver instance to use - /// Source member to supply to value resolver - void MapFrom(IMemberValueResolver valueResolver, string sourceMemberName); - /// - /// Specify a value converter type to convert from the matching source member to the destination member - /// - /// - /// Value converters are similar to type converters, but scoped to a single member. Value resolvers receive the enclosed source/destination objects as parameters. - /// Value converters do not. This makes it possible to reuse value converters across multiple members and multiple maps. - /// - /// Value converter type - void ConvertUsing(Type valueConverterType); - /// - /// Specify a value converter type to convert from the specified source member name to the destination member - /// - /// - /// Value converters are similar to type converters, but scoped to a single member. Value resolvers receive the enclosed source/destination objects as parameters. - /// Value converters do not. This makes it possible to reuse value converters across multiple members and multiple maps. - /// - /// Value converter type - /// Source member name to supply to the value converter - void ConvertUsing(Type valueConverterType, string sourceMemberName); - /// - /// Specify a value converter instance to convert from the specified source member name to the destination member - /// - /// - /// Value converters are similar to type converters, but scoped to a single member. Value resolvers receive the enclosed source/destination objects as parameters. - /// Value converters do not. This makes it possible to reuse value converters across multiple members and multiple maps. - /// - /// Source member type - /// Destination member type - /// Value converter instance - /// Source member name to supply to the value converter - void ConvertUsing(IValueConverter valueConverter, string sourceMemberName); - } - /// - /// Member configuration options - /// - /// Source type for this member - /// Type for this member - /// Destination type for this map - public interface IProjectionMemberConfiguration - { - /// - /// Substitute a custom value when the source member resolves as null - /// - /// Value to use - void NullSubstitute(object nullSubstitute); - /// - /// Map destination member using a custom expression. Used in LINQ projection (ProjectTo). - /// - /// Member type of the source member to use - /// Map expression - void MapFrom(Expression> mapExpression); - /// - /// Ignore this member for configuration validation and skip during mapping - /// - void Ignore(); - /// - /// Allow this member to be null. Overrides AllowNullDestinationValues/AllowNullCollection. - /// - void AllowNull(); - /// - /// Don't allow this member to be null. Overrides AllowNullDestinationValues/AllowNullCollection. - /// - void DoNotAllowNull(); - /// - /// Ignore this member for LINQ projections unless explicitly expanded during projection - /// - void ExplicitExpansion(); - /// - /// Apply a transformation function after any resolved destination member value with the given type - /// - /// Transformation expression - void AddTransform(Expression> transformer); - } - /// - /// Converts a source member value to a destination member value + /// Do not precompute the execution plan for this member, just map it at runtime. + /// Simplifies the execution plan by not inlining. + /// + void MapAtRuntime(); + /// + /// Map destination member using a custom value resolver + /// + /// Not used for LINQ projection (ProjectTo) + /// Value resolver type + void MapFrom() where TValueResolver : IValueResolver; + /// + /// Map destination member using a custom member value resolver supplied with a source member + /// + /// Not used for LINQ projection (ProjectTo) + /// Value resolver type + /// Source member to supply + void MapFrom(Expression> sourceMember) + where TValueResolver : IMemberValueResolver; + /// + /// Map destination member using a custom member value resolver supplied from a source member name + /// + /// Not used for LINQ projection (ProjectTo) + /// Value resolver type + /// Source member to supply + /// Source member name + void MapFrom(string sourceMemberName) + where TValueResolver : IMemberValueResolver; + /// + /// Map destination member using a custom value resolver instance + /// + /// Not used for LINQ projection (ProjectTo) + /// Value resolver instance to use + void MapFrom(IValueResolver valueResolver); + /// + /// Map destination member using a custom value resolver instance + /// + /// Not used for LINQ projection (ProjectTo) + /// Value resolver instance to use + /// Source member to supply to value resolver + void MapFrom(IMemberValueResolver valueResolver, Expression> sourceMember); + /// + /// Map destination member using a custom function. Access both the source and destination object. + /// + /// Not used for LINQ projection (ProjectTo) + /// Function to map to destination member + void MapFrom(Func mappingFunction); + /// + /// Map destination member using a custom function. Access the source, destination object, and destination member. + /// + /// Not used for LINQ projection (ProjectTo) + /// Function to map to destination member + void MapFrom(Func mappingFunction); + /// + /// Map destination member using a custom function. Access the source, destination object, destination member, and context. + /// + /// Not used for LINQ projection (ProjectTo) + /// Function to map to destination member + void MapFrom(Func mappingFunction); + /// + /// Specify the source member(s) to map from. + /// + /// Property name referencing the source member to map against. Or a dot separated member path. + void MapFrom(string sourceMembersPath); + /// + /// Supply a custom mapping order instead of what the .NET runtime returns + /// + /// Mapping order value + void SetMappingOrder(int mappingOrder); + /// + /// Reset UseDestinationValue. + /// + void DoNotUseDestinationValue(); + /// + /// Use the destination value instead of mapping from the source value or creating a new instance + /// + void UseDestinationValue(); + /// + /// Conditionally map this member against the source, destination, source and destination members + /// + /// Condition to evaluate using the source object + void Condition(Func condition); + /// + /// Conditionally map this member + /// + /// Condition to evaluate using the source object + void Condition(Func condition); + /// + /// Conditionally map this member + /// + /// Condition to evaluate using the source object + void Condition(Func condition); + /// + /// Conditionally map this member + /// + /// Condition to evaluate using the source object + void Condition(Func condition); + /// + /// Conditionally map this member + /// + /// Condition to evaluate using the source object + void Condition(Func condition); + /// + /// Conditionally map this member, evaluated before accessing the source value + /// + /// Condition to evaluate using the source object + void PreCondition(Func condition); + /// + /// Conditionally map this member, evaluated before accessing the source value + /// + /// Condition to evaluate using the current resolution context + void PreCondition(Func condition); + /// + /// Conditionally map this member, evaluated before accessing the source value + /// + /// Condition to evaluate using the source object and the current resolution context + void PreCondition(Func condition); + /// + /// Conditionally map this member, evaluated before accessing the source value + /// + /// Condition to evaluate using the source object, the destination object, and the current resolution context + void PreCondition(Func condition); + /// + /// The destination member being configured. + /// + MemberInfo DestinationMember { get; } + /// + /// Specify a value converter to convert from the matching source member to the destination member + /// + /// + /// Value converters are similar to type converters, but scoped to a single member. Value resolvers receive the enclosed source/destination objects as parameters. + /// Value converters do not. This makes it possible to reuse value converters across multiple members and multiple maps. + /// + /// Value converter type + /// Source member type + void ConvertUsing() where TValueConverter : IValueConverter; + /// + /// Specify a value converter to convert from the specified source member to the destination member /// + /// + /// Value converters are similar to type converters, but scoped to a single member. Value resolvers receive the enclosed source/destination objects as parameters. + /// Value converters do not. This makes it possible to reuse value converters across multiple members and multiple maps. + /// + /// Value converter type + /// Source member type + /// Source member to supply to the value converter + void ConvertUsing(Expression> sourceMember) where TValueConverter : IValueConverter; + /// + /// Specify a value converter to convert from the specified source member name to the destination member + /// + /// + /// Value converters are similar to type converters, but scoped to a single member. Value resolvers receive the enclosed source/destination objects as parameters. + /// Value converters do not. This makes it possible to reuse value converters across multiple members and multiple maps. + /// + /// Value converter type + /// Source member type + /// Source member name to supply to the value converter + void ConvertUsing(string sourceMemberName) where TValueConverter : IValueConverter; + /// + /// Specify a value converter instance to convert from the matching source member to the destination member + /// + /// + /// Value converters are similar to type converters, but scoped to a single member. Value resolvers receive the enclosed source/destination objects as parameters. + /// Value converters do not. This makes it possible to reuse value converters across multiple members and multiple maps. + /// + /// Source member type + /// Value converter instance + void ConvertUsing(IValueConverter valueConverter); + /// + /// Specify a value converter instance from the specified source member to the destination member + /// + /// + /// Value converters are similar to type converters, but scoped to a single member. Value resolvers receive the enclosed source/destination objects as parameters. + /// Value converters do not. This makes it possible to reuse value converters across multiple members and multiple maps. + /// + /// Source member type + /// Value converter instance + /// Source member to supply to the value converter + void ConvertUsing(IValueConverter valueConverter, Expression> sourceMember); + /// + /// Specify a value converter instance to convert from the specified source member name to the destination member + /// + /// + /// Value converters are similar to type converters, but scoped to a single member. Value resolvers receive the enclosed source/destination objects as parameters. + /// Value converters do not. This makes it possible to reuse value converters across multiple members and multiple maps. + /// + /// Source member type + /// Value converter instance + /// Source member name to supply to the value converter + void ConvertUsing(IValueConverter valueConverter, string sourceMemberName); +} +/// +/// Configuration options for an individual member +/// +public interface IMemberConfigurationExpression : IMemberConfigurationExpression +{ + /// + /// Map destination member using a custom value resolver. Used when the value resolver is not known at compile-time + /// + /// Not used for LINQ projection (ProjectTo) + /// Value resolver type + void MapFrom(Type valueResolverType); + /// + /// Map destination member using a custom value resolver. Used when the value resolver is not known at compile-time + /// + /// Not used for LINQ projection (ProjectTo) + /// Value resolver type + /// Member to supply to value resolver + void MapFrom(Type valueResolverType, string sourceMemberName); + /// + /// Map destination member using a custom value resolver instance + /// + /// Not used for LINQ projection (ProjectTo) + /// Value resolver instance to use + /// Source member to supply to value resolver + void MapFrom(IMemberValueResolver valueResolver, string sourceMemberName); + /// + /// Specify a value converter type to convert from the matching source member to the destination member + /// + /// + /// Value converters are similar to type converters, but scoped to a single member. Value resolvers receive the enclosed source/destination objects as parameters. + /// Value converters do not. This makes it possible to reuse value converters across multiple members and multiple maps. + /// + /// Value converter type + void ConvertUsing(Type valueConverterType); + /// + /// Specify a value converter type to convert from the specified source member name to the destination member + /// + /// + /// Value converters are similar to type converters, but scoped to a single member. Value resolvers receive the enclosed source/destination objects as parameters. + /// Value converters do not. This makes it possible to reuse value converters across multiple members and multiple maps. + /// + /// Value converter type + /// Source member name to supply to the value converter + void ConvertUsing(Type valueConverterType, string sourceMemberName); + /// + /// Specify a value converter instance to convert from the specified source member name to the destination member + /// + /// + /// Value converters are similar to type converters, but scoped to a single member. Value resolvers receive the enclosed source/destination objects as parameters. + /// Value converters do not. This makes it possible to reuse value converters across multiple members and multiple maps. + /// /// Source member type /// Destination member type - public interface IValueConverter - { - /// - /// Perform conversion from source member value to destination member value - /// - /// Source member object - /// Resolution context - /// Destination member value - TDestinationMember Convert(TSourceMember sourceMember, ResolutionContext context); - } - /// - /// Extension point to provide custom resolution for a destination value - /// - public interface IValueResolver - { - /// - /// Implementors use source object to provide a destination object. - /// - /// Source object - /// Destination object, if exists - /// Destination member - /// The context of the mapping - /// Result, typically build from the source resolution result - TDestMember Resolve(TSource source, TDestination destination, TDestMember destMember, ResolutionContext context); - } + /// Value converter instance + /// Source member name to supply to the value converter + void ConvertUsing(IValueConverter valueConverter, string sourceMemberName); +} +/// +/// Member configuration options +/// +/// Source type for this member +/// Type for this member +/// Destination type for this map +public interface IProjectionMemberConfiguration +{ + /// + /// Substitute a custom value when the source member resolves as null + /// + /// Value to use + void NullSubstitute(object nullSubstitute); + /// + /// Map destination member using a custom expression. Used in LINQ projection (ProjectTo). + /// + /// Member type of the source member to use + /// Map expression + void MapFrom(Expression> mapExpression); + /// + /// Ignore this member for configuration validation and skip during mapping + /// + void Ignore(); + /// + /// Allow this member to be null. Overrides AllowNullDestinationValues/AllowNullCollection. + /// + void AllowNull(); + /// + /// Don't allow this member to be null. Overrides AllowNullDestinationValues/AllowNullCollection. + /// + void DoNotAllowNull(); + /// + /// Ignore this member for LINQ projections unless explicitly expanded during projection + /// + void ExplicitExpansion(); + /// + /// Apply a transformation function after any resolved destination member value with the given type + /// + /// Transformation expression + void AddTransform(Expression> transformer); +} +/// +/// Converts a source member value to a destination member value +/// +/// Source member type +/// Destination member type +public interface IValueConverter +{ + /// + /// Perform conversion from source member value to destination member value + /// + /// Source member object + /// Resolution context + /// Destination member value + TDestinationMember Convert(TSourceMember sourceMember, ResolutionContext context); +} +/// +/// Extension point to provide custom resolution for a destination value +/// +public interface IValueResolver +{ + /// + /// Implementors use source object to provide a destination object. + /// + /// Source object + /// Destination object, if exists + /// Destination member + /// The context of the mapping + /// Result, typically build from the source resolution result + TDestMember Resolve(TSource source, TDestination destination, TDestMember destMember, ResolutionContext context); +} +/// +/// Extension point to provide custom resolution for a destination value +/// +public interface IMemberValueResolver +{ /// - /// Extension point to provide custom resolution for a destination value - /// - public interface IMemberValueResolver - { - /// - /// Implementors use source object to provide a destination object. - /// - /// Source object - /// Destination object, if exists - /// Source member - /// Destination member - /// The context of the mapping - /// Result, typically build from the source resolution result - TDestMember Resolve(TSource source, TDestination destination, TSourceMember sourceMember, TDestMember destMember, ResolutionContext context); - } + /// Implementors use source object to provide a destination object. + /// + /// Source object + /// Destination object, if exists + /// Source member + /// Destination member + /// The context of the mapping + /// Result, typically build from the source resolution result + TDestMember Resolve(TSource source, TDestination destination, TSourceMember sourceMember, TDestMember destMember, ResolutionContext context); } \ No newline at end of file diff --git a/src/AutoMapper/Configuration/IMemberConfigurationProvider.cs b/src/AutoMapper/Configuration/IMemberConfigurationProvider.cs index 962bf1ec9c..b9fa328a59 100644 --- a/src/AutoMapper/Configuration/IMemberConfigurationProvider.cs +++ b/src/AutoMapper/Configuration/IMemberConfigurationProvider.cs @@ -1,7 +1,6 @@ -namespace AutoMapper.Configuration +namespace AutoMapper.Configuration; + +public interface IMemberConfigurationProvider { - public interface IMemberConfigurationProvider - { - void ApplyConfiguration(IMemberConfigurationExpression memberConfigurationExpression); - } + void ApplyConfiguration(IMemberConfigurationExpression memberConfigurationExpression); } \ No newline at end of file diff --git a/src/AutoMapper/Configuration/INamingConvention.cs b/src/AutoMapper/Configuration/INamingConvention.cs index ba8e1e4de4..c17894d7cd 100644 --- a/src/AutoMapper/Configuration/INamingConvention.cs +++ b/src/AutoMapper/Configuration/INamingConvention.cs @@ -1,50 +1,49 @@ using System; using System.Collections.Generic; -namespace AutoMapper +namespace AutoMapper; + +/// +/// Defines a naming convention strategy +/// +public interface INamingConvention { - /// - /// Defines a naming convention strategy - /// - public interface INamingConvention - { - string[] Split(string input); - string SeparatorCharacter { get; } - } - public sealed class ExactMatchNamingConvention : INamingConvention - { - public static readonly ExactMatchNamingConvention Instance = new(); - public string[] Split(string _) => Array.Empty(); - public string SeparatorCharacter => null; - } - public sealed class PascalCaseNamingConvention : INamingConvention + string[] Split(string input); + string SeparatorCharacter { get; } +} +public sealed class ExactMatchNamingConvention : INamingConvention +{ + public static readonly ExactMatchNamingConvention Instance = new(); + public string[] Split(string _) => Array.Empty(); + public string SeparatorCharacter => null; +} +public sealed class PascalCaseNamingConvention : INamingConvention +{ + public static readonly PascalCaseNamingConvention Instance = new(); + public string SeparatorCharacter => ""; + public string[] Split(string input) { - public static readonly PascalCaseNamingConvention Instance = new(); - public string SeparatorCharacter => ""; - public string[] Split(string input) + List result = null; + int lower = 0; + for(int index = 1; index < input.Length; index++) { - List result = null; - int lower = 0; - for(int index = 1; index < input.Length; index++) + if (char.IsUpper(input[index])) { - if (char.IsUpper(input[index])) - { - result ??= new(); - result.Add(input[lower..index]); - lower = index; - } + result ??= new(); + result.Add(input[lower..index]); + lower = index; } - if (result == null) - { - return Array.Empty(); - } - result.Add(input[lower..]); - return result.ToArray(); } + if (result == null) + { + return Array.Empty(); + } + result.Add(input[lower..]); + return result.ToArray(); } - public sealed class LowerUnderscoreNamingConvention : INamingConvention - { - public static readonly LowerUnderscoreNamingConvention Instance = new(); - public string SeparatorCharacter => "_"; - public string[] Split(string input) => input.Split('_', StringSplitOptions.RemoveEmptyEntries); - } +} +public sealed class LowerUnderscoreNamingConvention : INamingConvention +{ + public static readonly LowerUnderscoreNamingConvention Instance = new(); + public string SeparatorCharacter => "_"; + public string[] Split(string input) => input.Split('_', StringSplitOptions.RemoveEmptyEntries); } \ No newline at end of file diff --git a/src/AutoMapper/Configuration/IProfileExpression.cs b/src/AutoMapper/Configuration/IProfileExpression.cs index 3121f945a8..185b967551 100644 --- a/src/AutoMapper/Configuration/IProfileExpression.cs +++ b/src/AutoMapper/Configuration/IProfileExpression.cs @@ -1,171 +1,170 @@ using System; using System.Collections.Generic; using System.Reflection; -namespace AutoMapper +namespace AutoMapper; + +/// +/// Configuration for profile-specific maps +/// +public interface IProfileExpression { /// - /// Configuration for profile-specific maps - /// - public interface IProfileExpression - { - /// - /// Disable constructor mapping. Use this if you don't intend to have AutoMapper try to map to constructors - /// - void DisableConstructorMapping(); - - /// - /// Creates a mapping configuration from the type to the type - /// - /// Source type - /// Destination type - /// Mapping expression for more configuration options - IMappingExpression CreateMap(); - - /// - /// Creates a mapping configuration from the type to the type. - /// Specify the member list to validate against during configuration validation. - /// - /// Source type - /// Destination type - /// Member list to validate - /// Mapping expression for more configuration options - IMappingExpression CreateMap(MemberList memberList); - - /// - /// Creates a projection configuration from the type to the type - /// - /// Source type - /// Destination type - /// Mapping expression for more configuration options - IProjectionExpression CreateProjection(); - - /// - /// Creates a projection configuration from the type to the type. - /// Specify the member list to validate against during configuration validation. - /// - /// Source type - /// Destination type - /// Member list to validate - /// Mapping expression for more configuration options - IProjectionExpression CreateProjection(MemberList memberList); - - /// - /// Create a mapping configuration from the source type to the destination type. - /// Use this method when the source and destination type are known at runtime and not compile time. - /// - /// Source type - /// Destination type - /// Mapping expression for more configuration options - IMappingExpression CreateMap(Type sourceType, Type destinationType); - - /// - /// Creates a mapping configuration from the source type to the destination type. - /// Specify the member list to validate against during configuration validation. - /// - /// Source type - /// Destination type - /// Member list to validate - /// Mapping expression for more configuration options - IMappingExpression CreateMap(Type sourceType, Type destinationType, MemberList memberList); - - /// - /// Clear the list of recognized prefixes. - /// - void ClearPrefixes(); - - /// - /// Recognize a list of prefixes to be removed from source member names when matching - /// - /// List of prefixes - void RecognizePrefixes(params string[] prefixes); - - /// - /// Recognize a list of postfixes to be removed from source member names when matching - /// - /// List of postfixes - void RecognizePostfixes(params string[] postfixes); - - /// - /// Provide a new value for a part of a members name - /// - /// Original member value - /// New member value - void ReplaceMemberName(string original, string newValue); - - /// - /// Recognize a list of prefixes to be removed from destination member names when matching - /// - /// List of prefixes - void RecognizeDestinationPrefixes(params string[] prefixes); - - /// - /// Recognize a list of postfixes to be removed from destination member names when matching - /// - /// List of postfixes - void RecognizeDestinationPostfixes(params string[] postfixes); - - /// - /// Add a property name to globally ignore. Matches against the beginning of the property names. - /// - /// Property name to match against - void AddGlobalIgnore(string propertyNameStartingWith); - - /// - /// Allow null destination values. If false, destination objects will be created for deep object graphs. Default true. - /// - bool? AllowNullDestinationValues { get; set; } - - /// - /// Allow null destination collections. If true, null source collections result in null destination collections. Default false. - /// - bool? AllowNullCollections { get; set; } - - /// - /// Naming convention for source members - /// - INamingConvention SourceMemberNamingConvention { get; set; } - - /// - /// Naming convention for destination members - /// - INamingConvention DestinationMemberNamingConvention { get; set; } - - Func ShouldMapProperty { get; set; } - Func ShouldMapField { get; set; } - Func ShouldMapMethod { get; set; } - Func ShouldUseConstructor { get; set; } - - string ProfileName { get; } - - /// - /// Include extension methods against source members for matching destination members to. Default source extension methods from - /// - /// Static type that contains extension methods - void IncludeSourceExtensionMethods(Type type); - - /// - /// Value transformers. Modify the list directly or use - /// - List ValueTransformers { get; } - } - /// - /// Member list to check for configuration validation - /// - public enum MemberList - { - /// - /// Check that all destination members are mapped - /// - Destination = 0, - - /// - /// Check that all source members are mapped - /// - Source = 1, - - /// - /// Check neither source nor destination members, skipping validation - /// - None = 2 - } + /// Disable constructor mapping. Use this if you don't intend to have AutoMapper try to map to constructors + /// + void DisableConstructorMapping(); + + /// + /// Creates a mapping configuration from the type to the type + /// + /// Source type + /// Destination type + /// Mapping expression for more configuration options + IMappingExpression CreateMap(); + + /// + /// Creates a mapping configuration from the type to the type. + /// Specify the member list to validate against during configuration validation. + /// + /// Source type + /// Destination type + /// Member list to validate + /// Mapping expression for more configuration options + IMappingExpression CreateMap(MemberList memberList); + + /// + /// Creates a projection configuration from the type to the type + /// + /// Source type + /// Destination type + /// Mapping expression for more configuration options + IProjectionExpression CreateProjection(); + + /// + /// Creates a projection configuration from the type to the type. + /// Specify the member list to validate against during configuration validation. + /// + /// Source type + /// Destination type + /// Member list to validate + /// Mapping expression for more configuration options + IProjectionExpression CreateProjection(MemberList memberList); + + /// + /// Create a mapping configuration from the source type to the destination type. + /// Use this method when the source and destination type are known at runtime and not compile time. + /// + /// Source type + /// Destination type + /// Mapping expression for more configuration options + IMappingExpression CreateMap(Type sourceType, Type destinationType); + + /// + /// Creates a mapping configuration from the source type to the destination type. + /// Specify the member list to validate against during configuration validation. + /// + /// Source type + /// Destination type + /// Member list to validate + /// Mapping expression for more configuration options + IMappingExpression CreateMap(Type sourceType, Type destinationType, MemberList memberList); + + /// + /// Clear the list of recognized prefixes. + /// + void ClearPrefixes(); + + /// + /// Recognize a list of prefixes to be removed from source member names when matching + /// + /// List of prefixes + void RecognizePrefixes(params string[] prefixes); + + /// + /// Recognize a list of postfixes to be removed from source member names when matching + /// + /// List of postfixes + void RecognizePostfixes(params string[] postfixes); + + /// + /// Provide a new value for a part of a members name + /// + /// Original member value + /// New member value + void ReplaceMemberName(string original, string newValue); + + /// + /// Recognize a list of prefixes to be removed from destination member names when matching + /// + /// List of prefixes + void RecognizeDestinationPrefixes(params string[] prefixes); + + /// + /// Recognize a list of postfixes to be removed from destination member names when matching + /// + /// List of postfixes + void RecognizeDestinationPostfixes(params string[] postfixes); + + /// + /// Add a property name to globally ignore. Matches against the beginning of the property names. + /// + /// Property name to match against + void AddGlobalIgnore(string propertyNameStartingWith); + + /// + /// Allow null destination values. If false, destination objects will be created for deep object graphs. Default true. + /// + bool? AllowNullDestinationValues { get; set; } + + /// + /// Allow null destination collections. If true, null source collections result in null destination collections. Default false. + /// + bool? AllowNullCollections { get; set; } + + /// + /// Naming convention for source members + /// + INamingConvention SourceMemberNamingConvention { get; set; } + + /// + /// Naming convention for destination members + /// + INamingConvention DestinationMemberNamingConvention { get; set; } + + Func ShouldMapProperty { get; set; } + Func ShouldMapField { get; set; } + Func ShouldMapMethod { get; set; } + Func ShouldUseConstructor { get; set; } + + string ProfileName { get; } + + /// + /// Include extension methods against source members for matching destination members to. Default source extension methods from + /// + /// Static type that contains extension methods + void IncludeSourceExtensionMethods(Type type); + + /// + /// Value transformers. Modify the list directly or use + /// + List ValueTransformers { get; } +} +/// +/// Member list to check for configuration validation +/// +public enum MemberList +{ + /// + /// Check that all destination members are mapped + /// + Destination = 0, + + /// + /// Check that all source members are mapped + /// + Source = 1, + + /// + /// Check neither source nor destination members, skipping validation + /// + None = 2 } \ No newline at end of file diff --git a/src/AutoMapper/Configuration/MapperConfigurationExpression.cs b/src/AutoMapper/Configuration/MapperConfigurationExpression.cs index 5cef3483f6..fbc076f1c6 100644 --- a/src/AutoMapper/Configuration/MapperConfigurationExpression.cs +++ b/src/AutoMapper/Configuration/MapperConfigurationExpression.cs @@ -7,201 +7,200 @@ using AutoMapper.Internal; using AutoMapper.Internal.Mappers; using AutoMapper.QueryableExtensions.Impl; -namespace AutoMapper +namespace AutoMapper; + +using Validator = Action; +public interface IMapperConfigurationExpression : IProfileExpression { - using Validator = Action; - public interface IMapperConfigurationExpression : IProfileExpression - { - /// - /// Add an existing profile - /// - /// Profile to add - void AddProfile(Profile profile); - - /// - /// Add an existing profile type. Profile will be instantiated and added to the configuration. - /// - /// Profile type - void AddProfile() where TProfile : Profile, new(); - - /// - /// Add an existing profile type. Profile will be instantiated and added to the configuration. - /// - /// Profile type - void AddProfile(Type profileType); - - /// - /// Add profiles contained in an IEnumerable - /// - /// IEnumerable of Profile - void AddProfiles(IEnumerable enumerableOfProfiles); - - /// - /// Add mapping definitions contained in assemblies. - /// Looks for definitions and classes decorated with - /// - /// Assemblies containing mapping definitions - void AddMaps(IEnumerable assembliesToScan); - - /// - /// Add mapping definitions contained in assemblies. - /// Looks for definitions and classes decorated with - /// - /// Assemblies containing mapping definitions - void AddMaps(params Assembly[] assembliesToScan); - - /// - /// Add mapping definitions contained in assemblies. - /// Looks for definitions and classes decorated with - /// - /// Assembly names to load and scan containing mapping definitions - void AddMaps(IEnumerable assemblyNamesToScan); - - /// - /// Add mapping definitions contained in assemblies. - /// Looks for definitions and classes decorated with - /// - /// Assembly names to load and scan containing mapping definitions - void AddMaps(params string[] assemblyNamesToScan); - - /// - /// Add mapping definitions contained in assemblies. - /// Looks for definitions and classes decorated with - /// - /// Types from assemblies containing mapping definitions - void AddMaps(IEnumerable typesFromAssembliesContainingMappingDefinitions); - - /// - /// Add mapping definitions contained in assemblies. - /// Looks for definitions and classes decorated with - /// - /// Types from assemblies containing mapping definitions - void AddMaps(params Type[] typesFromAssembliesContainingMappingDefinitions); - - /// - /// Supply a factory method callback for creating resolvers and type converters - /// - /// Factory method - void ConstructServicesUsing(Func constructor); - - /// - /// Create a named profile with the supplied configuration - /// - /// Profile name, must be unique - /// Profile configuration - void CreateProfile(string profileName, Action config); - } - public class MapperConfigurationExpression : Profile, IGlobalConfigurationExpression - { - private readonly List _profiles = new(); - private readonly List _validators = new(); - private readonly List _mappers; - private Func _serviceCtor = Activator.CreateInstance; + /// + /// Add an existing profile + /// + /// Profile to add + void AddProfile(Profile profile); + + /// + /// Add an existing profile type. Profile will be instantiated and added to the configuration. + /// + /// Profile type + void AddProfile() where TProfile : Profile, new(); + + /// + /// Add an existing profile type. Profile will be instantiated and added to the configuration. + /// + /// Profile type + void AddProfile(Type profileType); + + /// + /// Add profiles contained in an IEnumerable + /// + /// IEnumerable of Profile + void AddProfiles(IEnumerable enumerableOfProfiles); + + /// + /// Add mapping definitions contained in assemblies. + /// Looks for definitions and classes decorated with + /// + /// Assemblies containing mapping definitions + void AddMaps(IEnumerable assembliesToScan); + + /// + /// Add mapping definitions contained in assemblies. + /// Looks for definitions and classes decorated with + /// + /// Assemblies containing mapping definitions + void AddMaps(params Assembly[] assembliesToScan); + + /// + /// Add mapping definitions contained in assemblies. + /// Looks for definitions and classes decorated with + /// + /// Assembly names to load and scan containing mapping definitions + void AddMaps(IEnumerable assemblyNamesToScan); + + /// + /// Add mapping definitions contained in assemblies. + /// Looks for definitions and classes decorated with + /// + /// Assembly names to load and scan containing mapping definitions + void AddMaps(params string[] assemblyNamesToScan); + + /// + /// Add mapping definitions contained in assemblies. + /// Looks for definitions and classes decorated with + /// + /// Types from assemblies containing mapping definitions + void AddMaps(IEnumerable typesFromAssembliesContainingMappingDefinitions); + + /// + /// Add mapping definitions contained in assemblies. + /// Looks for definitions and classes decorated with + /// + /// Types from assemblies containing mapping definitions + void AddMaps(params Type[] typesFromAssembliesContainingMappingDefinitions); + + /// + /// Supply a factory method callback for creating resolvers and type converters + /// + /// Factory method + void ConstructServicesUsing(Func constructor); + + /// + /// Create a named profile with the supplied configuration + /// + /// Profile name, must be unique + /// Profile configuration + void CreateProfile(string profileName, Action config); +} +public class MapperConfigurationExpression : Profile, IGlobalConfigurationExpression +{ + private readonly List _profiles = new(); + private readonly List _validators = new(); + private readonly List _mappers; + private Func _serviceCtor = Activator.CreateInstance; - public MapperConfigurationExpression() : base() => _mappers = MapperRegistry.Mappers(); + public MapperConfigurationExpression() : base() => _mappers = MapperRegistry.Mappers(); - /// - /// Add an action to be called when validating the configuration. - /// - /// the validation callback - void IGlobalConfigurationExpression.Validator(Validator validator) => - _validators.Add(validator ?? throw new ArgumentNullException(nameof(validator))); + /// + /// Add an action to be called when validating the configuration. + /// + /// the validation callback + void IGlobalConfigurationExpression.Validator(Validator validator) => + _validators.Add(validator ?? throw new ArgumentNullException(nameof(validator))); - /// - /// Allow the same map to exist in different profiles. - /// The default is to throw an exception, true means the maps are merged. - /// - bool IGlobalConfigurationExpression.AllowAdditiveTypeMapCreation { get; set; } + /// + /// Allow the same map to exist in different profiles. + /// The default is to throw an exception, true means the maps are merged. + /// + bool IGlobalConfigurationExpression.AllowAdditiveTypeMapCreation { get; set; } - /// - /// How many levels deep should AutoMapper try to inline the execution plan for child classes. - /// See the docs for details. - /// - int IGlobalConfigurationExpression.MaxExecutionPlanDepth { get; set; } = 1; + /// + /// How many levels deep should AutoMapper try to inline the execution plan for child classes. + /// See the docs for details. + /// + int IGlobalConfigurationExpression.MaxExecutionPlanDepth { get; set; } = 1; - List IGlobalConfigurationExpression.Validators => _validators; + List IGlobalConfigurationExpression.Validators => _validators; - List IGlobalConfigurationExpression.ProjectionMappers { get; } = ProjectionBuilder.DefaultProjectionMappers(); + List IGlobalConfigurationExpression.ProjectionMappers { get; } = ProjectionBuilder.DefaultProjectionMappers(); - /// - /// How many levels deep should recursive queries be expanded. - /// Must be zero for EF6. Can be greater than zero for EF Core. - /// - int IGlobalConfigurationExpression.RecursiveQueriesMaxDepth { get; set; } + /// + /// How many levels deep should recursive queries be expanded. + /// Must be zero for EF6. Can be greater than zero for EF Core. + /// + int IGlobalConfigurationExpression.RecursiveQueriesMaxDepth { get; set; } - IReadOnlyCollection IGlobalConfigurationExpression.Profiles => _profiles; - Func IGlobalConfigurationExpression.ServiceCtor => _serviceCtor; + IReadOnlyCollection IGlobalConfigurationExpression.Profiles => _profiles; + Func IGlobalConfigurationExpression.ServiceCtor => _serviceCtor; - public void CreateProfile(string profileName, Action config) - => AddProfile(new Profile(profileName, config)); + public void CreateProfile(string profileName, Action config) + => AddProfile(new Profile(profileName, config)); - List IGlobalConfigurationExpression.Mappers => _mappers; + List IGlobalConfigurationExpression.Mappers => _mappers; - Features IGlobalConfigurationExpression.Features { get; } = new Features(); + Features IGlobalConfigurationExpression.Features { get; } = new Features(); - public void AddProfile(Profile profile) => _profiles.Add(profile); + public void AddProfile(Profile profile) => _profiles.Add(profile); - public void AddProfile() where TProfile : Profile, new() => AddProfile(new TProfile()); + public void AddProfile() where TProfile : Profile, new() => AddProfile(new TProfile()); - public void AddProfile(Type profileType) => AddProfile((Profile)Activator.CreateInstance(profileType)); + public void AddProfile(Type profileType) => AddProfile((Profile)Activator.CreateInstance(profileType)); - public void AddProfiles(IEnumerable enumerableOfProfiles) + public void AddProfiles(IEnumerable enumerableOfProfiles) + { + foreach (var profile in enumerableOfProfiles) { - foreach (var profile in enumerableOfProfiles) - { - AddProfile(profile); - } + AddProfile(profile); } + } - public void AddMaps(IEnumerable assembliesToScan) - => AddMapsCore(assembliesToScan); + public void AddMaps(IEnumerable assembliesToScan) + => AddMapsCore(assembliesToScan); - public void AddMaps(params Assembly[] assembliesToScan) - => AddMapsCore(assembliesToScan); + public void AddMaps(params Assembly[] assembliesToScan) + => AddMapsCore(assembliesToScan); - public void AddMaps(IEnumerable assemblyNamesToScan) - => AddMapsCore(assemblyNamesToScan.Select(Assembly.Load)); + public void AddMaps(IEnumerable assemblyNamesToScan) + => AddMapsCore(assemblyNamesToScan.Select(Assembly.Load)); - public void AddMaps(params string[] assemblyNamesToScan) - => AddMaps((IEnumerable)assemblyNamesToScan); + public void AddMaps(params string[] assemblyNamesToScan) + => AddMaps((IEnumerable)assemblyNamesToScan); - public void AddMaps(IEnumerable typesFromAssembliesContainingMappingDefinitions) - => AddMapsCore(typesFromAssembliesContainingMappingDefinitions.Select(t => t.GetTypeInfo().Assembly)); + public void AddMaps(IEnumerable typesFromAssembliesContainingMappingDefinitions) + => AddMapsCore(typesFromAssembliesContainingMappingDefinitions.Select(t => t.GetTypeInfo().Assembly)); - public void AddMaps(params Type[] typesFromAssembliesContainingMappingDefinitions) - => AddMaps((IEnumerable)typesFromAssembliesContainingMappingDefinitions); + public void AddMaps(params Type[] typesFromAssembliesContainingMappingDefinitions) + => AddMaps((IEnumerable)typesFromAssembliesContainingMappingDefinitions); - private void AddMapsCore(IEnumerable assembliesToScan) - { - var allTypes = assembliesToScan.Where(a => !a.IsDynamic && a != typeof(Profile).Assembly).SelectMany(a => a.DefinedTypes).ToArray(); - var autoMapAttributeProfile = new Profile(nameof(AutoMapAttribute)); + private void AddMapsCore(IEnumerable assembliesToScan) + { + var allTypes = assembliesToScan.Where(a => !a.IsDynamic && a != typeof(Profile).Assembly).SelectMany(a => a.DefinedTypes).ToArray(); + var autoMapAttributeProfile = new Profile(nameof(AutoMapAttribute)); - foreach (var type in allTypes) + foreach (var type in allTypes) + { + if (typeof(Profile).IsAssignableFrom(type) && !type.IsAbstract) { - if (typeof(Profile).IsAssignableFrom(type) && !type.IsAbstract) - { - AddProfile(type.AsType()); - } + AddProfile(type.AsType()); + } - foreach (var autoMapAttribute in type.GetCustomAttributes()) + foreach (var autoMapAttribute in type.GetCustomAttributes()) + { + var mappingExpression = (MappingExpression) autoMapAttributeProfile.CreateMap(autoMapAttribute.SourceType, type); + + foreach (var memberInfo in type.GetMembers(BindingFlags.Public | BindingFlags.Instance)) { - var mappingExpression = (MappingExpression) autoMapAttributeProfile.CreateMap(autoMapAttribute.SourceType, type); - - foreach (var memberInfo in type.GetMembers(BindingFlags.Public | BindingFlags.Instance)) + foreach (var memberConfigurationProvider in memberInfo.GetCustomAttributes().OfType()) { - foreach (var memberConfigurationProvider in memberInfo.GetCustomAttributes().OfType()) - { - mappingExpression.ForMember(memberInfo, cfg => memberConfigurationProvider.ApplyConfiguration(cfg)); - } + mappingExpression.ForMember(memberInfo, cfg => memberConfigurationProvider.ApplyConfiguration(cfg)); } - - autoMapAttribute.ApplyConfiguration(mappingExpression); } - } - AddProfile(autoMapAttributeProfile); + autoMapAttribute.ApplyConfiguration(mappingExpression); + } } - public void ConstructServicesUsing(Func constructor) => _serviceCtor = constructor; + AddProfile(autoMapAttributeProfile); } + + public void ConstructServicesUsing(Func constructor) => _serviceCtor = constructor; } \ No newline at end of file diff --git a/src/AutoMapper/Configuration/MappingExpression.cs b/src/AutoMapper/Configuration/MappingExpression.cs index c86ec898be..1ba9a1634d 100644 --- a/src/AutoMapper/Configuration/MappingExpression.cs +++ b/src/AutoMapper/Configuration/MappingExpression.cs @@ -3,198 +3,197 @@ using System.Linq.Expressions; using System.Reflection; using AutoMapper.Internal; -namespace AutoMapper.Configuration -{ - using Execution; - public class MappingExpression : MappingExpressionBase, IMappingExpression - { - public MappingExpression(TypePair types, MemberList memberList) : base(memberList, types){} - public string[] IncludedMembersNames { get; internal set; } = Array.Empty(); - public IMappingExpression ReverseMap() - { - var reversedTypes = new TypePair(DestinationType, SourceType); - var reverseMap = new MappingExpression(reversedTypes, MemberList.None) - { - IsReverseMap = true - }; - ReverseMapCore(reverseMap); - reverseMap.IncludeMembers(MapToSourceMembers().Select(m => m.DestinationMember.Name).ToArray()); - foreach (var includedMemberName in IncludedMembersNames) - { - reverseMap.ForMember(includedMemberName, m => m.MapFrom(s => s)); - } - return reverseMap; - } - public IMappingExpression IncludeMembers(params string[] memberNames) - { - IncludedMembersNames = memberNames; - foreach(var memberName in memberNames) - { - SourceType.GetFieldOrProperty(memberName); - } - TypeMapActions.Add(tm => tm.IncludedMembersNames = memberNames); - return this; - } - public void ForAllMembers(Action memberOptions) +namespace AutoMapper.Configuration; + +using Execution; +public class MappingExpression : MappingExpressionBase, IMappingExpression +{ + public MappingExpression(TypePair types, MemberList memberList) : base(memberList, types){} + public string[] IncludedMembersNames { get; internal set; } = Array.Empty(); + public IMappingExpression ReverseMap() + { + var reversedTypes = new TypePair(DestinationType, SourceType); + var reverseMap = new MappingExpression(reversedTypes, MemberList.None) { - TypeMapActions.Add(typeMap => - { - foreach (var accessor in typeMap.DestinationSetters) - { - ForMember(accessor, memberOptions); - } - }); - } - public IMappingExpression ForMember(string name, Action memberOptions) - { - var member = DestinationType.GetFieldOrProperty(name); - ForMember(member, memberOptions); - return this; - } - protected override void IgnoreDestinationMember(MemberInfo property, bool ignorePaths = true) => ForMember(property, o=>o.Ignore()); - internal MemberConfigurationExpression ForMember(MemberInfo destinationProperty, Action memberOptions) + IsReverseMap = true + }; + ReverseMapCore(reverseMap); + reverseMap.IncludeMembers(MapToSourceMembers().Select(m => m.DestinationMember.Name).ToArray()); + foreach (var includedMemberName in IncludedMembersNames) { - var expression = new MemberConfigurationExpression(destinationProperty, SourceType); - MemberConfigurations.Add(expression); - memberOptions(expression); - return expression; + reverseMap.ForMember(includedMemberName, m => m.MapFrom(s => s)); + } + return reverseMap; + } + public IMappingExpression IncludeMembers(params string[] memberNames) + { + IncludedMembersNames = memberNames; + foreach(var memberName in memberNames) + { + SourceType.GetFieldOrProperty(memberName); } - public class MemberConfigurationExpression : MemberConfigurationExpression, IMemberConfigurationExpression + TypeMapActions.Add(tm => tm.IncludedMembersNames = memberNames); + return this; + } + public void ForAllMembers(Action memberOptions) + { + TypeMapActions.Add(typeMap => { - public MemberConfigurationExpression(MemberInfo destinationMember, Type sourceType) : base(destinationMember, sourceType){} - public void MapFrom(Type valueResolverType) => MapFromCore(new(valueResolverType, valueResolverType.GetGenericInterface(typeof(IValueResolver<,,>)))); - public void MapFrom(Type valueResolverType, string sourceMemberName) => - MapFromCore(new(valueResolverType, valueResolverType.GetGenericInterface(typeof(IMemberValueResolver<,,,>))) - { - SourceMemberName = sourceMemberName - }); - public void MapFrom(IMemberValueResolver resolver, string sourceMemberName) => - MapFromCore(new(resolver, typeof(IMemberValueResolver)) - { - SourceMemberName = sourceMemberName - }); - public void ConvertUsing(Type valueConverterType) => ConvertUsingCore(valueConverterType); - public void ConvertUsing(Type valueConverterType, string sourceMemberName) => ConvertUsingCore(valueConverterType, sourceMemberName); - public void ConvertUsing(IValueConverter valueConverter, string sourceMemberName) => - base.ConvertUsingCore(new(valueConverter, typeof(IValueConverter)) - { - SourceMemberName = sourceMemberName - }); - private void ConvertUsingCore(Type valueConverterType, string sourceMemberName = null) => - base.ConvertUsingCore(new(valueConverterType, valueConverterType.GetGenericInterface(typeof(IValueConverter<,>))) - { - SourceMemberName = sourceMemberName - }); - } + foreach (var accessor in typeMap.DestinationSetters) + { + ForMember(accessor, memberOptions); + } + }); } - public class MappingExpression : MappingExpressionBase>, - IMappingExpression, IProjectionExpression + public IMappingExpression ForMember(string name, Action memberOptions) { - public MappingExpression(MemberList memberList, bool projection = false) : base(memberList) => Projection = projection; - public MappingExpression(MemberList memberList, Type sourceType, Type destinationType) : base(memberList, sourceType, destinationType) { } - public IMappingExpression ForPath(Expression> destinationMember, - Action> memberOptions) - { - if (!destinationMember.IsMemberPath(out var chain)) + var member = DestinationType.GetFieldOrProperty(name); + ForMember(member, memberOptions); + return this; + } + protected override void IgnoreDestinationMember(MemberInfo property, bool ignorePaths = true) => ForMember(property, o=>o.Ignore()); + internal MemberConfigurationExpression ForMember(MemberInfo destinationProperty, Action memberOptions) + { + var expression = new MemberConfigurationExpression(destinationProperty, SourceType); + MemberConfigurations.Add(expression); + memberOptions(expression); + return expression; + } + public class MemberConfigurationExpression : MemberConfigurationExpression, IMemberConfigurationExpression + { + public MemberConfigurationExpression(MemberInfo destinationMember, Type sourceType) : base(destinationMember, sourceType){} + public void MapFrom(Type valueResolverType) => MapFromCore(new(valueResolverType, valueResolverType.GetGenericInterface(typeof(IValueResolver<,,>)))); + public void MapFrom(Type valueResolverType, string sourceMemberName) => + MapFromCore(new(valueResolverType, valueResolverType.GetGenericInterface(typeof(IMemberValueResolver<,,,>))) { - throw new ArgumentOutOfRangeException(nameof(destinationMember), "Only member accesses are allowed. " + destinationMember); - } - var expression = new PathConfigurationExpression(destinationMember, chain); - var firstMember = expression.MemberPath.First; - var firstMemberConfig = GetDestinationMemberConfiguration(firstMember); - if(firstMemberConfig == null) + SourceMemberName = sourceMemberName + }); + public void MapFrom(IMemberValueResolver resolver, string sourceMemberName) => + MapFromCore(new(resolver, typeof(IMemberValueResolver)) { - IgnoreDestinationMember(firstMember, ignorePaths: false); - } - MemberConfigurations.Add(expression); - memberOptions(expression); - return this; - } - public IMappingExpression ForMember(Expression> destinationMember, Action> memberOptions) - { - var memberInfo = ReflectionHelper.FindProperty(destinationMember); - return ForDestinationMember(memberInfo, memberOptions); - } - private void IncludeMembersCore(LambdaExpression[] memberExpressions) => TypeMapActions.Add(tm => tm.IncludedMembers = memberExpressions); - public IMappingExpression IncludeMembers(params Expression>[] memberExpressions) - { - var memberExpressionsWithoutCastToObject = Array.ConvertAll( - memberExpressions, - e => - { - var bodyIsCastToObject = e.Body.NodeType == ExpressionType.Convert && e.Body.Type == typeof(object); - return bodyIsCastToObject ? Expression.Lambda(((UnaryExpression)e.Body).Operand, e.Parameters) : e; - }); - IncludeMembersCore(memberExpressionsWithoutCastToObject); - return this; - } - public IMappingExpression ForMember(string name, Action> memberOptions) - { - var member = DestinationType.GetFieldOrProperty(name); - return ForDestinationMember(member, memberOptions); - } - public void ForAllMembers(Action> memberOptions) - { - TypeMapActions.Add(typeMap => + SourceMemberName = sourceMemberName + }); + public void ConvertUsing(Type valueConverterType) => ConvertUsingCore(valueConverterType); + public void ConvertUsing(Type valueConverterType, string sourceMemberName) => ConvertUsingCore(valueConverterType, sourceMemberName); + public void ConvertUsing(IValueConverter valueConverter, string sourceMemberName) => + base.ConvertUsingCore(new(valueConverter, typeof(IValueConverter)) { - foreach (var accessor in typeMap.DestinationSetters) - { - ForDestinationMember(accessor, memberOptions); - } + SourceMemberName = sourceMemberName }); - } - public IMappingExpression Include() where TOtherSource : TSource where TOtherDestination : TDestination - { - IncludeCore(typeof(TOtherSource), typeof(TOtherDestination)); - return this; - } - public IMappingExpression IncludeBase() => IncludeBase(typeof(TSourceBase), typeof(TDestinationBase)); - public IMappingExpression ForSourceMember(Expression> sourceMember, Action memberOptions) + private void ConvertUsingCore(Type valueConverterType, string sourceMemberName = null) => + base.ConvertUsingCore(new(valueConverterType, valueConverterType.GetGenericInterface(typeof(IValueConverter<,>))) + { + SourceMemberName = sourceMemberName + }); + } +} +public class MappingExpression : MappingExpressionBase>, + IMappingExpression, IProjectionExpression +{ + public MappingExpression(MemberList memberList, bool projection = false) : base(memberList) => Projection = projection; + public MappingExpression(MemberList memberList, Type sourceType, Type destinationType) : base(memberList, sourceType, destinationType) { } + public IMappingExpression ForPath(Expression> destinationMember, + Action> memberOptions) + { + if (!destinationMember.IsMemberPath(out var chain)) { - var memberInfo = ReflectionHelper.FindProperty(sourceMember); - var srcConfig = new SourceMappingExpression(memberInfo); - memberOptions(srcConfig); - SourceMemberConfigurations.Add(srcConfig); - return this; + throw new ArgumentOutOfRangeException(nameof(destinationMember), "Only member accesses are allowed. " + destinationMember); } - public void As() where T : TDestination => As(typeof(T)); - public IMappingExpression AddTransform(Expression> transformer) + var expression = new PathConfigurationExpression(destinationMember, chain); + var firstMember = expression.MemberPath.First; + var firstMemberConfig = GetDestinationMemberConfiguration(firstMember); + if(firstMemberConfig == null) { - var config = new ValueTransformerConfiguration(typeof(TValue), transformer); - ValueTransformers.Add(config); - return this; + IgnoreDestinationMember(firstMember, ignorePaths: false); } - public IMappingExpression ReverseMap() - { - var reverseMap = new MappingExpression(MemberList.None, DestinationType, SourceType){ IsReverseMap = true }; - ReverseMapCore(reverseMap); - reverseMap.IncludeMembersCore(MapToSourceMembers().Select(m => m.GetDestinationExpression()).ToArray()); - return reverseMap; - } - private IMappingExpression ForDestinationMember(MemberInfo destinationProperty, Action> memberOptions) + MemberConfigurations.Add(expression); + memberOptions(expression); + return this; + } + public IMappingExpression ForMember(Expression> destinationMember, Action> memberOptions) + { + var memberInfo = ReflectionHelper.FindProperty(destinationMember); + return ForDestinationMember(memberInfo, memberOptions); + } + private void IncludeMembersCore(LambdaExpression[] memberExpressions) => TypeMapActions.Add(tm => tm.IncludedMembers = memberExpressions); + public IMappingExpression IncludeMembers(params Expression>[] memberExpressions) + { + var memberExpressionsWithoutCastToObject = Array.ConvertAll( + memberExpressions, + e => + { + var bodyIsCastToObject = e.Body.NodeType == ExpressionType.Convert && e.Body.Type == typeof(object); + return bodyIsCastToObject ? Expression.Lambda(((UnaryExpression)e.Body).Operand, e.Parameters) : e; + }); + IncludeMembersCore(memberExpressionsWithoutCastToObject); + return this; + } + public IMappingExpression ForMember(string name, Action> memberOptions) + { + var member = DestinationType.GetFieldOrProperty(name); + return ForDestinationMember(member, memberOptions); + } + public void ForAllMembers(Action> memberOptions) + { + TypeMapActions.Add(typeMap => { - var expression = new MemberConfigurationExpression(destinationProperty, SourceType); - MemberConfigurations.Add(expression); - memberOptions(expression); - return this; - } - protected override void IgnoreDestinationMember(MemberInfo property, bool ignorePaths = true) => - ForDestinationMember(property, options => options.Ignore(ignorePaths)); - IProjectionExpression IProjectionExpression.ForMember(Expression> destinationMember, - Action> memberOptions) => - (IProjectionExpression)ForMember(destinationMember, memberOptions); - IProjectionExpression IProjectionExpression>.AddTransform( - Expression> transformer) => (IProjectionExpression)AddTransform(transformer); - IProjectionExpression IProjectionExpression>.IncludeMembers( - params Expression>[] memberExpressions) => (IProjectionExpression)IncludeMembers(memberExpressions); - IProjectionExpression IProjectionExpressionBase>.MaxDepth(int depth) => - (IProjectionExpression)MaxDepth(depth); - IProjectionExpression IProjectionExpressionBase>.ValidateMemberList( - MemberList memberList) => (IProjectionExpression)ValidateMemberList(memberList); - IProjectionExpression IProjectionExpressionBase>.ConstructUsing( - Expression> ctor) => (IProjectionExpression)ConstructUsing(ctor); - IProjectionExpression IProjectionExpressionBase>.ForCtorParam( - string ctorParamName, Action> paramOptions) => - (IProjectionExpression)ForCtorParam(ctorParamName, paramOptions); + foreach (var accessor in typeMap.DestinationSetters) + { + ForDestinationMember(accessor, memberOptions); + } + }); + } + public IMappingExpression Include() where TOtherSource : TSource where TOtherDestination : TDestination + { + IncludeCore(typeof(TOtherSource), typeof(TOtherDestination)); + return this; + } + public IMappingExpression IncludeBase() => IncludeBase(typeof(TSourceBase), typeof(TDestinationBase)); + public IMappingExpression ForSourceMember(Expression> sourceMember, Action memberOptions) + { + var memberInfo = ReflectionHelper.FindProperty(sourceMember); + var srcConfig = new SourceMappingExpression(memberInfo); + memberOptions(srcConfig); + SourceMemberConfigurations.Add(srcConfig); + return this; + } + public void As() where T : TDestination => As(typeof(T)); + public IMappingExpression AddTransform(Expression> transformer) + { + var config = new ValueTransformerConfiguration(typeof(TValue), transformer); + ValueTransformers.Add(config); + return this; + } + public IMappingExpression ReverseMap() + { + var reverseMap = new MappingExpression(MemberList.None, DestinationType, SourceType){ IsReverseMap = true }; + ReverseMapCore(reverseMap); + reverseMap.IncludeMembersCore(MapToSourceMembers().Select(m => m.GetDestinationExpression()).ToArray()); + return reverseMap; + } + private IMappingExpression ForDestinationMember(MemberInfo destinationProperty, Action> memberOptions) + { + var expression = new MemberConfigurationExpression(destinationProperty, SourceType); + MemberConfigurations.Add(expression); + memberOptions(expression); + return this; } + protected override void IgnoreDestinationMember(MemberInfo property, bool ignorePaths = true) => + ForDestinationMember(property, options => options.Ignore(ignorePaths)); + IProjectionExpression IProjectionExpression.ForMember(Expression> destinationMember, + Action> memberOptions) => + (IProjectionExpression)ForMember(destinationMember, memberOptions); + IProjectionExpression IProjectionExpression>.AddTransform( + Expression> transformer) => (IProjectionExpression)AddTransform(transformer); + IProjectionExpression IProjectionExpression>.IncludeMembers( + params Expression>[] memberExpressions) => (IProjectionExpression)IncludeMembers(memberExpressions); + IProjectionExpression IProjectionExpressionBase>.MaxDepth(int depth) => + (IProjectionExpression)MaxDepth(depth); + IProjectionExpression IProjectionExpressionBase>.ValidateMemberList( + MemberList memberList) => (IProjectionExpression)ValidateMemberList(memberList); + IProjectionExpression IProjectionExpressionBase>.ConstructUsing( + Expression> ctor) => (IProjectionExpression)ConstructUsing(ctor); + IProjectionExpression IProjectionExpressionBase>.ForCtorParam( + string ctorParamName, Action> paramOptions) => + (IProjectionExpression)ForCtorParam(ctorParamName, paramOptions); } \ No newline at end of file diff --git a/src/AutoMapper/Configuration/MemberConfigurationExpression.cs b/src/AutoMapper/Configuration/MemberConfigurationExpression.cs index 3e2dba2d02..ef892baa62 100644 --- a/src/AutoMapper/Configuration/MemberConfigurationExpression.cs +++ b/src/AutoMapper/Configuration/MemberConfigurationExpression.cs @@ -4,175 +4,174 @@ using System.Linq; using System.Linq.Expressions; using System.Reflection; -namespace AutoMapper.Configuration +namespace AutoMapper.Configuration; + +using Execution; +using static AutoMapper.Execution.ExpressionBuilder; +public interface IPropertyMapConfiguration +{ + void Configure(TypeMap typeMap); + MemberInfo DestinationMember { get; } + LambdaExpression SourceExpression { get; } + LambdaExpression GetDestinationExpression(); + IPropertyMapConfiguration Reverse(); + bool Ignored => false; +} +public class MemberConfigurationExpression : IMemberConfigurationExpression, IPropertyMapConfiguration { - using Execution; - using static AutoMapper.Execution.ExpressionBuilder; - public interface IPropertyMapConfiguration - { - void Configure(TypeMap typeMap); - MemberInfo DestinationMember { get; } - LambdaExpression SourceExpression { get; } - LambdaExpression GetDestinationExpression(); - IPropertyMapConfiguration Reverse(); - bool Ignored => false; - } - public class MemberConfigurationExpression : IMemberConfigurationExpression, IPropertyMapConfiguration + private MemberInfo[] _sourceMembers; + private readonly Type _sourceType; + protected List> PropertyMapActions { get; } = new List>(); + public MemberConfigurationExpression(MemberInfo destinationMember, Type sourceType) { - private MemberInfo[] _sourceMembers; - private readonly Type _sourceType; - protected List> PropertyMapActions { get; } = new List>(); - public MemberConfigurationExpression(MemberInfo destinationMember, Type sourceType) + DestinationMember = destinationMember; + _sourceType = sourceType; + } + public MemberInfo DestinationMember { get; } + public void MapAtRuntime() => PropertyMapActions.Add(pm => pm.Inline = false); + public void NullSubstitute(object nullSubstitute) => PropertyMapActions.Add(pm => pm.NullSubstitute = nullSubstitute); + public void MapFrom() where TValueResolver : IValueResolver => + MapFromCore(new(typeof(TValueResolver), typeof(IValueResolver))); + protected void MapFromCore(ClassValueResolver config) => SetResolver(config); + protected void SetResolver(IValueResolver config) => PropertyMapActions.Add(pm => pm.Resolver = config); + public void MapFrom(Expression> sourceMember) + where TValueResolver : IMemberValueResolver => + MapFromCore(sourceMember); + public void MapFrom(string sourceMemberName) where TValueResolver : IMemberValueResolver => + MapFromCore(null, sourceMemberName); + private void MapFromCore(Expression> sourceMember, string sourceMemberName = null) where TValueResolver : IMemberValueResolver => + MapFromCore(new(typeof(TValueResolver), typeof(IMemberValueResolver)) { - DestinationMember = destinationMember; - _sourceType = sourceType; - } - public MemberInfo DestinationMember { get; } - public void MapAtRuntime() => PropertyMapActions.Add(pm => pm.Inline = false); - public void NullSubstitute(object nullSubstitute) => PropertyMapActions.Add(pm => pm.NullSubstitute = nullSubstitute); - public void MapFrom() where TValueResolver : IValueResolver => - MapFromCore(new(typeof(TValueResolver), typeof(IValueResolver))); - protected void MapFromCore(ClassValueResolver config) => SetResolver(config); - protected void SetResolver(IValueResolver config) => PropertyMapActions.Add(pm => pm.Resolver = config); - public void MapFrom(Expression> sourceMember) - where TValueResolver : IMemberValueResolver => - MapFromCore(sourceMember); - public void MapFrom(string sourceMemberName) where TValueResolver : IMemberValueResolver => - MapFromCore(null, sourceMemberName); - private void MapFromCore(Expression> sourceMember, string sourceMemberName = null) where TValueResolver : IMemberValueResolver => - MapFromCore(new(typeof(TValueResolver), typeof(IMemberValueResolver)) - { - SourceMemberName = sourceMemberName, - SourceMemberLambda = sourceMember - }); - public void MapFrom(IValueResolver valueResolver) => - MapFromCore(new(valueResolver, typeof(IValueResolver))); - public void MapFrom(IMemberValueResolver valueResolver, Expression> sourceMember) => - MapFromCore(new(valueResolver, typeof(IMemberValueResolver)) - { - SourceMemberLambda = sourceMember - }); - public void MapFrom(Func mappingFunction) => - MapFromResult((src, dest, destMember, ctxt) => mappingFunction(src, dest)); - public void MapFrom(Func mappingFunction) => - MapFromResult((src, dest, destMember, ctxt) => mappingFunction(src, dest, destMember)); - public void MapFrom(Func mappingFunction) => - MapFromResult((src, dest, destMember, ctxt) => mappingFunction(src, dest, destMember, ctxt)); - private void MapFromResult(Expression> expr) => - SetResolver(new FuncResolver(expr)); - public void MapFrom(Expression> mapExpression) => MapFromUntyped(mapExpression); - internal void MapFromUntyped(LambdaExpression sourceExpression) + SourceMemberName = sourceMemberName, + SourceMemberLambda = sourceMember + }); + public void MapFrom(IValueResolver valueResolver) => + MapFromCore(new(valueResolver, typeof(IValueResolver))); + public void MapFrom(IMemberValueResolver valueResolver, Expression> sourceMember) => + MapFromCore(new(valueResolver, typeof(IMemberValueResolver)) { - SourceExpression = sourceExpression; - PropertyMapActions.Add(pm => pm.MapFrom(sourceExpression)); - } - public void MapFrom(string sourceMembersPath) + SourceMemberLambda = sourceMember + }); + public void MapFrom(Func mappingFunction) => + MapFromResult((src, dest, destMember, ctxt) => mappingFunction(src, dest)); + public void MapFrom(Func mappingFunction) => + MapFromResult((src, dest, destMember, ctxt) => mappingFunction(src, dest, destMember)); + public void MapFrom(Func mappingFunction) => + MapFromResult((src, dest, destMember, ctxt) => mappingFunction(src, dest, destMember, ctxt)); + private void MapFromResult(Expression> expr) => + SetResolver(new FuncResolver(expr)); + public void MapFrom(Expression> mapExpression) => MapFromUntyped(mapExpression); + internal void MapFromUntyped(LambdaExpression sourceExpression) + { + SourceExpression = sourceExpression; + PropertyMapActions.Add(pm => pm.MapFrom(sourceExpression)); + } + public void MapFrom(string sourceMembersPath) + { + _sourceMembers = ReflectionHelper.GetMemberPath(_sourceType, sourceMembersPath); + PropertyMapActions.Add(pm => pm.MapFrom(sourceMembersPath, _sourceMembers)); + } + public void Condition(Func condition) => + ConditionCore((src, dest, srcMember, destMember, ctxt) => condition(src, dest, srcMember, destMember, ctxt)); + public void Condition(Func condition) => + ConditionCore((src, dest, srcMember, destMember, ctxt) => condition(src, dest, srcMember, destMember)); + public void Condition(Func condition) => + ConditionCore((src, dest, srcMember, destMember, ctxt) => condition(src, dest, srcMember)); + public void Condition(Func condition) => ConditionCore((src, dest, srcMember, destMember, ctxt) => condition(src, dest)); + public void Condition(Func condition) => ConditionCore((src, dest, srcMember, destMember, ctxt) => condition(src)); + private void ConditionCore(Expression> expr) => + PropertyMapActions.Add(pm => pm.Condition = expr); + public void PreCondition(Func condition) => PreConditionCore((src, dest, ctxt) => condition(src)); + public void PreCondition(Func condition) => PreConditionCore((src, dest, ctxt) => condition(ctxt)); + public void PreCondition(Func condition) => PreConditionCore((src, dest, ctxt) => condition(src, ctxt)); + public void PreCondition(Func condition) => PreConditionCore((src, dest, ctxt) => condition(src, dest, ctxt)); + private void PreConditionCore(Expression> expr) => + PropertyMapActions.Add(pm => pm.PreCondition = expr); + public void AddTransform(Expression> transformer) => + PropertyMapActions.Add(pm => pm.AddValueTransformation(new ValueTransformerConfiguration(pm.DestinationType, transformer))); + public void ExplicitExpansion() => PropertyMapActions.Add(pm => pm.ExplicitExpansion = true); + public void Ignore() => Ignore(ignorePaths: true); + public void Ignore(bool ignorePaths) + { + Ignored = true; + PropertyMapActions.Add(pm => + { + pm.Ignored = true; + if (ignorePaths && pm.TypeMap.PathMaps.Count > 0) + { + pm.TypeMap.IgnorePaths(DestinationMember); + } + }); + } + public void AllowNull() => SetAllowNull(true); + public void DoNotAllowNull() => SetAllowNull(false); + private void SetAllowNull(bool value) => PropertyMapActions.Add(pm => pm.AllowNull = value); + public void UseDestinationValue() => SetUseDestinationValue(true); + private void SetUseDestinationValue(bool value) => PropertyMapActions.Add(pm => pm.UseDestinationValue = value); + public void SetMappingOrder(int mappingOrder) => PropertyMapActions.Add(pm => pm.MappingOrder = mappingOrder); + public void ConvertUsing() where TValueConverter : IValueConverter => + ConvertUsingCore(); + public void ConvertUsing(Expression> sourceMember) where TValueConverter : IValueConverter => + ConvertUsingCore(sourceMember); + public void ConvertUsing(string sourceMemberName) where TValueConverter : IValueConverter => + ConvertUsingCore(null, sourceMemberName); + public void ConvertUsing(IValueConverter valueConverter) => ConvertUsingCore(valueConverter); + public void ConvertUsing(IValueConverter valueConverter, Expression> sourceMember) => + ConvertUsingCore(valueConverter, sourceMember); + public void ConvertUsing(IValueConverter valueConverter, string sourceMemberName) => + ConvertUsingCore(valueConverter, null, sourceMemberName); + private void ConvertUsingCore(Expression> sourceMember = null, string sourceMemberName = null) => + ConvertUsingCore(new(typeof(TValueConverter), typeof(IValueConverter)) { - _sourceMembers = ReflectionHelper.GetMemberPath(_sourceType, sourceMembersPath); - PropertyMapActions.Add(pm => pm.MapFrom(sourceMembersPath, _sourceMembers)); - } - public void Condition(Func condition) => - ConditionCore((src, dest, srcMember, destMember, ctxt) => condition(src, dest, srcMember, destMember, ctxt)); - public void Condition(Func condition) => - ConditionCore((src, dest, srcMember, destMember, ctxt) => condition(src, dest, srcMember, destMember)); - public void Condition(Func condition) => - ConditionCore((src, dest, srcMember, destMember, ctxt) => condition(src, dest, srcMember)); - public void Condition(Func condition) => ConditionCore((src, dest, srcMember, destMember, ctxt) => condition(src, dest)); - public void Condition(Func condition) => ConditionCore((src, dest, srcMember, destMember, ctxt) => condition(src)); - private void ConditionCore(Expression> expr) => - PropertyMapActions.Add(pm => pm.Condition = expr); - public void PreCondition(Func condition) => PreConditionCore((src, dest, ctxt) => condition(src)); - public void PreCondition(Func condition) => PreConditionCore((src, dest, ctxt) => condition(ctxt)); - public void PreCondition(Func condition) => PreConditionCore((src, dest, ctxt) => condition(src, ctxt)); - public void PreCondition(Func condition) => PreConditionCore((src, dest, ctxt) => condition(src, dest, ctxt)); - private void PreConditionCore(Expression> expr) => - PropertyMapActions.Add(pm => pm.PreCondition = expr); - public void AddTransform(Expression> transformer) => - PropertyMapActions.Add(pm => pm.AddValueTransformation(new ValueTransformerConfiguration(pm.DestinationType, transformer))); - public void ExplicitExpansion() => PropertyMapActions.Add(pm => pm.ExplicitExpansion = true); - public void Ignore() => Ignore(ignorePaths: true); - public void Ignore(bool ignorePaths) + SourceMemberLambda = sourceMember, + SourceMemberName = sourceMemberName + }); + protected void ConvertUsingCore(ValueConverter converter) => SetResolver(converter); + private void ConvertUsingCore(IValueConverter valueConverter, + Expression> sourceMember = null, string sourceMemberName = null) => + ConvertUsingCore(new(valueConverter, typeof(IValueConverter)) { - Ignored = true; - PropertyMapActions.Add(pm => - { - pm.Ignored = true; - if (ignorePaths && pm.TypeMap.PathMaps.Count > 0) - { - pm.TypeMap.IgnorePaths(DestinationMember); - } - }); + SourceMemberLambda = sourceMember, + SourceMemberName = sourceMemberName + }); + public void Configure(TypeMap typeMap) + { + var destMember = DestinationMember; + if(destMember.DeclaringType.ContainsGenericParameters) + { + destMember = typeMap.DestinationSetters.Single(m => m.Name == destMember.Name); } - public void AllowNull() => SetAllowNull(true); - public void DoNotAllowNull() => SetAllowNull(false); - private void SetAllowNull(bool value) => PropertyMapActions.Add(pm => pm.AllowNull = value); - public void UseDestinationValue() => SetUseDestinationValue(true); - private void SetUseDestinationValue(bool value) => PropertyMapActions.Add(pm => pm.UseDestinationValue = value); - public void SetMappingOrder(int mappingOrder) => PropertyMapActions.Add(pm => pm.MappingOrder = mappingOrder); - public void ConvertUsing() where TValueConverter : IValueConverter => - ConvertUsingCore(); - public void ConvertUsing(Expression> sourceMember) where TValueConverter : IValueConverter => - ConvertUsingCore(sourceMember); - public void ConvertUsing(string sourceMemberName) where TValueConverter : IValueConverter => - ConvertUsingCore(null, sourceMemberName); - public void ConvertUsing(IValueConverter valueConverter) => ConvertUsingCore(valueConverter); - public void ConvertUsing(IValueConverter valueConverter, Expression> sourceMember) => - ConvertUsingCore(valueConverter, sourceMember); - public void ConvertUsing(IValueConverter valueConverter, string sourceMemberName) => - ConvertUsingCore(valueConverter, null, sourceMemberName); - private void ConvertUsingCore(Expression> sourceMember = null, string sourceMemberName = null) => - ConvertUsingCore(new(typeof(TValueConverter), typeof(IValueConverter)) - { - SourceMemberLambda = sourceMember, - SourceMemberName = sourceMemberName - }); - protected void ConvertUsingCore(ValueConverter converter) => SetResolver(converter); - private void ConvertUsingCore(IValueConverter valueConverter, - Expression> sourceMember = null, string sourceMemberName = null) => - ConvertUsingCore(new(valueConverter, typeof(IValueConverter)) - { - SourceMemberLambda = sourceMember, - SourceMemberName = sourceMemberName - }); - public void Configure(TypeMap typeMap) + var propertyMap = typeMap.FindOrCreatePropertyMapFor(destMember, typeof(TMember) == typeof(object) ? destMember.GetMemberType() : typeof(TMember)); + Apply(propertyMap); + } + private void Apply(PropertyMap propertyMap) + { + foreach(var action in PropertyMapActions) { - var destMember = DestinationMember; - if(destMember.DeclaringType.ContainsGenericParameters) - { - destMember = typeMap.DestinationSetters.Single(m => m.Name == destMember.Name); - } - var propertyMap = typeMap.FindOrCreatePropertyMapFor(destMember, typeof(TMember) == typeof(object) ? destMember.GetMemberType() : typeof(TMember)); - Apply(propertyMap); - } - private void Apply(PropertyMap propertyMap) - { - foreach(var action in PropertyMapActions) - { - action(propertyMap); - } - } - public LambdaExpression SourceExpression { get; private set; } - public bool Ignored { get; private set; } - public LambdaExpression GetDestinationExpression() => DestinationMember.Lambda(); - public IPropertyMapConfiguration Reverse() + action(propertyMap); + } + } + public LambdaExpression SourceExpression { get; private set; } + public bool Ignored { get; private set; } + public LambdaExpression GetDestinationExpression() => DestinationMember.Lambda(); + public IPropertyMapConfiguration Reverse() + { + var destinationType = DestinationMember.DeclaringType; + if (_sourceMembers != null) { - var destinationType = DestinationMember.DeclaringType; - if (_sourceMembers != null) - { - if (_sourceMembers.Length > 1) - { - return null; - } - var reversedMemberConfiguration = new MemberConfigurationExpression(_sourceMembers[0], destinationType); - reversedMemberConfiguration.MapFrom(DestinationMember.Name); - return reversedMemberConfiguration; - } - if (destinationType.IsGenericTypeDefinition) // .ForMember("InnerSource", o => o.MapFrom(s => s)) + if (_sourceMembers.Length > 1) { return null; } - return PathConfigurationExpression.Create(SourceExpression, GetDestinationExpression()); + var reversedMemberConfiguration = new MemberConfigurationExpression(_sourceMembers[0], destinationType); + reversedMemberConfiguration.MapFrom(DestinationMember.Name); + return reversedMemberConfiguration; + } + if (destinationType.IsGenericTypeDefinition) // .ForMember("InnerSource", o => o.MapFrom(s => s)) + { + return null; } - public void DoNotUseDestinationValue() => SetUseDestinationValue(false); + return PathConfigurationExpression.Create(SourceExpression, GetDestinationExpression()); } + public void DoNotUseDestinationValue() => SetUseDestinationValue(false); } \ No newline at end of file diff --git a/src/AutoMapper/Configuration/PathConfigurationExpression.cs b/src/AutoMapper/Configuration/PathConfigurationExpression.cs index 7aea462dd3..d55d8a1af5 100644 --- a/src/AutoMapper/Configuration/PathConfigurationExpression.cs +++ b/src/AutoMapper/Configuration/PathConfigurationExpression.cs @@ -3,88 +3,87 @@ using System.Linq.Expressions; using System.Reflection; using AutoMapper.Internal; -namespace AutoMapper.Configuration +namespace AutoMapper.Configuration; + +using Execution; +/// +/// Member configuration options +/// +/// Source type for this member +/// Destination type for this map +/// Type for this member +public interface IPathConfigurationExpression { - using Execution; /// - /// Member configuration options + /// Specify the source member to map from. Can only reference a member on the type + /// Any null reference exceptions in this expression will be ignored (similar to flattening behavior) /// - /// Source type for this member - /// Destination type for this map - /// Type for this member - public interface IPathConfigurationExpression + /// Member type of the source member to use + /// Expression referencing the source member to map against + void MapFrom(Expression> sourceMember); + /// + /// Ignore this member for configuration validation and skip during mapping + /// + void Ignore(); + void Condition(Func, bool> condition); +} +public readonly record struct ConditionParameters(TSource Source, TDestination Destination, TMember SourceMember, TMember DestinationMember, ResolutionContext Context); +public class PathConfigurationExpression : IPathConfigurationExpression, IPropertyMapConfiguration +{ + private readonly LambdaExpression _destinationExpression; + private LambdaExpression _sourceExpression; + protected List> PathMapActions { get; } = new List>(); + public PathConfigurationExpression(LambdaExpression destinationExpression, Stack chain) { - /// - /// Specify the source member to map from. Can only reference a member on the type - /// Any null reference exceptions in this expression will be ignored (similar to flattening behavior) - /// - /// Member type of the source member to use - /// Expression referencing the source member to map against - void MapFrom(Expression> sourceMember); - /// - /// Ignore this member for configuration validation and skip during mapping - /// - void Ignore(); - void Condition(Func, bool> condition); + _destinationExpression = destinationExpression; + MemberPath = new MemberPath(chain); } - public readonly record struct ConditionParameters(TSource Source, TDestination Destination, TMember SourceMember, TMember DestinationMember, ResolutionContext Context); - public class PathConfigurationExpression : IPathConfigurationExpression, IPropertyMapConfiguration + public MemberPath MemberPath { get; } + public MemberInfo DestinationMember => MemberPath.Last; + public void MapFrom(Expression> sourceExpression) => MapFromUntyped(sourceExpression); + public void Ignore() => PathMapActions.Add(pm => pm.Ignored = true); + public void MapFromUntyped(LambdaExpression sourceExpression) { - private readonly LambdaExpression _destinationExpression; - private LambdaExpression _sourceExpression; - protected List> PathMapActions { get; } = new List>(); - public PathConfigurationExpression(LambdaExpression destinationExpression, Stack chain) - { - _destinationExpression = destinationExpression; - MemberPath = new MemberPath(chain); - } - public MemberPath MemberPath { get; } - public MemberInfo DestinationMember => MemberPath.Last; - public void MapFrom(Expression> sourceExpression) => MapFromUntyped(sourceExpression); - public void Ignore() => PathMapActions.Add(pm => pm.Ignored = true); - public void MapFromUntyped(LambdaExpression sourceExpression) - { - _sourceExpression = sourceExpression ?? throw new ArgumentNullException(nameof(sourceExpression), $"{nameof(sourceExpression)} may not be null when mapping {DestinationMember.Name} from {typeof(TSource)} to {typeof(TDestination)}."); - PathMapActions.Add(pm => pm.MapFrom(sourceExpression)); - } - public void Configure(TypeMap typeMap) + _sourceExpression = sourceExpression ?? throw new ArgumentNullException(nameof(sourceExpression), $"{nameof(sourceExpression)} may not be null when mapping {DestinationMember.Name} from {typeof(TSource)} to {typeof(TDestination)}."); + PathMapActions.Add(pm => pm.MapFrom(sourceExpression)); + } + public void Configure(TypeMap typeMap) + { + var pathMap = typeMap.FindOrCreatePathMapFor(_destinationExpression, MemberPath, typeMap); + Apply(pathMap); + } + private void Apply(PathMap pathMap) + { + foreach (var action in PathMapActions) { - var pathMap = typeMap.FindOrCreatePathMapFor(_destinationExpression, MemberPath, typeMap); - Apply(pathMap); + action(pathMap); } - private void Apply(PathMap pathMap) + } + internal static IPropertyMapConfiguration Create(LambdaExpression destination, LambdaExpression source) + { + if (destination == null || !destination.IsMemberPath(out var chain)) { - foreach (var action in PathMapActions) - { - action(pathMap); - } + return null; } - internal static IPropertyMapConfiguration Create(LambdaExpression destination, LambdaExpression source) + var reversed = new PathConfigurationExpression(destination, chain); + if (reversed.MemberPath.Length == 1) { - if (destination == null || !destination.IsMemberPath(out var chain)) - { - return null; - } - var reversed = new PathConfigurationExpression(destination, chain); - if (reversed.MemberPath.Length == 1) - { - var reversedMemberExpression = new MemberConfigurationExpression(reversed.DestinationMember, typeof(TSource)); - reversedMemberExpression.MapFromUntyped(source); - return reversedMemberExpression; - } - reversed.MapFromUntyped(source); - return reversed; + var reversedMemberExpression = new MemberConfigurationExpression(reversed.DestinationMember, typeof(TSource)); + reversedMemberExpression.MapFromUntyped(source); + return reversedMemberExpression; } - public LambdaExpression SourceExpression => _sourceExpression; - public LambdaExpression GetDestinationExpression() => _destinationExpression; - public IPropertyMapConfiguration Reverse() => Create(_sourceExpression, _destinationExpression); - public void Condition(Func, bool> condition) => - PathMapActions.Add(pm => - { - Expression> expr = - (src, dest, srcMember, destMember, ctxt) => - condition(new ConditionParameters(src, dest, srcMember, destMember, ctxt)); - pm.Condition = expr; - }); + reversed.MapFromUntyped(source); + return reversed; } + public LambdaExpression SourceExpression => _sourceExpression; + public LambdaExpression GetDestinationExpression() => _destinationExpression; + public IPropertyMapConfiguration Reverse() => Create(_sourceExpression, _destinationExpression); + public void Condition(Func, bool> condition) => + PathMapActions.Add(pm => + { + Expression> expr = + (src, dest, srcMember, destMember, ctxt) => + condition(new ConditionParameters(src, dest, srcMember, destMember, ctxt)); + pm.Condition = expr; + }); } \ No newline at end of file diff --git a/src/AutoMapper/Configuration/Profile.cs b/src/AutoMapper/Configuration/Profile.cs index 83bfb8aaa3..d17db3c9b0 100644 --- a/src/AutoMapper/Configuration/Profile.cs +++ b/src/AutoMapper/Configuration/Profile.cs @@ -6,189 +6,188 @@ using AutoMapper.Configuration; using AutoMapper.Configuration.Conventions; using AutoMapper.Internal; -namespace AutoMapper -{ - using static Execution.ExpressionBuilder; - public interface IProfileConfiguration - { - bool? FieldMappingEnabled { get; } - bool? MethodMappingEnabled { get; } - bool? ConstructorMappingEnabled { get; } - bool? AllowNullDestinationValues { get; } - bool? AllowNullCollections { get; } - bool? EnableNullPropagationForQueryMapping { get; } - IReadOnlyCollection> AllTypeMapActions { get; } - IReadOnlyCollection> AllPropertyMapActions { get; } +namespace AutoMapper; - /// - /// Source extension methods included for search - /// - IReadOnlyCollection SourceExtensionMethods { get; } +using static Execution.ExpressionBuilder; +public interface IProfileConfiguration +{ + bool? FieldMappingEnabled { get; } + bool? MethodMappingEnabled { get; } + bool? ConstructorMappingEnabled { get; } + bool? AllowNullDestinationValues { get; } + bool? AllowNullCollections { get; } + bool? EnableNullPropagationForQueryMapping { get; } + IReadOnlyCollection> AllTypeMapActions { get; } + IReadOnlyCollection> AllPropertyMapActions { get; } - /// - /// Specify which properties should be mapped. - /// By default only public properties are mapped. - /// - Func ShouldMapProperty { get; } + /// + /// Source extension methods included for search + /// + IReadOnlyCollection SourceExtensionMethods { get; } - /// - /// Specify which fields should be mapped. - /// By default only public fields are mapped. - /// - Func ShouldMapField { get; } + /// + /// Specify which properties should be mapped. + /// By default only public properties are mapped. + /// + Func ShouldMapProperty { get; } - /// - /// Specify which methods, of those that are eligible (public, parameterless, and non-static or extension methods), should be mapped. - /// By default all eligible methods are mapped. - /// - Func ShouldMapMethod { get; } + /// + /// Specify which fields should be mapped. + /// By default only public fields are mapped. + /// + Func ShouldMapField { get; } - /// - /// Specify which constructors should be considered for the destination objects. - /// By default all constructors are considered. - /// - Func ShouldUseConstructor { get; } + /// + /// Specify which methods, of those that are eligible (public, parameterless, and non-static or extension methods), should be mapped. + /// By default all eligible methods are mapped. + /// + Func ShouldMapMethod { get; } - string ProfileName { get; } - IReadOnlyCollection GlobalIgnores { get; } - INamingConvention SourceMemberNamingConvention { get; } - INamingConvention DestinationMemberNamingConvention { get; } - IReadOnlyCollection TypeMapConfigs { get; } - IReadOnlyCollection OpenTypeMapConfigs { get; } - IReadOnlyCollection ValueTransformers { get; } - } /// - /// Provides a named configuration for maps. Naming conventions become scoped per profile. + /// Specify which constructors should be considered for the destination objects. + /// By default all constructors are considered. /// - public class Profile : IProfileExpressionInternal, IProfileConfiguration + Func ShouldUseConstructor { get; } + + string ProfileName { get; } + IReadOnlyCollection GlobalIgnores { get; } + INamingConvention SourceMemberNamingConvention { get; } + INamingConvention DestinationMemberNamingConvention { get; } + IReadOnlyCollection TypeMapConfigs { get; } + IReadOnlyCollection OpenTypeMapConfigs { get; } + IReadOnlyCollection ValueTransformers { get; } +} +/// +/// Provides a named configuration for maps. Naming conventions become scoped per profile. +/// +public class Profile : IProfileExpressionInternal, IProfileConfiguration +{ + private readonly List _prefixes = new() { "Get" }; + private readonly List _postfixes = new(); + private readonly List _typeMapConfigs = new(); + private readonly PrePostfixName _prePostfixName = new(); + private ReplaceName _replaceName; + private readonly MemberConfiguration _memberConfiguration; + private List> _allPropertyMapActions; + private List> _allTypeMapActions; + private List _globalIgnores; + private List _openTypeMapConfigs; + private List _sourceExtensionMethods; + private List _valueTransformerConfigs; + private bool? _constructorMappingEnabled; + protected internal Profile(string profileName) : this() => ProfileName = profileName; + protected Profile() { - private readonly List _prefixes = new() { "Get" }; - private readonly List _postfixes = new(); - private readonly List _typeMapConfigs = new(); - private readonly PrePostfixName _prePostfixName = new(); - private ReplaceName _replaceName; - private readonly MemberConfiguration _memberConfiguration; - private List> _allPropertyMapActions; - private List> _allTypeMapActions; - private List _globalIgnores; - private List _openTypeMapConfigs; - private List _sourceExtensionMethods; - private List _valueTransformerConfigs; - private bool? _constructorMappingEnabled; - protected internal Profile(string profileName) : this() => ProfileName = profileName; - protected Profile() - { - ProfileName = GetType().FullName; - _memberConfiguration = new(){ NameToMemberMappers = { _prePostfixName } }; - } - protected internal Profile(string profileName, Action configurationAction) : this(profileName) => configurationAction(this); - MemberConfiguration IProfileExpressionInternal.MemberConfiguration => _memberConfiguration; - bool? IProfileConfiguration.ConstructorMappingEnabled => _constructorMappingEnabled; - bool? IProfileExpressionInternal.MethodMappingEnabled { get; set; } - bool? IProfileConfiguration.MethodMappingEnabled => this.Internal().MethodMappingEnabled; - bool? IProfileExpressionInternal.FieldMappingEnabled { get; set; } - bool? IProfileConfiguration.FieldMappingEnabled => this.Internal().FieldMappingEnabled; - bool? IProfileConfiguration.EnableNullPropagationForQueryMapping => this.Internal().EnableNullPropagationForQueryMapping; - IReadOnlyCollection> IProfileConfiguration.AllPropertyMapActions - => _allPropertyMapActions.NullCheck(); - IReadOnlyCollection> IProfileConfiguration.AllTypeMapActions => _allTypeMapActions.NullCheck(); - IReadOnlyCollection IProfileConfiguration.GlobalIgnores => _globalIgnores.NullCheck(); - IReadOnlyCollection IProfileConfiguration.SourceExtensionMethods => _sourceExtensionMethods.NullCheck(); - IReadOnlyCollection IProfileConfiguration.TypeMapConfigs => _typeMapConfigs; - IReadOnlyCollection IProfileConfiguration.OpenTypeMapConfigs => _openTypeMapConfigs.NullCheck(); - IReadOnlyCollection IProfileConfiguration.ValueTransformers => _valueTransformerConfigs.NullCheck(); + ProfileName = GetType().FullName; + _memberConfiguration = new(){ NameToMemberMappers = { _prePostfixName } }; + } + protected internal Profile(string profileName, Action configurationAction) : this(profileName) => configurationAction(this); + MemberConfiguration IProfileExpressionInternal.MemberConfiguration => _memberConfiguration; + bool? IProfileConfiguration.ConstructorMappingEnabled => _constructorMappingEnabled; + bool? IProfileExpressionInternal.MethodMappingEnabled { get; set; } + bool? IProfileConfiguration.MethodMappingEnabled => this.Internal().MethodMappingEnabled; + bool? IProfileExpressionInternal.FieldMappingEnabled { get; set; } + bool? IProfileConfiguration.FieldMappingEnabled => this.Internal().FieldMappingEnabled; + bool? IProfileConfiguration.EnableNullPropagationForQueryMapping => this.Internal().EnableNullPropagationForQueryMapping; + IReadOnlyCollection> IProfileConfiguration.AllPropertyMapActions + => _allPropertyMapActions.NullCheck(); + IReadOnlyCollection> IProfileConfiguration.AllTypeMapActions => _allTypeMapActions.NullCheck(); + IReadOnlyCollection IProfileConfiguration.GlobalIgnores => _globalIgnores.NullCheck(); + IReadOnlyCollection IProfileConfiguration.SourceExtensionMethods => _sourceExtensionMethods.NullCheck(); + IReadOnlyCollection IProfileConfiguration.TypeMapConfigs => _typeMapConfigs; + IReadOnlyCollection IProfileConfiguration.OpenTypeMapConfigs => _openTypeMapConfigs.NullCheck(); + IReadOnlyCollection IProfileConfiguration.ValueTransformers => _valueTransformerConfigs.NullCheck(); - public virtual string ProfileName { get; } - public bool? AllowNullDestinationValues { get; set; } - public bool? AllowNullCollections { get; set; } - bool? IProfileExpressionInternal.EnableNullPropagationForQueryMapping { get; set; } - public Func ShouldMapProperty { get; set; } - public Func ShouldMapField { get; set; } - public Func ShouldMapMethod { get; set; } - public Func ShouldUseConstructor { get; set; } - public INamingConvention SourceMemberNamingConvention - { - get => _memberConfiguration.SourceNamingConvention; - set => _memberConfiguration.SourceNamingConvention = value; - } - public INamingConvention DestinationMemberNamingConvention - { - get => _memberConfiguration.DestinationNamingConvention; - set => _memberConfiguration.DestinationNamingConvention = value; - } - public List ValueTransformers => _valueTransformerConfigs ??= new(); - List IProfileExpressionInternal.Prefixes => _prefixes; - List IProfileExpressionInternal.Postfixes => _postfixes; - public void DisableConstructorMapping() => _constructorMappingEnabled = false; + public virtual string ProfileName { get; } + public bool? AllowNullDestinationValues { get; set; } + public bool? AllowNullCollections { get; set; } + bool? IProfileExpressionInternal.EnableNullPropagationForQueryMapping { get; set; } + public Func ShouldMapProperty { get; set; } + public Func ShouldMapField { get; set; } + public Func ShouldMapMethod { get; set; } + public Func ShouldUseConstructor { get; set; } + public INamingConvention SourceMemberNamingConvention + { + get => _memberConfiguration.SourceNamingConvention; + set => _memberConfiguration.SourceNamingConvention = value; + } + public INamingConvention DestinationMemberNamingConvention + { + get => _memberConfiguration.DestinationNamingConvention; + set => _memberConfiguration.DestinationNamingConvention = value; + } + public List ValueTransformers => _valueTransformerConfigs ??= new(); + List IProfileExpressionInternal.Prefixes => _prefixes; + List IProfileExpressionInternal.Postfixes => _postfixes; + public void DisableConstructorMapping() => _constructorMappingEnabled = false; - void IProfileExpressionInternal.ForAllMaps(Action configuration) - { - _allTypeMapActions ??= new(); - _allTypeMapActions.Add(configuration); - } + void IProfileExpressionInternal.ForAllMaps(Action configuration) + { + _allTypeMapActions ??= new(); + _allTypeMapActions.Add(configuration); + } - void IProfileExpressionInternal.ForAllPropertyMaps(Func condition, Action configuration) - { - _allPropertyMapActions ??= new(); - _allPropertyMapActions.Add((pm, cfg) => - { - if (condition(pm)) configuration(pm, cfg); - }); - } - public IProjectionExpression CreateProjection() => - CreateProjection(MemberList.Destination); - public IProjectionExpression CreateProjection(MemberList memberList) => - (IProjectionExpression)CreateMapCore(memberList, projection: true); - public IMappingExpression CreateMap() => - CreateMapCore(MemberList.Destination); - public IMappingExpression CreateMap(MemberList memberList) => - CreateMapCore(memberList); - private IMappingExpression CreateMapCore(MemberList memberList, bool projection = false) + void IProfileExpressionInternal.ForAllPropertyMaps(Func condition, Action configuration) + { + _allPropertyMapActions ??= new(); + _allPropertyMapActions.Add((pm, cfg) => { - var mappingExp = new MappingExpression(memberList, projection); - _typeMapConfigs.Add(mappingExp); - return mappingExp; - } + if (condition(pm)) configuration(pm, cfg); + }); + } + public IProjectionExpression CreateProjection() => + CreateProjection(MemberList.Destination); + public IProjectionExpression CreateProjection(MemberList memberList) => + (IProjectionExpression)CreateMapCore(memberList, projection: true); + public IMappingExpression CreateMap() => + CreateMapCore(MemberList.Destination); + public IMappingExpression CreateMap(MemberList memberList) => + CreateMapCore(memberList); + private IMappingExpression CreateMapCore(MemberList memberList, bool projection = false) + { + var mappingExp = new MappingExpression(memberList, projection); + _typeMapConfigs.Add(mappingExp); + return mappingExp; + } - public IMappingExpression CreateMap(Type sourceType, Type destinationType) => - CreateMap(sourceType, destinationType, MemberList.Destination); + public IMappingExpression CreateMap(Type sourceType, Type destinationType) => + CreateMap(sourceType, destinationType, MemberList.Destination); - public IMappingExpression CreateMap(Type sourceType, Type destinationType, MemberList memberList) - { - var types = new TypePair(sourceType, destinationType); - var map = new MappingExpression(types, memberList); - _typeMapConfigs.Add(map); - if (types.ContainsGenericParameters) - { - _openTypeMapConfigs ??= new(); - _openTypeMapConfigs.Add(map); - } - return map; - } - public void ClearPrefixes() => _prefixes.Clear(); - public void ReplaceMemberName(string original, string newValue) - { - if (_replaceName == null) - { - _replaceName = new(); - _memberConfiguration.NameToMemberMappers.Add(_replaceName); - } - _replaceName.MemberNameReplacers.Add(new(original, newValue)); - } - public void RecognizePrefixes(params string[] prefixes) => _prefixes.AddRange(prefixes); - public void RecognizePostfixes(params string[] postfixes) => _postfixes.AddRange(postfixes); - public void RecognizeDestinationPrefixes(params string[] prefixes) => _prePostfixName.DestinationPrefixes.UnionWith(prefixes); - public void RecognizeDestinationPostfixes(params string[] postfixes) => _prePostfixName.DestinationPostfixes.UnionWith(postfixes); - public void AddGlobalIgnore(string propertyNameStartingWith) + public IMappingExpression CreateMap(Type sourceType, Type destinationType, MemberList memberList) + { + var types = new TypePair(sourceType, destinationType); + var map = new MappingExpression(types, memberList); + _typeMapConfigs.Add(map); + if (types.ContainsGenericParameters) { - _globalIgnores ??= new(); - _globalIgnores.Add(propertyNameStartingWith); + _openTypeMapConfigs ??= new(); + _openTypeMapConfigs.Add(map); } - public void IncludeSourceExtensionMethods(Type type) + return map; + } + public void ClearPrefixes() => _prefixes.Clear(); + public void ReplaceMemberName(string original, string newValue) + { + if (_replaceName == null) { - _sourceExtensionMethods ??= new(); - _sourceExtensionMethods.AddRange( - type.GetMethods(TypeExtensions.StaticFlags).Where(m => m.Has() && m.GetParameters().Length == 1)); + _replaceName = new(); + _memberConfiguration.NameToMemberMappers.Add(_replaceName); } + _replaceName.MemberNameReplacers.Add(new(original, newValue)); + } + public void RecognizePrefixes(params string[] prefixes) => _prefixes.AddRange(prefixes); + public void RecognizePostfixes(params string[] postfixes) => _postfixes.AddRange(postfixes); + public void RecognizeDestinationPrefixes(params string[] prefixes) => _prePostfixName.DestinationPrefixes.UnionWith(prefixes); + public void RecognizeDestinationPostfixes(params string[] postfixes) => _prePostfixName.DestinationPostfixes.UnionWith(postfixes); + public void AddGlobalIgnore(string propertyNameStartingWith) + { + _globalIgnores ??= new(); + _globalIgnores.Add(propertyNameStartingWith); + } + public void IncludeSourceExtensionMethods(Type type) + { + _sourceExtensionMethods ??= new(); + _sourceExtensionMethods.AddRange( + type.GetMethods(TypeExtensions.StaticFlags).Where(m => m.Has() && m.GetParameters().Length == 1)); } } \ No newline at end of file diff --git a/src/AutoMapper/Configuration/SourceMappingExpression.cs b/src/AutoMapper/Configuration/SourceMappingExpression.cs index b87dd1af9e..0253840f39 100644 --- a/src/AutoMapper/Configuration/SourceMappingExpression.cs +++ b/src/AutoMapper/Configuration/SourceMappingExpression.cs @@ -2,55 +2,54 @@ using System.Collections.Generic; using System.Reflection; -namespace AutoMapper.Configuration +namespace AutoMapper.Configuration; + +public interface ISourceMemberConfiguration +{ + void Configure(TypeMap typeMap); +} +/// +/// Source member configuration options +/// +public interface ISourceMemberConfigurationExpression { - public interface ISourceMemberConfiguration - { - void Configure(TypeMap typeMap); - } /// - /// Source member configuration options + /// Ignore this member when validating source members, MemberList.Source. + /// Does not affect validation for the default case, MemberList.Destination. /// - public interface ISourceMemberConfigurationExpression - { - /// - /// Ignore this member when validating source members, MemberList.Source. - /// Does not affect validation for the default case, MemberList.Destination. - /// - void DoNotValidate(); - } - public class SourceMappingExpression : ISourceMemberConfigurationExpression, ISourceMemberConfiguration - { - private readonly MemberInfo _sourceMember; - private readonly List> _sourceMemberActions = new List>(); + void DoNotValidate(); +} +public class SourceMappingExpression : ISourceMemberConfigurationExpression, ISourceMemberConfiguration +{ + private readonly MemberInfo _sourceMember; + private readonly List> _sourceMemberActions = new List>(); - public SourceMappingExpression(MemberInfo sourceMember) => _sourceMember = sourceMember; + public SourceMappingExpression(MemberInfo sourceMember) => _sourceMember = sourceMember; - public void DoNotValidate() => _sourceMemberActions.Add(smc => smc.Ignore()); + public void DoNotValidate() => _sourceMemberActions.Add(smc => smc.Ignore()); - public void Configure(TypeMap typeMap) - { - var sourcePropertyConfig = typeMap.FindOrCreateSourceMemberConfigFor(_sourceMember); + public void Configure(TypeMap typeMap) + { + var sourcePropertyConfig = typeMap.FindOrCreateSourceMemberConfigFor(_sourceMember); - foreach (var action in _sourceMemberActions) - { - action(sourcePropertyConfig); - } + foreach (var action in _sourceMemberActions) + { + action(sourcePropertyConfig); } } - /// - /// Contains member configuration relating to source members - /// - public class SourceMemberConfig - { - private bool _ignored; +} +/// +/// Contains member configuration relating to source members +/// +public class SourceMemberConfig +{ + private bool _ignored; - public SourceMemberConfig(MemberInfo sourceMember) => SourceMember = sourceMember; + public SourceMemberConfig(MemberInfo sourceMember) => SourceMember = sourceMember; - public MemberInfo SourceMember { get; } + public MemberInfo SourceMember { get; } - public void Ignore() => _ignored = true; + public void Ignore() => _ignored = true; - public bool IsIgnored() => _ignored; - } + public bool IsIgnored() => _ignored; } \ No newline at end of file diff --git a/src/AutoMapper/Configuration/TypeMapConfiguration.cs b/src/AutoMapper/Configuration/TypeMapConfiguration.cs index 93f18aa612..99cc6c4ae3 100644 --- a/src/AutoMapper/Configuration/TypeMapConfiguration.cs +++ b/src/AutoMapper/Configuration/TypeMapConfiguration.cs @@ -6,388 +6,387 @@ using System.Reflection; using AutoMapper.Features; using AutoMapper.Internal; -namespace AutoMapper.Configuration +namespace AutoMapper.Configuration; + +using static Expression; +using Execution; +[EditorBrowsable(EditorBrowsableState.Never)] +public abstract class TypeMapConfiguration { - using static Expression; - using Execution; - [EditorBrowsable(EditorBrowsableState.Never)] - public abstract class TypeMapConfiguration - { - private List _valueTransformers; - private Features _features; - private List _sourceMemberConfigurations; - private List _ctorParamConfigurations; - private List _memberConfigurations; - private readonly MemberList _memberList; - private readonly TypePair _types; - protected TypeMapConfiguration(MemberList memberList, Type sourceType, Type destinationType) : this(memberList, new TypePair(sourceType, destinationType)) - { - } - protected TypeMapConfiguration(MemberList memberList, TypePair types) - { - _memberList = memberList; - _types = types; - } - public Type DestinationTypeOverride { get; protected set; } - protected bool Projection { get; set; } - public TypePair Types => _types; - public bool IsReverseMap { get; set; } - public bool HasTypeConverter { get; protected set; } - public TypeMap TypeMap { get; private set; } - public Type SourceType => _types.SourceType; - public Type DestinationType => _types.DestinationType; - public Features Features => _features ??= new(); - public TypeMapConfiguration ReverseTypeMap => ReverseMapExpression; - public List ValueTransformers => _valueTransformers ??= new(); - protected TypeMapConfiguration ReverseMapExpression { get; set; } - protected List> TypeMapActions { get; } = new List>(); - protected List MemberConfigurations => _memberConfigurations ??= new(); - protected List SourceMemberConfigurations => _sourceMemberConfigurations ??= new(); - protected List CtorParamConfigurations => _ctorParamConfigurations ??= new(); - public void Configure(TypeMap typeMap, List sourceMembers) - { - TypeMap = typeMap; - typeMap.Projection = Projection; - typeMap.ConfiguredMemberList = _memberList; - foreach (var action in TypeMapActions) - { - action(typeMap); - } - if (typeMap.ConstructorMap == null && typeMap.CanConstructorMap()) - { - MapDestinationCtorToSource(typeMap, sourceMembers); - } - if (_memberConfigurations != null) - { - foreach (var memberConfig in _memberConfigurations) - { - memberConfig.Configure(typeMap); - } - } - if (_sourceMemberConfigurations != null) - { - AddSourceMembersConfigurations(typeMap); - } - if (_ctorParamConfigurations != null) - { - AddCtorParamConfigurations(typeMap); - } - if (_valueTransformers != null) - { - AddValueTransformers(typeMap); - } - _features?.Configure(typeMap); - if (ReverseMapExpression != null) - { - ConfigureReverseMap(typeMap); - } - } - protected void ReverseMapCore(TypeMapConfiguration reverseMap) + private List _valueTransformers; + private Features _features; + private List _sourceMemberConfigurations; + private List _ctorParamConfigurations; + private List _memberConfigurations; + private readonly MemberList _memberList; + private readonly TypePair _types; + protected TypeMapConfiguration(MemberList memberList, Type sourceType, Type destinationType) : this(memberList, new TypePair(sourceType, destinationType)) + { + } + protected TypeMapConfiguration(MemberList memberList, TypePair types) + { + _memberList = memberList; + _types = types; + } + public Type DestinationTypeOverride { get; protected set; } + protected bool Projection { get; set; } + public TypePair Types => _types; + public bool IsReverseMap { get; set; } + public bool HasTypeConverter { get; protected set; } + public TypeMap TypeMap { get; private set; } + public Type SourceType => _types.SourceType; + public Type DestinationType => _types.DestinationType; + public Features Features => _features ??= new(); + public TypeMapConfiguration ReverseTypeMap => ReverseMapExpression; + public List ValueTransformers => _valueTransformers ??= new(); + protected TypeMapConfiguration ReverseMapExpression { get; set; } + protected List> TypeMapActions { get; } = new List>(); + protected List MemberConfigurations => _memberConfigurations ??= new(); + protected List SourceMemberConfigurations => _sourceMemberConfigurations ??= new(); + protected List CtorParamConfigurations => _ctorParamConfigurations ??= new(); + public void Configure(TypeMap typeMap, List sourceMembers) + { + TypeMap = typeMap; + typeMap.Projection = Projection; + typeMap.ConfiguredMemberList = _memberList; + foreach (var action in TypeMapActions) { - ReverseMapExpression = reverseMap; - if (_memberConfigurations != null) - { - reverseMap.MemberConfigurations.AddRange(_memberConfigurations.Select(m => m.Reverse()).Where(m => m != null)); - } - _features?.ReverseTo(reverseMap.Features); + action(typeMap); } - private void AddCtorParamConfigurations(TypeMap typeMap) + if (typeMap.ConstructorMap == null && typeMap.CanConstructorMap()) { - foreach (var paramConfig in _ctorParamConfigurations) - { - paramConfig.Configure(typeMap); - } + MapDestinationCtorToSource(typeMap, sourceMembers); } - private void AddSourceMembersConfigurations(TypeMap typeMap) + if (_memberConfigurations != null) { - foreach (var memberConfig in _sourceMemberConfigurations) + foreach (var memberConfig in _memberConfigurations) { memberConfig.Configure(typeMap); } } - private void AddValueTransformers(TypeMap typeMap) + if (_sourceMemberConfigurations != null) { - foreach (var valueTransformer in _valueTransformers) - { - typeMap.AddValueTransformation(valueTransformer); - } + AddSourceMembersConfigurations(typeMap); } - private void ConfigureReverseMap(TypeMap typeMap) + if (_ctorParamConfigurations != null) { - ReverseSourceMembers(typeMap); - foreach (var destProperty in typeMap.PropertyMaps.Where(pm => pm.Ignored)) - { - ReverseMapExpression.ForSourceMemberCore(destProperty.DestinationName, opt => opt.DoNotValidate()); - } - foreach (var includedDerivedType in typeMap.IncludedDerivedTypes) - { - ReverseMapExpression.IncludeCore(includedDerivedType.DestinationType, includedDerivedType.SourceType); - } - foreach (var includedBaseType in typeMap.IncludedBaseTypes) - { - ReverseMapExpression.IncludeBaseCore(includedBaseType.DestinationType, includedBaseType.SourceType); - } - ReverseIncludedMembers(typeMap); + AddCtorParamConfigurations(typeMap); } - private void MapDestinationCtorToSource(TypeMap typeMap, List sourceMembers) + if (_valueTransformers != null) { - sourceMembers ??= new(); - ConstructorMap ctorMap = new(); - typeMap.ConstructorMap = ctorMap; - foreach (var destCtor in typeMap.DestinationConstructors) - { - var constructor = destCtor.Constructor; - ctorMap.Reset(constructor); - bool canMapResolve = true; - foreach (var parameter in destCtor.Parameters) - { - var name = parameter.Name; - if (name == null) - { - return; - } - sourceMembers.Clear(); - var canResolve = typeMap.Profile.MapDestinationPropertyToSource(typeMap.SourceTypeDetails, constructor.DeclaringType, parameter.ParameterType, name, sourceMembers, IsReverseMap); - if (!canResolve && !parameter.IsOptional && !IsConfigured(parameter)) - { - canMapResolve = false; - } - ctorMap.AddParameter(parameter, sourceMembers, typeMap); - } - if (canMapResolve) - { - ctorMap.CanResolve = true; - break; - } - } - return; - bool IsConfigured(ParameterInfo parameter) => _ctorParamConfigurations?.Any(c => c.CtorParamName == parameter.Name) is true; + AddValueTransformers(typeMap); } - protected IEnumerable MapToSourceMembers() => - _memberConfigurations?.Where(m => m.SourceExpression != null && m.SourceExpression.Body == m.SourceExpression.Parameters[0]) ?? Array.Empty(); - private void ReverseIncludedMembers(TypeMap typeMap) + _features?.Configure(typeMap); + if (ReverseMapExpression != null) { - Stack chain = null; - foreach (var includedMember in typeMap.IncludedMembers.Where(i => i.IsMemberPath(out chain))) - { - var memberPath = new MemberPath(chain); - var newSource = Parameter(typeMap.DestinationType, "source"); - var customExpression = Lambda(newSource, newSource); - ReverseSourceMembers(memberPath, customExpression); - } + ConfigureReverseMap(typeMap); } - private void ReverseSourceMembers(TypeMap typeMap) + } + protected void ReverseMapCore(TypeMapConfiguration reverseMap) + { + ReverseMapExpression = reverseMap; + if (_memberConfigurations != null) { - foreach (var propertyMap in typeMap.PropertyMaps.Where(p => p.SourceMembers.Length > 1 && !p.SourceMembers.Any(s => s is MethodInfo))) - { - var memberPath = new MemberPath(propertyMap.SourceMembers); - var customExpression = propertyMap.DestinationMember.Lambda(); - ReverseSourceMembers(memberPath, customExpression); - } + reverseMap.MemberConfigurations.AddRange(_memberConfigurations.Select(m => m.Reverse()).Where(m => m != null)); } - private void ReverseSourceMembers(MemberPath memberPath, LambdaExpression customExpression) + _features?.ReverseTo(reverseMap.Features); + } + private void AddCtorParamConfigurations(TypeMap typeMap) + { + foreach (var paramConfig in _ctorParamConfigurations) { - ReverseMapExpression.TypeMapActions.Add(reverseTypeMap => - { - var newDestination = Parameter(reverseTypeMap.DestinationType, "destination"); - var path = memberPath.Members.Chain(newDestination); - var forPathLambda = Lambda(path, newDestination); - - var pathMap = reverseTypeMap.FindOrCreatePathMapFor(forPathLambda, memberPath, reverseTypeMap); - - pathMap.SetResolver(customExpression); - }); + paramConfig.Configure(typeMap); } - protected void ForSourceMemberCore(string sourceMemberName, Action memberOptions) + } + private void AddSourceMembersConfigurations(TypeMap typeMap) + { + foreach (var memberConfig in _sourceMemberConfigurations) { - var memberInfo = SourceType.GetFieldOrProperty(sourceMemberName); - ForSourceMemberCore(memberInfo, memberOptions); + memberConfig.Configure(typeMap); } - protected void ForSourceMemberCore(MemberInfo memberInfo, Action memberOptions) + } + private void AddValueTransformers(TypeMap typeMap) + { + foreach (var valueTransformer in _valueTransformers) { - var srcConfig = new SourceMappingExpression(memberInfo); - memberOptions(srcConfig); - SourceMemberConfigurations.Add(srcConfig); + typeMap.AddValueTransformation(valueTransformer); } - protected void IncludeCore(Type derivedSourceType, Type derivedDestinationType) + } + private void ConfigureReverseMap(TypeMap typeMap) + { + ReverseSourceMembers(typeMap); + foreach (var destProperty in typeMap.PropertyMaps.Where(pm => pm.Ignored)) { - var derivedTypes = new TypePair(derivedSourceType, derivedDestinationType); - derivedTypes.CheckIsDerivedFrom(_types); - TypeMapActions.Add(tm => tm.IncludeDerivedTypes(derivedTypes)); + ReverseMapExpression.ForSourceMemberCore(destProperty.DestinationName, opt => opt.DoNotValidate()); } - protected void IncludeBaseCore(Type sourceBase, Type destinationBase) + foreach (var includedDerivedType in typeMap.IncludedDerivedTypes) { - var baseTypes = new TypePair(sourceBase, destinationBase); - _types.CheckIsDerivedFrom(baseTypes); - TypeMapActions.Add(tm => tm.IncludeBaseTypes(baseTypes)); + ReverseMapExpression.IncludeCore(includedDerivedType.DestinationType, includedDerivedType.SourceType); } - public IPropertyMapConfiguration GetDestinationMemberConfiguration(MemberInfo destinationMember) + foreach (var includedBaseType in typeMap.IncludedBaseTypes) { - if (_memberConfigurations == null) - { - return null; - } - foreach (var config in _memberConfigurations) + ReverseMapExpression.IncludeBaseCore(includedBaseType.DestinationType, includedBaseType.SourceType); + } + ReverseIncludedMembers(typeMap); + } + private void MapDestinationCtorToSource(TypeMap typeMap, List sourceMembers) + { + sourceMembers ??= new(); + ConstructorMap ctorMap = new(); + typeMap.ConstructorMap = ctorMap; + foreach (var destCtor in typeMap.DestinationConstructors) + { + var constructor = destCtor.Constructor; + ctorMap.Reset(constructor); + bool canMapResolve = true; + foreach (var parameter in destCtor.Parameters) { - if (config.DestinationMember == destinationMember) + var name = parameter.Name; + if (name == null) + { + return; + } + sourceMembers.Clear(); + var canResolve = typeMap.Profile.MapDestinationPropertyToSource(typeMap.SourceTypeDetails, constructor.DeclaringType, parameter.ParameterType, name, sourceMembers, IsReverseMap); + if (!canResolve && !parameter.IsOptional && !IsConfigured(parameter)) { - return config; + canMapResolve = false; } + ctorMap.AddParameter(parameter, sourceMembers, typeMap); + } + if (canMapResolve) + { + ctorMap.CanResolve = true; + break; } - return null; } - protected abstract void IgnoreDestinationMember(MemberInfo property, bool ignorePaths = true); + return; + bool IsConfigured(ParameterInfo parameter) => _ctorParamConfigurations?.Any(c => c.CtorParamName == parameter.Name) is true; } - public abstract class MappingExpressionBase : TypeMapConfiguration, IMappingExpressionBase - where TMappingExpression : class, IMappingExpressionBase + protected IEnumerable MapToSourceMembers() => + _memberConfigurations?.Where(m => m.SourceExpression != null && m.SourceExpression.Body == m.SourceExpression.Parameters[0]) ?? Array.Empty(); + private void ReverseIncludedMembers(TypeMap typeMap) { - protected MappingExpressionBase(MemberList memberList) : base(memberList, typeof(TSource), typeof(TDestination)){ } - protected MappingExpressionBase(MemberList memberList, Type sourceType, Type destinationType) : base(memberList, sourceType, destinationType){} - protected MappingExpressionBase(MemberList memberList, TypePair types) : base(memberList, types){} - public void As(Type typeOverride) + Stack chain = null; + foreach (var includedMember in typeMap.IncludedMembers.Where(i => i.IsMemberPath(out chain))) { - if (typeOverride == DestinationType) - { - throw new InvalidOperationException("As must specify a derived type, not " + DestinationType); - } - typeOverride.CheckIsDerivedFrom(DestinationType); - DestinationTypeOverride = typeOverride; + var memberPath = new MemberPath(chain); + var newSource = Parameter(typeMap.DestinationType, "source"); + var customExpression = Lambda(newSource, newSource); + ReverseSourceMembers(memberPath, customExpression); } - public TMappingExpression MaxDepth(int depth) + } + private void ReverseSourceMembers(TypeMap typeMap) + { + foreach (var propertyMap in typeMap.PropertyMaps.Where(p => p.SourceMembers.Length > 1 && !p.SourceMembers.Any(s => s is MethodInfo))) { - TypeMapActions.Add(tm => tm.MaxDepth = depth); - - return this as TMappingExpression; + var memberPath = new MemberPath(propertyMap.SourceMembers); + var customExpression = propertyMap.DestinationMember.Lambda(); + ReverseSourceMembers(memberPath, customExpression); } - public TMappingExpression ConstructUsingServiceLocator() + } + private void ReverseSourceMembers(MemberPath memberPath, LambdaExpression customExpression) + { + ReverseMapExpression.TypeMapActions.Add(reverseTypeMap => { - TypeMapActions.Add(tm => tm.ConstructUsingServiceLocator()); + var newDestination = Parameter(reverseTypeMap.DestinationType, "destination"); + var path = memberPath.Members.Chain(newDestination); + var forPathLambda = Lambda(path, newDestination); - return this as TMappingExpression; - } - public TMappingExpression BeforeMap(Action beforeFunction) => BeforeMapCore((src, dest, ctxt) => beforeFunction(src, dest)); - private TMappingExpression BeforeMapCore(Expression> expr) - { - TypeMapActions.Add(tm => tm.AddBeforeMapAction(expr)); - return this as TMappingExpression; - } - public TMappingExpression BeforeMap(Action beforeFunction) => - BeforeMapCore((src, dest, ctxt) => beforeFunction(src, dest, ctxt)); - public TMappingExpression BeforeMap() where TMappingAction : IMappingAction => - BeforeMap(CallMapAction); - public TMappingExpression AfterMap() where TMappingAction : IMappingAction => - AfterMap(CallMapAction); - private static void CallMapAction(TSource source, TDestination destination, ResolutionContext context) => - ((IMappingAction)context.CreateInstance(typeof(TMappingAction))).Process(source, destination, context); - public TMappingExpression AfterMap(Action afterFunction) => AfterMapCore((src, dest, ctxt) => afterFunction(src, dest)); - private TMappingExpression AfterMapCore(Expression> expr) - { - TypeMapActions.Add(tm => tm.AddAfterMapAction(expr)); - return this as TMappingExpression; - } - public TMappingExpression AfterMap(Action afterFunction) => - AfterMapCore((src, dest, ctxt) => afterFunction(src, dest, ctxt)); - public TMappingExpression PreserveReferences() - { - TypeMapActions.Add(tm => tm.PreserveReferences = true); - return this as TMappingExpression; - } - public TMappingExpression DisableCtorValidation() + var pathMap = reverseTypeMap.FindOrCreatePathMapFor(forPathLambda, memberPath, reverseTypeMap); + + pathMap.SetResolver(customExpression); + }); + } + protected void ForSourceMemberCore(string sourceMemberName, Action memberOptions) + { + var memberInfo = SourceType.GetFieldOrProperty(sourceMemberName); + ForSourceMemberCore(memberInfo, memberOptions); + } + protected void ForSourceMemberCore(MemberInfo memberInfo, Action memberOptions) + { + var srcConfig = new SourceMappingExpression(memberInfo); + memberOptions(srcConfig); + SourceMemberConfigurations.Add(srcConfig); + } + protected void IncludeCore(Type derivedSourceType, Type derivedDestinationType) + { + var derivedTypes = new TypePair(derivedSourceType, derivedDestinationType); + derivedTypes.CheckIsDerivedFrom(_types); + TypeMapActions.Add(tm => tm.IncludeDerivedTypes(derivedTypes)); + } + protected void IncludeBaseCore(Type sourceBase, Type destinationBase) + { + var baseTypes = new TypePair(sourceBase, destinationBase); + _types.CheckIsDerivedFrom(baseTypes); + TypeMapActions.Add(tm => tm.IncludeBaseTypes(baseTypes)); + } + public IPropertyMapConfiguration GetDestinationMemberConfiguration(MemberInfo destinationMember) + { + if (_memberConfigurations == null) { - TypeMapActions.Add(tm => - { - tm.DisableConstructorValidation = true; - }); - return this as TMappingExpression; + return null; } - public TMappingExpression ValidateMemberList(MemberList memberList) + foreach (var config in _memberConfigurations) { - TypeMapActions.Add(tm => + if (config.DestinationMember == destinationMember) { - tm.ConfiguredMemberList = memberList; - }); - return this as TMappingExpression; - } - public TMappingExpression IncludeAllDerived() - { - TypeMapActions.Add(tm => tm.IncludeAllDerivedTypes = true); - return this as TMappingExpression; - } - public TMappingExpression Include(Type otherSourceType, Type otherDestinationType) - { - IncludeCore(otherSourceType, otherDestinationType); - return this as TMappingExpression; - } - public TMappingExpression IncludeBase(Type sourceBase, Type destinationBase) - { - IncludeBaseCore(sourceBase, destinationBase); - return this as TMappingExpression; - } - public TMappingExpression ForSourceMember(string sourceMemberName, Action memberOptions) - { - ForSourceMemberCore(sourceMemberName, memberOptions); - return this as TMappingExpression; - } - public TMappingExpression ConstructUsing(Expression> ctor) => ConstructUsingCore(ctor); - private TMappingExpression ConstructUsingCore(LambdaExpression ctor) - { - TypeMapActions.Add(tm => tm.CustomCtorFunction = ctor); - return this as TMappingExpression; - } - public TMappingExpression ConstructUsing(Func ctor) - { - Expression> expr = (src, ctxt) => ctor(src, ctxt); - return ConstructUsingCore(expr); + return config; + } } - public void ConvertUsing(Type typeConverterType) + return null; + } + protected abstract void IgnoreDestinationMember(MemberInfo property, bool ignorePaths = true); +} +public abstract class MappingExpressionBase : TypeMapConfiguration, IMappingExpressionBase + where TMappingExpression : class, IMappingExpressionBase +{ + protected MappingExpressionBase(MemberList memberList) : base(memberList, typeof(TSource), typeof(TDestination)){ } + protected MappingExpressionBase(MemberList memberList, Type sourceType, Type destinationType) : base(memberList, sourceType, destinationType){} + protected MappingExpressionBase(MemberList memberList, TypePair types) : base(memberList, types){} + public void As(Type typeOverride) + { + if (typeOverride == DestinationType) { - HasTypeConverter = true; - TypeMapActions.Add(tm => tm.TypeConverter = new ClassTypeConverter(typeConverterType, tm.Types.ITypeConverter())); + throw new InvalidOperationException("As must specify a derived type, not " + DestinationType); } - public void ConvertUsing(Func mappingFunction) => ConvertUsingCore((src, dest, ctxt) => mappingFunction(src, dest)); - private void ConvertUsingCore(Expression> expr) => SetTypeConverter(new LambdaTypeConverter(expr)); - private void SetTypeConverter(TypeConverter typeConverter) + typeOverride.CheckIsDerivedFrom(DestinationType); + DestinationTypeOverride = typeOverride; + } + public TMappingExpression MaxDepth(int depth) + { + TypeMapActions.Add(tm => tm.MaxDepth = depth); + + return this as TMappingExpression; + } + public TMappingExpression ConstructUsingServiceLocator() + { + TypeMapActions.Add(tm => tm.ConstructUsingServiceLocator()); + + return this as TMappingExpression; + } + public TMappingExpression BeforeMap(Action beforeFunction) => BeforeMapCore((src, dest, ctxt) => beforeFunction(src, dest)); + private TMappingExpression BeforeMapCore(Expression> expr) + { + TypeMapActions.Add(tm => tm.AddBeforeMapAction(expr)); + return this as TMappingExpression; + } + public TMappingExpression BeforeMap(Action beforeFunction) => + BeforeMapCore((src, dest, ctxt) => beforeFunction(src, dest, ctxt)); + public TMappingExpression BeforeMap() where TMappingAction : IMappingAction => + BeforeMap(CallMapAction); + public TMappingExpression AfterMap() where TMappingAction : IMappingAction => + AfterMap(CallMapAction); + private static void CallMapAction(TSource source, TDestination destination, ResolutionContext context) => + ((IMappingAction)context.CreateInstance(typeof(TMappingAction))).Process(source, destination, context); + public TMappingExpression AfterMap(Action afterFunction) => AfterMapCore((src, dest, ctxt) => afterFunction(src, dest)); + private TMappingExpression AfterMapCore(Expression> expr) + { + TypeMapActions.Add(tm => tm.AddAfterMapAction(expr)); + return this as TMappingExpression; + } + public TMappingExpression AfterMap(Action afterFunction) => + AfterMapCore((src, dest, ctxt) => afterFunction(src, dest, ctxt)); + public TMappingExpression PreserveReferences() + { + TypeMapActions.Add(tm => tm.PreserveReferences = true); + return this as TMappingExpression; + } + public TMappingExpression DisableCtorValidation() + { + TypeMapActions.Add(tm => { - HasTypeConverter = true; - TypeMapActions.Add(tm => tm.TypeConverter = typeConverter); - } - public void ConvertUsing(Func mappingFunction) => ConvertUsingCore((src, dest, ctxt) => mappingFunction(src, dest, ctxt)); - public void ConvertUsing(ITypeConverter converter) => ConvertUsing(converter.Convert); - public void ConvertUsing() where TTypeConverter : ITypeConverter => - SetTypeConverter(new ClassTypeConverter(typeof(TTypeConverter), typeof(ITypeConverter))); - public TMappingExpression ForCtorParam(string ctorParamName, Action> paramOptions) + tm.DisableConstructorValidation = true; + }); + return this as TMappingExpression; + } + public TMappingExpression ValidateMemberList(MemberList memberList) + { + TypeMapActions.Add(tm => { - var ctorParamExpression = new CtorParamConfigurationExpression(ctorParamName, SourceType); - paramOptions(ctorParamExpression); - CtorParamConfigurations.Add(ctorParamExpression); - return this as TMappingExpression; - } - public TMappingExpression IgnoreAllPropertiesWithAnInaccessibleSetter() + tm.ConfiguredMemberList = memberList; + }); + return this as TMappingExpression; + } + public TMappingExpression IncludeAllDerived() + { + TypeMapActions.Add(tm => tm.IncludeAllDerivedTypes = true); + return this as TMappingExpression; + } + public TMappingExpression Include(Type otherSourceType, Type otherDestinationType) + { + IncludeCore(otherSourceType, otherDestinationType); + return this as TMappingExpression; + } + public TMappingExpression IncludeBase(Type sourceBase, Type destinationBase) + { + IncludeBaseCore(sourceBase, destinationBase); + return this as TMappingExpression; + } + public TMappingExpression ForSourceMember(string sourceMemberName, Action memberOptions) + { + ForSourceMemberCore(sourceMemberName, memberOptions); + return this as TMappingExpression; + } + public TMappingExpression ConstructUsing(Expression> ctor) => ConstructUsingCore(ctor); + private TMappingExpression ConstructUsingCore(LambdaExpression ctor) + { + TypeMapActions.Add(tm => tm.CustomCtorFunction = ctor); + return this as TMappingExpression; + } + public TMappingExpression ConstructUsing(Func ctor) + { + Expression> expr = (src, ctxt) => ctor(src, ctxt); + return ConstructUsingCore(expr); + } + public void ConvertUsing(Type typeConverterType) + { + HasTypeConverter = true; + TypeMapActions.Add(tm => tm.TypeConverter = new ClassTypeConverter(typeConverterType, tm.Types.ITypeConverter())); + } + public void ConvertUsing(Func mappingFunction) => ConvertUsingCore((src, dest, ctxt) => mappingFunction(src, dest)); + private void ConvertUsingCore(Expression> expr) => SetTypeConverter(new LambdaTypeConverter(expr)); + private void SetTypeConverter(TypeConverter typeConverter) + { + HasTypeConverter = true; + TypeMapActions.Add(tm => tm.TypeConverter = typeConverter); + } + public void ConvertUsing(Func mappingFunction) => ConvertUsingCore((src, dest, ctxt) => mappingFunction(src, dest, ctxt)); + public void ConvertUsing(ITypeConverter converter) => ConvertUsing(converter.Convert); + public void ConvertUsing() where TTypeConverter : ITypeConverter => + SetTypeConverter(new ClassTypeConverter(typeof(TTypeConverter), typeof(ITypeConverter))); + public TMappingExpression ForCtorParam(string ctorParamName, Action> paramOptions) + { + var ctorParamExpression = new CtorParamConfigurationExpression(ctorParamName, SourceType); + paramOptions(ctorParamExpression); + CtorParamConfigurations.Add(ctorParamExpression); + return this as TMappingExpression; + } + public TMappingExpression IgnoreAllPropertiesWithAnInaccessibleSetter() + { + foreach(var property in PropertiesWithAnInaccessibleSetter(DestinationType)) { - foreach(var property in PropertiesWithAnInaccessibleSetter(DestinationType)) - { - IgnoreDestinationMember(property); - } - return this as TMappingExpression; + IgnoreDestinationMember(property); } - public TMappingExpression IgnoreAllSourcePropertiesWithAnInaccessibleSetter() + return this as TMappingExpression; + } + public TMappingExpression IgnoreAllSourcePropertiesWithAnInaccessibleSetter() + { + foreach (var property in PropertiesWithAnInaccessibleSetter(SourceType)) { - foreach (var property in PropertiesWithAnInaccessibleSetter(SourceType)) - { - ForSourceMemberCore(property, options => options.DoNotValidate()); - } - return this as TMappingExpression; + ForSourceMemberCore(property, options => options.DoNotValidate()); } - private static IEnumerable PropertiesWithAnInaccessibleSetter(Type type) => type.GetRuntimeProperties().Where(p => p.GetSetMethod() == null); - public void ConvertUsing(Expression> mappingFunction) => SetTypeConverter(new ExpressionTypeConverter(mappingFunction)); - public TMappingExpression AsProxy() + return this as TMappingExpression; + } + private static IEnumerable PropertiesWithAnInaccessibleSetter(Type type) => type.GetRuntimeProperties().Where(p => p.GetSetMethod() == null); + public void ConvertUsing(Expression> mappingFunction) => SetTypeConverter(new ExpressionTypeConverter(mappingFunction)); + public TMappingExpression AsProxy() + { + if (!DestinationType.IsInterface) { - if (!DestinationType.IsInterface) - { - throw new InvalidOperationException("Only interfaces can be proxied. " + DestinationType); - } - TypeMapActions.Add(tm => tm.AsProxy()); - return this as TMappingExpression; + throw new InvalidOperationException("Only interfaces can be proxied. " + DestinationType); } + TypeMapActions.Add(tm => tm.AsProxy()); + return this as TMappingExpression; } } \ No newline at end of file diff --git a/src/AutoMapper/ConstructorMap.cs b/src/AutoMapper/ConstructorMap.cs index 6fa2695608..bb0928377b 100644 --- a/src/AutoMapper/ConstructorMap.cs +++ b/src/AutoMapper/ConstructorMap.cs @@ -5,100 +5,99 @@ using System.Linq; using System.Linq.Expressions; using System.Reflection; -namespace AutoMapper +namespace AutoMapper; + +using Execution; +[EditorBrowsable(EditorBrowsableState.Never)] +public class ConstructorMap { - using Execution; - [EditorBrowsable(EditorBrowsableState.Never)] - public class ConstructorMap + private bool? _canResolve; + private readonly Dictionary _ctorParams = new(StringComparer.OrdinalIgnoreCase); + public ConstructorInfo Ctor { get; private set; } + public IReadOnlyCollection CtorParams => _ctorParams.Values; + public void Reset(ConstructorInfo ctor) { - private bool? _canResolve; - private readonly Dictionary _ctorParams = new(StringComparer.OrdinalIgnoreCase); - public ConstructorInfo Ctor { get; private set; } - public IReadOnlyCollection CtorParams => _ctorParams.Values; - public void Reset(ConstructorInfo ctor) - { - Ctor = ctor; - _ctorParams.Clear(); - _canResolve = null; - } - public bool CanResolve - { - get => _canResolve ??= ParametersCanResolve(); - set => _canResolve = value; - } - private bool ParametersCanResolve() + Ctor = ctor; + _ctorParams.Clear(); + _canResolve = null; + } + public bool CanResolve + { + get => _canResolve ??= ParametersCanResolve(); + set => _canResolve = value; + } + private bool ParametersCanResolve() + { + foreach (var param in _ctorParams.Values) { - foreach (var param in _ctorParams.Values) + if (!param.CanResolveValue) { - if (!param.CanResolveValue) - { - return false; - } + return false; } - return true; } - public ConstructorParameterMap this[string name] => _ctorParams.GetValueOrDefault(name); - public void AddParameter(ParameterInfo parameter, IEnumerable sourceMembers, TypeMap typeMap) + return true; + } + public ConstructorParameterMap this[string name] => _ctorParams.GetValueOrDefault(name); + public void AddParameter(ParameterInfo parameter, IEnumerable sourceMembers, TypeMap typeMap) + { + if (parameter.Name == null) { - if (parameter.Name == null) - { - return; - } - _ctorParams.Add(parameter.Name, new ConstructorParameterMap(typeMap, parameter, sourceMembers.ToArray())); + return; } - public bool ApplyIncludedMember(IncludedMember includedMember) + _ctorParams.Add(parameter.Name, new ConstructorParameterMap(typeMap, parameter, sourceMembers.ToArray())); + } + public bool ApplyIncludedMember(IncludedMember includedMember) + { + var typeMap = includedMember.TypeMap; + if (CanResolve || typeMap.ConstructorMap == null) + { + return false; + } + bool canResolve = false; + foreach (var includedParam in typeMap.ConstructorMap._ctorParams.Values) { - var typeMap = includedMember.TypeMap; - if (CanResolve || typeMap.ConstructorMap == null) + if (!includedParam.CanResolveValue) { - return false; + continue; } - bool canResolve = false; - foreach (var includedParam in typeMap.ConstructorMap._ctorParams.Values) + var name = includedParam.DestinationName; + if (_ctorParams.TryGetValue(name, out var existingParam) && existingParam.CanResolveValue) { - if (!includedParam.CanResolveValue) - { - continue; - } - var name = includedParam.DestinationName; - if (_ctorParams.TryGetValue(name, out var existingParam) && existingParam.CanResolveValue) - { - continue; - } - canResolve = true; - _canResolve = null; - _ctorParams[name] = new ConstructorParameterMap(includedParam, includedMember); + continue; } - return canResolve; + canResolve = true; + _canResolve = null; + _ctorParams[name] = new ConstructorParameterMap(includedParam, includedMember); } + return canResolve; } - [EditorBrowsable(EditorBrowsableState.Never)] - public class ConstructorParameterMap : MemberMap +} +[EditorBrowsable(EditorBrowsableState.Never)] +public class ConstructorParameterMap : MemberMap +{ + private Type _sourceType; + public ConstructorParameterMap(TypeMap typeMap, ParameterInfo parameter, MemberInfo[] sourceMembers) : base(typeMap) { - private Type _sourceType; - public ConstructorParameterMap(TypeMap typeMap, ParameterInfo parameter, MemberInfo[] sourceMembers) : base(typeMap) + Parameter = parameter; + if (sourceMembers.Length > 0) { - Parameter = parameter; - if (sourceMembers.Length > 0) - { - MapByConvention(sourceMembers); - } - else - { - SourceMembers = Array.Empty(); - } + MapByConvention(sourceMembers); + } + else + { + SourceMembers = Array.Empty(); } - public ConstructorParameterMap(ConstructorParameterMap parameterMap, IncludedMember includedMember) : - this(includedMember.TypeMap, parameterMap.Parameter, parameterMap.SourceMembers) => - IncludedMember = includedMember.Chain(parameterMap.IncludedMember); - public ParameterInfo Parameter { get; } - public override Type SourceType => _sourceType ??= GetSourceType(); - public override Type DestinationType => Parameter.ParameterType; - public override IncludedMember IncludedMember { get; } - public override MemberInfo[] SourceMembers { get; set; } - public override string DestinationName => Parameter.Name; - public Expression DefaultValue(IGlobalConfiguration configuration) => Parameter.IsOptional ? Parameter.GetDefaultValue(configuration) : configuration.Default(DestinationType); - public override string ToString() => $"{Constructor.DeclaringType} {Constructor}, parameter {DestinationName}"; - private MemberInfo Constructor => Parameter.Member; } + public ConstructorParameterMap(ConstructorParameterMap parameterMap, IncludedMember includedMember) : + this(includedMember.TypeMap, parameterMap.Parameter, parameterMap.SourceMembers) => + IncludedMember = includedMember.Chain(parameterMap.IncludedMember); + public ParameterInfo Parameter { get; } + public override Type SourceType => _sourceType ??= GetSourceType(); + public override Type DestinationType => Parameter.ParameterType; + public override IncludedMember IncludedMember { get; } + public override MemberInfo[] SourceMembers { get; set; } + public override string DestinationName => Parameter.Name; + public Expression DefaultValue(IGlobalConfiguration configuration) => Parameter.IsOptional ? Parameter.GetDefaultValue(configuration) : configuration.Default(DestinationType); + public override string ToString() => $"{Constructor.DeclaringType} {Constructor}, parameter {DestinationName}"; + private MemberInfo Constructor => Parameter.Member; } \ No newline at end of file diff --git a/src/AutoMapper/Execution/ExpressionBuilder.cs b/src/AutoMapper/Execution/ExpressionBuilder.cs index ead369ab4c..aee4e7f484 100644 --- a/src/AutoMapper/Execution/ExpressionBuilder.cs +++ b/src/AutoMapper/Execution/ExpressionBuilder.cs @@ -7,457 +7,456 @@ using System.ComponentModel; using System.Runtime.CompilerServices; using System.Collections.ObjectModel; -namespace AutoMapper.Execution +namespace AutoMapper.Execution; + +using Internal; +using static Expression; +using static Internal.ReflectionHelper; +[EditorBrowsable(EditorBrowsableState.Never)] +public static class ExpressionBuilder { - using Internal; - using static Expression; - using static Internal.ReflectionHelper; - [EditorBrowsable(EditorBrowsableState.Never)] - public static class ExpressionBuilder + public static readonly MethodInfo ObjectToString = typeof(object).GetMethod(nameof(object.ToString)); + private static readonly MethodInfo DisposeMethod = typeof(IDisposable).GetMethod(nameof(IDisposable.Dispose)); + public static readonly Expression True = Constant(true, typeof(bool)); + public static readonly Expression Null = Constant(null, typeof(object)); + public static readonly Expression Empty = Empty(); + public static readonly Expression Zero = Constant(0, typeof(int)); + public static readonly ParameterExpression ExceptionParameter = Parameter(typeof(Exception), "ex"); + public static readonly ParameterExpression ContextParameter = Parameter(typeof(ResolutionContext), "context"); + public static readonly MethodInfo IListClear = typeof(IList).GetMethod(nameof(IList.Clear)); + public static readonly MethodInfo IListAdd = typeof(IList).GetMethod(nameof(IList.Add)); + public static readonly MethodInfo IncTypeDepthInfo = typeof(ResolutionContext).GetInstanceMethod(nameof(ResolutionContext.IncrementTypeDepth)); + public static readonly MethodInfo DecTypeDepthInfo = typeof(ResolutionContext).GetInstanceMethod(nameof(ResolutionContext.DecrementTypeDepth)); + private static readonly MethodInfo ContextCreate = typeof(ResolutionContext).GetInstanceMethod(nameof(ResolutionContext.CreateInstance)); + public static readonly MethodInfo OverTypeDepthMethod = typeof(ResolutionContext).GetInstanceMethod(nameof(ResolutionContext.OverTypeDepth)); + public static readonly MethodInfo CacheDestinationMethod = typeof(ResolutionContext).GetInstanceMethod(nameof(ResolutionContext.CacheDestination)); + public static readonly MethodInfo GetDestinationMethod = typeof(ResolutionContext).GetInstanceMethod(nameof(ResolutionContext.GetDestination)); + private static readonly MethodCallExpression CheckContextCall = Expression.Call( + typeof(ResolutionContext).GetStaticMethod(nameof(ResolutionContext.CheckContext)), ContextParameter); + private static readonly MethodInfo ContextMapMethod = typeof(ResolutionContext).GetInstanceMethod(nameof(ResolutionContext.MapInternal)); + private static readonly MethodInfo ArrayEmptyMethod = typeof(Array).GetStaticMethod(nameof(Array.Empty)); + private static readonly ParameterExpression Disposable = Variable(typeof(IDisposable), "disposableEnumerator"); + private static readonly ReadOnlyCollection DisposableArray = Disposable.ToReadOnly(); + private static readonly Expression DisposeCall = IfThen(ReferenceNotEqual(Disposable, Null), Expression.Call(Disposable, DisposeMethod)); + private static readonly ParameterExpression Index = Variable(typeof(int), "sourceArrayIndex"); + private static readonly BinaryExpression ResetIndex = Assign(Index, Zero); + private static readonly UnaryExpression IncrementIndex = PostIncrementAssign(Index); + public static Expression ReplaceParameters(this IGlobalConfiguration configuration, LambdaExpression initialLambda, Expression newParameter) => + configuration.ParameterReplaceVisitor().Replace(initialLambda, newParameter); + public static Expression ReplaceParameters(this IGlobalConfiguration configuration, LambdaExpression initialLambda, Expression[] newParameters) => + configuration.ParameterReplaceVisitor().Replace(initialLambda, newParameters); + public static Expression ConvertReplaceParameters(this IGlobalConfiguration configuration, LambdaExpression initialLambda, Expression newParameter) => + configuration.ConvertParameterReplaceVisitor().Replace(initialLambda, newParameter); + public static Expression ConvertReplaceParameters(this IGlobalConfiguration configuration, LambdaExpression initialLambda, Expression[] newParameters) => + configuration.ConvertParameterReplaceVisitor().Replace(initialLambda, newParameters); + public static DefaultExpression Default(this IGlobalConfiguration configuration, Type type) => + configuration == null ? Expression.Default(type) : configuration.GetDefault(type); + public static (List Variables, List Expressions) Scratchpad(this IGlobalConfiguration configuration) { - public static readonly MethodInfo ObjectToString = typeof(object).GetMethod(nameof(object.ToString)); - private static readonly MethodInfo DisposeMethod = typeof(IDisposable).GetMethod(nameof(IDisposable.Dispose)); - public static readonly Expression True = Constant(true, typeof(bool)); - public static readonly Expression Null = Constant(null, typeof(object)); - public static readonly Expression Empty = Empty(); - public static readonly Expression Zero = Constant(0, typeof(int)); - public static readonly ParameterExpression ExceptionParameter = Parameter(typeof(Exception), "ex"); - public static readonly ParameterExpression ContextParameter = Parameter(typeof(ResolutionContext), "context"); - public static readonly MethodInfo IListClear = typeof(IList).GetMethod(nameof(IList.Clear)); - public static readonly MethodInfo IListAdd = typeof(IList).GetMethod(nameof(IList.Add)); - public static readonly MethodInfo IncTypeDepthInfo = typeof(ResolutionContext).GetInstanceMethod(nameof(ResolutionContext.IncrementTypeDepth)); - public static readonly MethodInfo DecTypeDepthInfo = typeof(ResolutionContext).GetInstanceMethod(nameof(ResolutionContext.DecrementTypeDepth)); - private static readonly MethodInfo ContextCreate = typeof(ResolutionContext).GetInstanceMethod(nameof(ResolutionContext.CreateInstance)); - public static readonly MethodInfo OverTypeDepthMethod = typeof(ResolutionContext).GetInstanceMethod(nameof(ResolutionContext.OverTypeDepth)); - public static readonly MethodInfo CacheDestinationMethod = typeof(ResolutionContext).GetInstanceMethod(nameof(ResolutionContext.CacheDestination)); - public static readonly MethodInfo GetDestinationMethod = typeof(ResolutionContext).GetInstanceMethod(nameof(ResolutionContext.GetDestination)); - private static readonly MethodCallExpression CheckContextCall = Expression.Call( - typeof(ResolutionContext).GetStaticMethod(nameof(ResolutionContext.CheckContext)), ContextParameter); - private static readonly MethodInfo ContextMapMethod = typeof(ResolutionContext).GetInstanceMethod(nameof(ResolutionContext.MapInternal)); - private static readonly MethodInfo ArrayEmptyMethod = typeof(Array).GetStaticMethod(nameof(Array.Empty)); - private static readonly ParameterExpression Disposable = Variable(typeof(IDisposable), "disposableEnumerator"); - private static readonly ReadOnlyCollection DisposableArray = Disposable.ToReadOnly(); - private static readonly Expression DisposeCall = IfThen(ReferenceNotEqual(Disposable, Null), Expression.Call(Disposable, DisposeMethod)); - private static readonly ParameterExpression Index = Variable(typeof(int), "sourceArrayIndex"); - private static readonly BinaryExpression ResetIndex = Assign(Index, Zero); - private static readonly UnaryExpression IncrementIndex = PostIncrementAssign(Index); - public static Expression ReplaceParameters(this IGlobalConfiguration configuration, LambdaExpression initialLambda, Expression newParameter) => - configuration.ParameterReplaceVisitor().Replace(initialLambda, newParameter); - public static Expression ReplaceParameters(this IGlobalConfiguration configuration, LambdaExpression initialLambda, Expression[] newParameters) => - configuration.ParameterReplaceVisitor().Replace(initialLambda, newParameters); - public static Expression ConvertReplaceParameters(this IGlobalConfiguration configuration, LambdaExpression initialLambda, Expression newParameter) => - configuration.ConvertParameterReplaceVisitor().Replace(initialLambda, newParameter); - public static Expression ConvertReplaceParameters(this IGlobalConfiguration configuration, LambdaExpression initialLambda, Expression[] newParameters) => - configuration.ConvertParameterReplaceVisitor().Replace(initialLambda, newParameters); - public static DefaultExpression Default(this IGlobalConfiguration configuration, Type type) => - configuration == null ? Expression.Default(type) : configuration.GetDefault(type); - public static (List Variables, List Expressions) Scratchpad(this IGlobalConfiguration configuration) + var variables = configuration?.Variables; + if (variables == null) { - var variables = configuration?.Variables; - if (variables == null) - { - variables = new(); - } - else + variables = new(); + } + else + { + variables.Clear(); + } + var expressions = configuration?.Expressions; + if (expressions == null) + { + expressions = new(); + } + else + { + expressions.Clear(); + } + return (variables, expressions); + } + public static Expression MapExpression(this IGlobalConfiguration configuration, ProfileMap profileMap, TypePair typePair, Expression source, + MemberMap memberMap = null, Expression destination = null) + { + destination ??= configuration.Default(typePair.DestinationType); + var typeMap = configuration.ResolveTypeMap(typePair); + Expression mapExpression = null; + bool nullCheck; + if (typeMap != null) + { + var allowNull = memberMap?.AllowNull; + nullCheck = !typeMap.HasTypeConverter && allowNull.HasValue && allowNull != profileMap.AllowNullDestinationValues; + if (!typeMap.HasDerivedTypesToInclude) { - variables.Clear(); + typeMap.Seal(configuration); + if (typeMap.MapExpression != null) + { + mapExpression = typeMap.Invoke(source, destination); + } } - var expressions = configuration?.Expressions; - if (expressions == null) + } + else + { + var mapper = configuration.FindMapper(typePair); + if (mapper != null) { - expressions = new(); + mapExpression = mapper.MapExpression(configuration, profileMap, memberMap, source, destination); + nullCheck = mapExpression != source; + mapExpression = ToType(mapExpression, typePair.DestinationType); } else { - expressions.Clear(); + nullCheck = true; } - return (variables, expressions); } - public static Expression MapExpression(this IGlobalConfiguration configuration, ProfileMap profileMap, TypePair typePair, Expression source, - MemberMap memberMap = null, Expression destination = null) + mapExpression ??= ContextMap(typePair, source, destination, memberMap); + return nullCheck ? configuration.NullCheckSource(profileMap, source, destination, mapExpression, memberMap) : mapExpression; + } + public static Expression NullCheckSource(this IGlobalConfiguration configuration, ProfileMap profileMap, Expression source, Expression destination, + Expression mapExpression, MemberMap memberMap) + { + var sourceType = source.Type; + if (sourceType.IsValueType && !sourceType.IsNullableType()) + { + return mapExpression; + } + var destinationType = destination.Type; + var isCollection = destinationType.IsCollection(); + var mustUseDestination = memberMap is { MustUseDestination: true }; + var ifSourceNull = memberMap == null ? + destination.IfNullElse(DefaultDestination(), ClearDestinationCollection()) : + mustUseDestination ? ClearDestinationCollection() : DefaultDestination(); + return source.IfNullElse(ifSourceNull, mapExpression); + Expression ClearDestinationCollection() { - destination ??= configuration.Default(typePair.DestinationType); - var typeMap = configuration.ResolveTypeMap(typePair); - Expression mapExpression = null; - bool nullCheck; - if (typeMap != null) + if (!isCollection) { - var allowNull = memberMap?.AllowNull; - nullCheck = !typeMap.HasTypeConverter && allowNull.HasValue && allowNull != profileMap.AllowNullDestinationValues; - if (!typeMap.HasDerivedTypesToInclude) - { - typeMap.Seal(configuration); - if (typeMap.MapExpression != null) - { - mapExpression = typeMap.Invoke(source, destination); - } - } + return destination; + } + MethodInfo clearMethod; + var destinationVariable = Variable(destination.Type, "collectionDestination"); + Expression collection = destinationVariable; + if (destinationType.IsListType()) + { + clearMethod = IListClear; } else { - var mapper = configuration.FindMapper(typePair); - if (mapper != null) + var destinationCollectionType = destinationType.GetICollectionType(); + if (destinationCollectionType == null) { - mapExpression = mapper.MapExpression(configuration, profileMap, memberMap, source, destination); - nullCheck = mapExpression != source; - mapExpression = ToType(mapExpression, typePair.DestinationType); - } - else - { - nullCheck = true; + if (!mustUseDestination) + { + return destination; + } + var destinationElementType = GetEnumerableElementType(destinationType); + destinationCollectionType = typeof(ICollection<>).MakeGenericType(destinationElementType); + collection = TypeAs(collection, destinationCollectionType); } + clearMethod = destinationCollectionType.GetMethod("Clear"); } - mapExpression ??= ContextMap(typePair, source, destination, memberMap); - return nullCheck ? configuration.NullCheckSource(profileMap, source, destination, mapExpression, memberMap) : mapExpression; + var (variables, statements) = configuration.Scratchpad(); + variables.Add(destinationVariable); + statements.Add(Assign(destinationVariable, destination)); + statements.Add(IfThen(ReferenceNotEqual(collection, Null), Expression.Call(collection, clearMethod))); + statements.Add(destinationVariable); + return Block(variables, statements); } - public static Expression NullCheckSource(this IGlobalConfiguration configuration, ProfileMap profileMap, Expression source, Expression destination, - Expression mapExpression, MemberMap memberMap) + Expression DefaultDestination() { - var sourceType = source.Type; - if (sourceType.IsValueType && !sourceType.IsNullableType()) - { - return mapExpression; - } - var destinationType = destination.Type; - var isCollection = destinationType.IsCollection(); - var mustUseDestination = memberMap is { MustUseDestination: true }; - var ifSourceNull = memberMap == null ? - destination.IfNullElse(DefaultDestination(), ClearDestinationCollection()) : - mustUseDestination ? ClearDestinationCollection() : DefaultDestination(); - return source.IfNullElse(ifSourceNull, mapExpression); - Expression ClearDestinationCollection() + if ((isCollection && profileMap.AllowsNullCollectionsFor(memberMap)) || (!isCollection && profileMap.AllowsNullDestinationValuesFor(memberMap))) { - if (!isCollection) - { - return destination; - } - MethodInfo clearMethod; - var destinationVariable = Variable(destination.Type, "collectionDestination"); - Expression collection = destinationVariable; - if (destinationType.IsListType()) - { - clearMethod = IListClear; - } - else - { - var destinationCollectionType = destinationType.GetICollectionType(); - if (destinationCollectionType == null) - { - if (!mustUseDestination) - { - return destination; - } - var destinationElementType = GetEnumerableElementType(destinationType); - destinationCollectionType = typeof(ICollection<>).MakeGenericType(destinationElementType); - collection = TypeAs(collection, destinationCollectionType); - } - clearMethod = destinationCollectionType.GetMethod("Clear"); - } - var (variables, statements) = configuration.Scratchpad(); - variables.Add(destinationVariable); - statements.Add(Assign(destinationVariable, destination)); - statements.Add(IfThen(ReferenceNotEqual(collection, Null), Expression.Call(collection, clearMethod))); - statements.Add(destinationVariable); - return Block(variables, statements); + return destination.NodeType == ExpressionType.Default ? destination : configuration.Default(destinationType); } - Expression DefaultDestination() + if (destinationType.IsArray) { - if ((isCollection && profileMap.AllowsNullCollectionsFor(memberMap)) || (!isCollection && profileMap.AllowsNullDestinationValuesFor(memberMap))) - { - return destination.NodeType == ExpressionType.Default ? destination : configuration.Default(destinationType); - } - if (destinationType.IsArray) - { - var destinationElementType = destinationType.GetElementType(); - var rank = destinationType.GetArrayRank(); - return rank == 1 ? - Expression.Call(ArrayEmptyMethod.MakeGenericMethod(destinationElementType)) : - NewArrayBounds(destinationElementType, Enumerable.Repeat(Zero, rank)); - } - return ObjectFactory.GenerateConstructorExpression(destinationType, configuration); + var destinationElementType = destinationType.GetElementType(); + var rank = destinationType.GetArrayRank(); + return rank == 1 ? + Expression.Call(ArrayEmptyMethod.MakeGenericMethod(destinationElementType)) : + NewArrayBounds(destinationElementType, Enumerable.Repeat(Zero, rank)); } + return ObjectFactory.GenerateConstructorExpression(destinationType, configuration); } - public static Expression ServiceLocator(Type type) => Expression.Call(ContextParameter, ContextCreate, Constant(type)); - public static Expression ContextMap(TypePair typePair, Expression sourceParameter, Expression destinationParameter, MemberMap memberMap) + } + public static Expression ServiceLocator(Type type) => Expression.Call(ContextParameter, ContextCreate, Constant(type)); + public static Expression ContextMap(TypePair typePair, Expression sourceParameter, Expression destinationParameter, MemberMap memberMap) + { + var mapMethod = ContextMapMethod.MakeGenericMethod(typePair.SourceType, typePair.DestinationType); + return Expression.Call(ContextParameter, mapMethod, sourceParameter, destinationParameter, Constant(memberMap, typeof(MemberMap))); + } + public static Expression CheckContext(TypeMap typeMap) + { + if (typeMap.MaxDepth > 0 || typeMap.PreserveReferences) { - var mapMethod = ContextMapMethod.MakeGenericMethod(typePair.SourceType, typePair.DestinationType); - return Expression.Call(ContextParameter, mapMethod, sourceParameter, destinationParameter, Constant(memberMap, typeof(MemberMap))); + return CheckContextCall; } - public static Expression CheckContext(TypeMap typeMap) + return null; + } + public static Expression OverMaxDepth(TypeMap typeMap) => typeMap?.MaxDepth > 0 ? Expression.Call(ContextParameter, OverTypeDepthMethod, Constant(typeMap)) : null; + public static Expression NullSubstitute(this MemberMap memberMap, Expression sourceExpression) => + Coalesce(sourceExpression, ToType(Constant(memberMap.NullSubstitute), sourceExpression.Type)); + public static Expression ApplyTransformers(this MemberMap memberMap, Expression source, IGlobalConfiguration configuration) + { + var perMember = memberMap.ValueTransformers; + var perMap = memberMap.TypeMap.ValueTransformers; + var perProfile = memberMap.TypeMap.Profile.ValueTransformers; + if (perMember.Count == 0 && perMap.Count == 0 && perProfile.Count == 0) { - if (typeMap.MaxDepth > 0 || typeMap.PreserveReferences) - { - return CheckContextCall; - } - return null; + return source; } - public static Expression OverMaxDepth(TypeMap typeMap) => typeMap?.MaxDepth > 0 ? Expression.Call(ContextParameter, OverTypeDepthMethod, Constant(typeMap)) : null; - public static Expression NullSubstitute(this MemberMap memberMap, Expression sourceExpression) => - Coalesce(sourceExpression, ToType(Constant(memberMap.NullSubstitute), sourceExpression.Type)); - public static Expression ApplyTransformers(this MemberMap memberMap, Expression source, IGlobalConfiguration configuration) + var transformers = perMember.Concat(perMap).Concat(perProfile); + return memberMap.ApplyTransformers(source, configuration, transformers); + } + static Expression ApplyTransformers(this MemberMap memberMap, Expression source, IGlobalConfiguration configuration, IEnumerable transformers) => + transformers.Where(vt => vt.IsMatch(memberMap)).Aggregate(source, (current, vtConfig) => + ToType(configuration.ReplaceParameters(vtConfig.TransformerExpression, ToType(current, vtConfig.ValueType)), memberMap.DestinationType)); + public static LambdaExpression Lambda(this MemberInfo member) => new[] { member }.Lambda(); + public static LambdaExpression Lambda(this MemberInfo[] members) + { + var source = Parameter(members[0].DeclaringType, "source"); + return Expression.Lambda(members.Chain(source), source); + } + public static Expression Chain(this MemberInfo[] members, Expression target) + { + foreach (var member in members) { - var perMember = memberMap.ValueTransformers; - var perMap = memberMap.TypeMap.ValueTransformers; - var perProfile = memberMap.TypeMap.Profile.ValueTransformers; - if (perMember.Count == 0 && perMap.Count == 0 && perProfile.Count == 0) + target = member switch { - return source; - } - var transformers = perMember.Concat(perMap).Concat(perProfile); - return memberMap.ApplyTransformers(source, configuration, transformers); + PropertyInfo property => Expression.Property(target, property), + MethodInfo { IsStatic: true } getter => Expression.Call(getter, target), + FieldInfo field => Field(target, field), + MethodInfo getter => Expression.Call(target, getter), + _ => throw new ArgumentOutOfRangeException(nameof(member), member, "Unexpected member.") + }; } - static Expression ApplyTransformers(this MemberMap memberMap, Expression source, IGlobalConfiguration configuration, IEnumerable transformers) => - transformers.Where(vt => vt.IsMatch(memberMap)).Aggregate(source, (current, vtConfig) => - ToType(configuration.ReplaceParameters(vtConfig.TransformerExpression, ToType(current, vtConfig.ValueType)), memberMap.DestinationType)); - public static LambdaExpression Lambda(this MemberInfo member) => new[] { member }.Lambda(); - public static LambdaExpression Lambda(this MemberInfo[] members) + return target; + } + public static MemberInfo[] GetMembersChain(this LambdaExpression lambda) => lambda.Body.GetChain().ToMemberInfos(); + public static MemberInfo GetMember(this LambdaExpression lambda) => + (lambda?.Body is MemberExpression memberExpression && memberExpression.Expression == lambda.Parameters[0]) ? memberExpression.Member : null; + public static MemberInfo[] ToMemberInfos(this Stack chain) + { + var members = new MemberInfo[chain.Count]; + int index = 0; + foreach (var member in chain) { - var source = Parameter(members[0].DeclaringType, "source"); - return Expression.Lambda(members.Chain(source), source); + members[index++] = member.MemberInfo; } - public static Expression Chain(this MemberInfo[] members, Expression target) + return members; + } + public static Stack GetChain(this Expression expression) + { + var stack = new Stack(); + while (expression != null) { - foreach (var member in members) + var member = expression switch { - target = member switch - { - PropertyInfo property => Expression.Property(target, property), - MethodInfo { IsStatic: true } getter => Expression.Call(getter, target), - FieldInfo field => Field(target, field), - MethodInfo getter => Expression.Call(target, getter), - _ => throw new ArgumentOutOfRangeException(nameof(member), member, "Unexpected member.") - }; - } - return target; - } - public static MemberInfo[] GetMembersChain(this LambdaExpression lambda) => lambda.Body.GetChain().ToMemberInfos(); - public static MemberInfo GetMember(this LambdaExpression lambda) => - (lambda?.Body is MemberExpression memberExpression && memberExpression.Expression == lambda.Parameters[0]) ? memberExpression.Member : null; - public static MemberInfo[] ToMemberInfos(this Stack chain) - { - var members = new MemberInfo[chain.Count]; - int index = 0; - foreach (var member in chain) + MemberExpression { Expression: Expression target, Member: MemberInfo propertyOrField } => + new Member(expression, propertyOrField, target), + MethodCallExpression { Method: var instanceMethod, Object: Expression target } => + new Member(expression, instanceMethod, target), + MethodCallExpression { Method: var extensionMethod, Arguments: { Count: > 0 } arguments } when extensionMethod.Has() => + new Member(expression, extensionMethod, arguments[0]), + _ => default + }; + if (member.Expression == null) { - members[index++] = member.MemberInfo; + break; } - return members; + stack.Push(member); + expression = member.Target; } - public static Stack GetChain(this Expression expression) + return stack; + } + public static IEnumerable GetMemberExpressions(this Expression expression) + { + if (expression is not MemberExpression memberExpression) { - var stack = new Stack(); - while (expression != null) - { - var member = expression switch - { - MemberExpression { Expression: Expression target, Member: MemberInfo propertyOrField } => - new Member(expression, propertyOrField, target), - MethodCallExpression { Method: var instanceMethod, Object: Expression target } => - new Member(expression, instanceMethod, target), - MethodCallExpression { Method: var extensionMethod, Arguments: { Count: > 0 } arguments } when extensionMethod.Has() => - new Member(expression, extensionMethod, arguments[0]), - _ => default - }; - if (member.Expression == null) - { - break; - } - stack.Push(member); - expression = member.Target; - } - return stack; + return Array.Empty(); } - public static IEnumerable GetMemberExpressions(this Expression expression) + return expression.GetChain().Select(m => m.Expression as MemberExpression).TakeWhile(m => m != null); + } + public static bool IsMemberPath(this LambdaExpression lambda, out Stack members) + { + Expression currentExpression = null; + members = lambda.Body.GetChain(); + foreach (var member in members) { - if (expression is not MemberExpression memberExpression) + currentExpression = member.Expression; + if (currentExpression is not MemberExpression) { - return Array.Empty(); + return false; } - return expression.GetChain().Select(m => m.Expression as MemberExpression).TakeWhile(m => m != null); } - public static bool IsMemberPath(this LambdaExpression lambda, out Stack members) + return currentExpression == lambda.Body; + } + public static LambdaExpression MemberAccessLambda(Type type, string memberPath, TypeMap typeMap) => + GetMemberPath(type, memberPath, typeMap).Lambda(); + public static Expression ForEach(List variables, List statements, ParameterExpression loopVar, Expression collection, Expression loopContent) + { + if (collection.Type.IsArray) { - Expression currentExpression = null; - members = lambda.Body.GetChain(); - foreach (var member in members) - { - currentExpression = member.Expression; - if (currentExpression is not MemberExpression) - { - return false; - } - } - return currentExpression == lambda.Body; + return ForEachArrayItem(variables, statements, loopVar, collection, loopContent); } - public static LambdaExpression MemberAccessLambda(Type type, string memberPath, TypeMap typeMap) => - GetMemberPath(type, memberPath, typeMap).Lambda(); - public static Expression ForEach(List variables, List statements, ParameterExpression loopVar, Expression collection, Expression loopContent) + var getEnumeratorCall = Call(collection, "GetEnumerator"); + var enumeratorVar = Variable(getEnumeratorCall.Type, "enumerator"); + var breakLabel = Label("LoopBreak"); + var usingEnumerator = Using(statements, enumeratorVar, + Loop( + IfThenElse( + Call(enumeratorVar, "MoveNext"), + Block(Assign(loopVar, ToType(Property(enumeratorVar, "Current"), loopVar.Type)), loopContent), + Break(breakLabel) + ), + breakLabel)); + statements.Clear(); + variables.Add(enumeratorVar); + variables.Add(loopVar); + statements.Add(Assign(enumeratorVar, getEnumeratorCall)); + statements.Add(usingEnumerator); + return Block(variables, statements); + static Expression ForEachArrayItem(List variables, List statements, ParameterExpression loopVar, Expression array, Expression loopContent) { - if (collection.Type.IsArray) - { - return ForEachArrayItem(variables, statements, loopVar, collection, loopContent); - } - var getEnumeratorCall = Call(collection, "GetEnumerator"); - var enumeratorVar = Variable(getEnumeratorCall.Type, "enumerator"); var breakLabel = Label("LoopBreak"); - var usingEnumerator = Using(statements, enumeratorVar, - Loop( - IfThenElse( - Call(enumeratorVar, "MoveNext"), - Block(Assign(loopVar, ToType(Property(enumeratorVar, "Current"), loopVar.Type)), loopContent), - Break(breakLabel) - ), - breakLabel)); - statements.Clear(); - variables.Add(enumeratorVar); + variables.Add(Index); variables.Add(loopVar); - statements.Add(Assign(enumeratorVar, getEnumeratorCall)); - statements.Add(usingEnumerator); + statements.Add(ResetIndex); + statements.Add(Loop( + IfThenElse( + LessThan(Index, ArrayLength(array)), + Block(Assign(loopVar, ArrayIndex(array, Index)), loopContent, IncrementIndex), + Break(breakLabel) + ), + breakLabel)); return Block(variables, statements); - static Expression ForEachArrayItem(List variables, List statements, ParameterExpression loopVar, Expression array, Expression loopContent) + } + static Expression Using(List statements, Expression target, Expression body) + { + Expression finallyDispose; + if (typeof(IDisposable).IsAssignableFrom(target.Type)) { - var breakLabel = Label("LoopBreak"); - variables.Add(Index); - variables.Add(loopVar); - statements.Add(ResetIndex); - statements.Add(Loop( - IfThenElse( - LessThan(Index, ArrayLength(array)), - Block(Assign(loopVar, ArrayIndex(array, Index)), loopContent, IncrementIndex), - Break(breakLabel) - ), - breakLabel)); - return Block(variables, statements); + finallyDispose = Expression.Call(target, DisposeMethod); } - static Expression Using(List statements, Expression target, Expression body) + else { - Expression finallyDispose; - if (typeof(IDisposable).IsAssignableFrom(target.Type)) + if (target.Type.IsValueType) { - finallyDispose = Expression.Call(target, DisposeMethod); - } - else - { - if (target.Type.IsValueType) - { - return body; - } - var assignDisposable = Assign(Disposable, TypeAs(target, typeof(IDisposable))); - statements.Add(assignDisposable); - statements.Add(DisposeCall); - finallyDispose = Block(DisposableArray, statements); + return body; } - return TryFinally(body, finallyDispose); + var assignDisposable = Assign(Disposable, TypeAs(target, typeof(IDisposable))); + statements.Add(assignDisposable); + statements.Add(DisposeCall); + finallyDispose = Block(DisposableArray, statements); } + return TryFinally(body, finallyDispose); } - // Expression.Property(string) is inefficient because it does a case insensitive match - public static MemberExpression Property(Expression target, string name) => - Expression.Property(target, target.Type.GetInheritedProperty(name)); - // Expression.Call(string) is inefficient because it does a case insensitive match - public static MethodCallExpression Call(Expression target, string name) => Expression.Call(target, target.Type.GetInheritedMethod(name)); - public static MethodCallExpression Call(Expression target, string name, Expression[] arguments) => - Expression.Call(target, target.Type.GetInheritedMethod(name), arguments); - public static Expression ToObject(this Expression expression) => expression.Type.IsValueType ? Convert(expression, typeof(object)) : expression; - public static Expression ToType(Expression expression, Type type) => expression.Type == type ? expression : Convert(expression, type); - public static Expression ReplaceParameters(this LambdaExpression initialLambda, Expression newParameter) => - new ParameterReplaceVisitor().Replace(initialLambda, newParameter); - private static Expression Replace(this ParameterReplaceVisitor visitor, LambdaExpression initialLambda, Expression newParameter) => - visitor.Replace(initialLambda.Body, initialLambda.Parameters[0], newParameter); - private static Expression Replace(this ParameterReplaceVisitor visitor, LambdaExpression initialLambda, Expression[] newParameters) + } + // Expression.Property(string) is inefficient because it does a case insensitive match + public static MemberExpression Property(Expression target, string name) => + Expression.Property(target, target.Type.GetInheritedProperty(name)); + // Expression.Call(string) is inefficient because it does a case insensitive match + public static MethodCallExpression Call(Expression target, string name) => Expression.Call(target, target.Type.GetInheritedMethod(name)); + public static MethodCallExpression Call(Expression target, string name, Expression[] arguments) => + Expression.Call(target, target.Type.GetInheritedMethod(name), arguments); + public static Expression ToObject(this Expression expression) => expression.Type.IsValueType ? Convert(expression, typeof(object)) : expression; + public static Expression ToType(Expression expression, Type type) => expression.Type == type ? expression : Convert(expression, type); + public static Expression ReplaceParameters(this LambdaExpression initialLambda, Expression newParameter) => + new ParameterReplaceVisitor().Replace(initialLambda, newParameter); + private static Expression Replace(this ParameterReplaceVisitor visitor, LambdaExpression initialLambda, Expression newParameter) => + visitor.Replace(initialLambda.Body, initialLambda.Parameters[0], newParameter); + private static Expression Replace(this ParameterReplaceVisitor visitor, LambdaExpression initialLambda, Expression[] newParameters) + { + var newLambda = initialLambda.Body; + for (var i = 0; i < Math.Min(newParameters.Length, initialLambda.Parameters.Count); i++) { - var newLambda = initialLambda.Body; - for (var i = 0; i < Math.Min(newParameters.Length, initialLambda.Parameters.Count); i++) - { - newLambda = visitor.Replace(newLambda, initialLambda.Parameters[i], newParameters[i]); - } - return newLambda; + newLambda = visitor.Replace(newLambda, initialLambda.Parameters[i], newParameters[i]); + } + return newLambda; + } + public static Expression Replace(this Expression exp, Expression old, Expression replace) => new ReplaceVisitor().Replace(exp, old, replace); + public static Expression NullCheck(this Expression expression, IGlobalConfiguration configuration, MemberMap memberMap = null, Expression defaultValue = null) + { + var chain = expression.GetChain(); + var min = memberMap?.IncludedMember == null ? 2 : 1; + if (chain.Count < min || chain.Peek().Target is not ParameterExpression parameter) + { + return expression; } - public static Expression Replace(this Expression exp, Expression old, Expression replace) => new ReplaceVisitor().Replace(exp, old, replace); - public static Expression NullCheck(this Expression expression, IGlobalConfiguration configuration, MemberMap memberMap = null, Expression defaultValue = null) + var destinationType = memberMap?.DestinationType; + var returnType = (destinationType != null && destinationType != expression.Type && Nullable.GetUnderlyingType(destinationType) == expression.Type) ? + destinationType : expression.Type; + var defaultReturn = (defaultValue is { NodeType: ExpressionType.Default } && defaultValue.Type == returnType) ? defaultValue : configuration.Default(returnType); + List variables = null; + List expressions = null; + var name = parameter.Name; + var nullCheckedExpression = NullCheck(parameter); + if (variables == null) { - var chain = expression.GetChain(); - var min = memberMap?.IncludedMember == null ? 2 : 1; - if (chain.Count < min || chain.Peek().Target is not ParameterExpression parameter) + return nullCheckedExpression; + } + expressions.Add(nullCheckedExpression); + return Block(variables, expressions); + Expression NullCheck(Expression variable) + { + var member = chain.Pop(); + var skipNullCheck = min == 2 && variable == parameter; + if (chain.Count == 0) { - return expression; + var updated = UpdateTarget(expression, variable); + return skipNullCheck ? updated : variable.IfNullElse(defaultReturn, updated); } - var destinationType = memberMap?.DestinationType; - var returnType = (destinationType != null && destinationType != expression.Type && Nullable.GetUnderlyingType(destinationType) == expression.Type) ? - destinationType : expression.Type; - var defaultReturn = (defaultValue is { NodeType: ExpressionType.Default } && defaultValue.Type == returnType) ? defaultValue : configuration.Default(returnType); - List variables = null; - List expressions = null; - var name = parameter.Name; - var nullCheckedExpression = NullCheck(parameter); if (variables == null) { - return nullCheckedExpression; - } - expressions.Add(nullCheckedExpression); - return Block(variables, expressions); - Expression NullCheck(Expression variable) - { - var member = chain.Pop(); - var skipNullCheck = min == 2 && variable == parameter; - if (chain.Count == 0) - { - var updated = UpdateTarget(expression, variable); - return skipNullCheck ? updated : variable.IfNullElse(defaultReturn, updated); - } - if (variables == null) - { - (variables, expressions) = configuration.Scratchpad(); - } - name += member.MemberInfo.Name; - var newVariable = Variable(member.Expression.Type, name); - variables.Add(newVariable); - var assignment = Assign(newVariable, UpdateTarget(member.Expression, variable)); - var block = Block(assignment, NullCheck(newVariable)); - return skipNullCheck ? block : variable.IfNullElse(defaultReturn, block); - } - static Expression UpdateTarget(Expression sourceExpression, Expression newTarget) => sourceExpression switch - { - MemberExpression memberExpression => memberExpression.Update(newTarget), - MethodCallExpression { Object: null, Arguments: var args } methodCall when args[0] != newTarget => - ExtensionMethod(methodCall.Method, newTarget, args), - MethodCallExpression { Object: Expression target } methodCall when target != newTarget => - Expression.Call(newTarget, methodCall.Method, methodCall.Arguments), - _ => sourceExpression, - }; - static MethodCallExpression ExtensionMethod(MethodInfo method, Expression newTarget, ReadOnlyCollection args) - { - var newArgs = args.ToArray(); - newArgs[0] = newTarget; - return Expression.Call(method, newArgs); + (variables, expressions) = configuration.Scratchpad(); } + name += member.MemberInfo.Name; + var newVariable = Variable(member.Expression.Type, name); + variables.Add(newVariable); + var assignment = Assign(newVariable, UpdateTarget(member.Expression, variable)); + var block = Block(assignment, NullCheck(newVariable)); + return skipNullCheck ? block : variable.IfNullElse(defaultReturn, block); } - public static Expression IfNullElse(this Expression expression, Expression then, Expression @else) => expression.Type.IsValueType ? - (expression.Type.IsNullableType() ? Condition(Property(expression, "HasValue"), ToType(@else, then.Type), then) : @else) : - Condition(ReferenceEqual(expression, Null), then, ToType(@else, then.Type)); - } - public readonly record struct Member(Expression Expression, MemberInfo MemberInfo, Expression Target); - public class ReplaceVisitorBase : ExpressionVisitor - { - private protected Expression _oldNode; - private protected Expression _newNode; - public virtual Expression Replace(Expression target, Expression oldNode, Expression newNode) + static Expression UpdateTarget(Expression sourceExpression, Expression newTarget) => sourceExpression switch { - _oldNode = oldNode; - _newNode = newNode; - return base.Visit(target); + MemberExpression memberExpression => memberExpression.Update(newTarget), + MethodCallExpression { Object: null, Arguments: var args } methodCall when args[0] != newTarget => + ExtensionMethod(methodCall.Method, newTarget, args), + MethodCallExpression { Object: Expression target } methodCall when target != newTarget => + Expression.Call(newTarget, methodCall.Method, methodCall.Arguments), + _ => sourceExpression, + }; + static MethodCallExpression ExtensionMethod(MethodInfo method, Expression newTarget, ReadOnlyCollection args) + { + var newArgs = args.ToArray(); + newArgs[0] = newTarget; + return Expression.Call(method, newArgs); } } - public class ReplaceVisitor : ReplaceVisitorBase - { - public override Expression Visit(Expression node) => _oldNode == node ? _newNode : base.Visit(node); - } - public class ParameterReplaceVisitor : ReplaceVisitorBase - { - protected override Expression VisitParameter(ParameterExpression node) => _oldNode == node ? _newNode : base.VisitParameter(node); - } - public class ConvertParameterReplaceVisitor : ParameterReplaceVisitor + public static Expression IfNullElse(this Expression expression, Expression then, Expression @else) => expression.Type.IsValueType ? + (expression.Type.IsNullableType() ? Condition(Property(expression, "HasValue"), ToType(@else, then.Type), then) : @else) : + Condition(ReferenceEqual(expression, Null), then, ToType(@else, then.Type)); +} +public readonly record struct Member(Expression Expression, MemberInfo MemberInfo, Expression Target); +public class ReplaceVisitorBase : ExpressionVisitor +{ + private protected Expression _oldNode; + private protected Expression _newNode; + public virtual Expression Replace(Expression target, Expression oldNode, Expression newNode) { - public override Expression Replace(Expression target, Expression oldNode, Expression newNode) => - base.Replace(target, oldNode, ExpressionBuilder.ToType(newNode, oldNode.Type)); + _oldNode = oldNode; + _newNode = newNode; + return base.Visit(target); } +} +public class ReplaceVisitor : ReplaceVisitorBase +{ + public override Expression Visit(Expression node) => _oldNode == node ? _newNode : base.Visit(node); +} +public class ParameterReplaceVisitor : ReplaceVisitorBase +{ + protected override Expression VisitParameter(ParameterExpression node) => _oldNode == node ? _newNode : base.VisitParameter(node); +} +public class ConvertParameterReplaceVisitor : ParameterReplaceVisitor +{ + public override Expression Replace(Expression target, Expression oldNode, Expression newNode) => + base.Replace(target, oldNode, ExpressionBuilder.ToType(newNode, oldNode.Type)); } \ No newline at end of file diff --git a/src/AutoMapper/Execution/ObjectFactory.cs b/src/AutoMapper/Execution/ObjectFactory.cs index 4ff4fc3f30..b9a0f71ac8 100644 --- a/src/AutoMapper/Execution/ObjectFactory.cs +++ b/src/AutoMapper/Execution/ObjectFactory.cs @@ -5,56 +5,55 @@ using System.Linq; using System.Linq.Expressions; using AutoMapper.Internal; -namespace AutoMapper.Execution +namespace AutoMapper.Execution; + +using static Expression; +using static ExpressionBuilder; +[EditorBrowsable(EditorBrowsableState.Never)] +public static class ObjectFactory { - using static Expression; - using static ExpressionBuilder; - [EditorBrowsable(EditorBrowsableState.Never)] - public static class ObjectFactory + private static readonly LockingConcurrentDictionary> CtorCache = new(GenerateConstructor); + public static object CreateInstance(Type type) => CtorCache.GetOrAdd(type)(); + private static Func GenerateConstructor(Type type) => + Lambda>(GenerateConstructorExpression(type, null).ToObject()).Compile(); + public static object CreateInterfaceProxy(Type interfaceType) => CreateInstance(ProxyGenerator.GetProxyType(interfaceType)); + public static Expression GenerateConstructorExpression(Type type, IGlobalConfiguration configuration) => type switch { - private static readonly LockingConcurrentDictionary> CtorCache = new(GenerateConstructor); - public static object CreateInstance(Type type) => CtorCache.GetOrAdd(type)(); - private static Func GenerateConstructor(Type type) => - Lambda>(GenerateConstructorExpression(type, null).ToObject()).Compile(); - public static object CreateInterfaceProxy(Type interfaceType) => CreateInstance(ProxyGenerator.GetProxyType(interfaceType)); - public static Expression GenerateConstructorExpression(Type type, IGlobalConfiguration configuration) => type switch - { - { IsValueType: true } => configuration.Default(type), - Type stringType when stringType == typeof(string) => Constant(string.Empty), - { IsInterface: true } => CreateInterfaceExpression(type), - { IsAbstract: true } => InvalidType(type, $"Cannot create an instance of abstract type {type}."), - _ => CallConstructor(type, configuration) - }; - private static Expression CallConstructor(Type type, IGlobalConfiguration configuration) + { IsValueType: true } => configuration.Default(type), + Type stringType when stringType == typeof(string) => Constant(string.Empty), + { IsInterface: true } => CreateInterfaceExpression(type), + { IsAbstract: true } => InvalidType(type, $"Cannot create an instance of abstract type {type}."), + _ => CallConstructor(type, configuration) + }; + private static Expression CallConstructor(Type type, IGlobalConfiguration configuration) + { + var defaultCtor = type.GetConstructor(TypeExtensions.InstanceFlags, null, Type.EmptyTypes, null); + if (defaultCtor != null) { - var defaultCtor = type.GetConstructor(TypeExtensions.InstanceFlags, null, Type.EmptyTypes, null); - if (defaultCtor != null) - { - return New(defaultCtor); - } - var ctorWithOptionalArgs = - (from ctor in type.GetDeclaredConstructors() let args = ctor.GetParameters() where args.All(p => p.IsOptional) select (ctor, args)).FirstOrDefault(); - if (ctorWithOptionalArgs.args == null) - { - return InvalidType(type, $"{type} needs to have a constructor with 0 args or only optional args. Validate your configuration for details."); - } - var arguments = ctorWithOptionalArgs.args.Select(p => p.GetDefaultValue(configuration)); - return New(ctorWithOptionalArgs.ctor, arguments); + return New(defaultCtor); } - private static Expression CreateInterfaceExpression(Type type) => - type.IsGenericType(typeof(IDictionary<,>)) ? CreateCollection(type, typeof(Dictionary<,>)) : - type.IsGenericType(typeof(IReadOnlyDictionary<,>)) ? CreateReadOnlyDictionary(type.GenericTypeArguments) : - type.IsGenericType(typeof(ISet<>)) ? CreateCollection(type, typeof(HashSet<>)) : - type.IsCollection() ? CreateCollection(type, typeof(List<>), GetIEnumerableArguments(type)) : - InvalidType(type, $"Cannot create an instance of interface type {type}."); - private static Type[] GetIEnumerableArguments(Type type) => type.GetIEnumerableType()?.GenericTypeArguments ?? new[] { typeof(object) }; - private static Expression CreateCollection(Type type, Type collectionType, Type[] genericArguments = null) => - ToType(New(collectionType.MakeGenericType(genericArguments ?? type.GenericTypeArguments)), type); - private static Expression CreateReadOnlyDictionary(Type[] typeArguments) + var ctorWithOptionalArgs = + (from ctor in type.GetDeclaredConstructors() let args = ctor.GetParameters() where args.All(p => p.IsOptional) select (ctor, args)).FirstOrDefault(); + if (ctorWithOptionalArgs.args == null) { - var ctor = typeof(ReadOnlyDictionary<,>).MakeGenericType(typeArguments).GetConstructors()[0]; - return New(ctor, New(typeof(Dictionary<,>).MakeGenericType(typeArguments))); + return InvalidType(type, $"{type} needs to have a constructor with 0 args or only optional args. Validate your configuration for details."); } - private static Expression InvalidType(Type type, string message) => Throw(Constant(new ArgumentException(message, "type")), type); + var arguments = ctorWithOptionalArgs.args.Select(p => p.GetDefaultValue(configuration)); + return New(ctorWithOptionalArgs.ctor, arguments); + } + private static Expression CreateInterfaceExpression(Type type) => + type.IsGenericType(typeof(IDictionary<,>)) ? CreateCollection(type, typeof(Dictionary<,>)) : + type.IsGenericType(typeof(IReadOnlyDictionary<,>)) ? CreateReadOnlyDictionary(type.GenericTypeArguments) : + type.IsGenericType(typeof(ISet<>)) ? CreateCollection(type, typeof(HashSet<>)) : + type.IsCollection() ? CreateCollection(type, typeof(List<>), GetIEnumerableArguments(type)) : + InvalidType(type, $"Cannot create an instance of interface type {type}."); + private static Type[] GetIEnumerableArguments(Type type) => type.GetIEnumerableType()?.GenericTypeArguments ?? new[] { typeof(object) }; + private static Expression CreateCollection(Type type, Type collectionType, Type[] genericArguments = null) => + ToType(New(collectionType.MakeGenericType(genericArguments ?? type.GenericTypeArguments)), type); + private static Expression CreateReadOnlyDictionary(Type[] typeArguments) + { + var ctor = typeof(ReadOnlyDictionary<,>).MakeGenericType(typeArguments).GetConstructors()[0]; + return New(ctor, New(typeof(Dictionary<,>).MakeGenericType(typeArguments))); } + private static Expression InvalidType(Type type, string message) => Throw(Constant(new ArgumentException(message, "type")), type); } \ No newline at end of file diff --git a/src/AutoMapper/Execution/ProxyGenerator.cs b/src/AutoMapper/Execution/ProxyGenerator.cs index 5976eac9f9..df72e38203 100644 --- a/src/AutoMapper/Execution/ProxyGenerator.cs +++ b/src/AutoMapper/Execution/ProxyGenerator.cs @@ -7,190 +7,189 @@ using System.Reflection; using System.Reflection.Emit; -namespace AutoMapper.Execution +namespace AutoMapper.Execution; + +public static class ProxyGenerator { - public static class ProxyGenerator + private static readonly MethodInfo DelegateCombine = typeof(Delegate).GetMethod(nameof(Delegate.Combine), new[] { typeof(Delegate), typeof(Delegate) }); + private static readonly MethodInfo DelegateRemove = typeof(Delegate).GetMethod(nameof(Delegate.Remove)); + private static readonly EventInfo PropertyChanged = typeof(INotifyPropertyChanged).GetEvent(nameof(INotifyPropertyChanged.PropertyChanged)); + private static readonly ConstructorInfo ProxyBaseCtor = typeof(ProxyBase).GetConstructor(Type.EmptyTypes); + private static readonly ModuleBuilder ProxyModule = CreateProxyModule(); + private static readonly LockingConcurrentDictionary ProxyTypes = new(EmitProxy); + private static ModuleBuilder CreateProxyModule() + { + var assemblyName = typeof(Mapper).Assembly.GetName(); + assemblyName.Name = "AutoMapper.Proxies.emit"; + var builder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); + return builder.DefineDynamicModule(assemblyName.Name); + } + private static Type EmitProxy(TypeDescription typeDescription) { - private static readonly MethodInfo DelegateCombine = typeof(Delegate).GetMethod(nameof(Delegate.Combine), new[] { typeof(Delegate), typeof(Delegate) }); - private static readonly MethodInfo DelegateRemove = typeof(Delegate).GetMethod(nameof(Delegate.Remove)); - private static readonly EventInfo PropertyChanged = typeof(INotifyPropertyChanged).GetEvent(nameof(INotifyPropertyChanged.PropertyChanged)); - private static readonly ConstructorInfo ProxyBaseCtor = typeof(ProxyBase).GetConstructor(Type.EmptyTypes); - private static readonly ModuleBuilder ProxyModule = CreateProxyModule(); - private static readonly LockingConcurrentDictionary ProxyTypes = new(EmitProxy); - private static ModuleBuilder CreateProxyModule() + var interfaceType = typeDescription.Type; + var typeBuilder = GenerateType(); + GenerateConstructor(); + FieldBuilder propertyChangedField = null; + if (typeof(INotifyPropertyChanged).IsAssignableFrom(interfaceType)) { - var assemblyName = typeof(Mapper).Assembly.GetName(); - assemblyName.Name = "AutoMapper.Proxies.emit"; - var builder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); - return builder.DefineDynamicModule(assemblyName.Name); + GeneratePropertyChanged(); } - private static Type EmitProxy(TypeDescription typeDescription) + GenerateFields(); + return typeBuilder.CreateTypeInfo().AsType(); + TypeBuilder GenerateType() { - var interfaceType = typeDescription.Type; - var typeBuilder = GenerateType(); - GenerateConstructor(); - FieldBuilder propertyChangedField = null; - if (typeof(INotifyPropertyChanged).IsAssignableFrom(interfaceType)) - { - GeneratePropertyChanged(); - } - GenerateFields(); - return typeBuilder.CreateTypeInfo().AsType(); - TypeBuilder GenerateType() - { - var propertyNames = string.Join("_", typeDescription.AdditionalProperties.Select(p => p.Name)); - var typeName = $"Proxy_{interfaceType.FullName}_{typeDescription.GetHashCode()}_{propertyNames}"; - const int MaxTypeNameLength = 1023; - typeName = typeName.Substring(0, Math.Min(MaxTypeNameLength, typeName.Length)); - Debug.WriteLine(typeName, "Emitting proxy type"); - return ProxyModule.DefineType(typeName, - TypeAttributes.Class | TypeAttributes.Sealed | TypeAttributes.Public, typeof(ProxyBase), - interfaceType.IsInterface ? new[] { interfaceType } : Type.EmptyTypes); - } - void GeneratePropertyChanged() - { - propertyChangedField = typeBuilder.DefineField(PropertyChanged.Name, typeof(PropertyChangedEventHandler), FieldAttributes.Private); - EventAccessor(PropertyChanged.AddMethod, DelegateCombine); - EventAccessor(PropertyChanged.RemoveMethod, DelegateRemove); - } - void EventAccessor(MethodInfo method, MethodInfo delegateMethod) - { - var eventAccessor = typeBuilder.DefineMethod(method.Name, - MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | - MethodAttributes.NewSlot | MethodAttributes.Virtual, typeof(void), - new[] { typeof(PropertyChangedEventHandler) }); - var addIl = eventAccessor.GetILGenerator(); - addIl.Emit(OpCodes.Ldarg_0); - addIl.Emit(OpCodes.Dup); - addIl.Emit(OpCodes.Ldfld, propertyChangedField); - addIl.Emit(OpCodes.Ldarg_1); - addIl.Emit(OpCodes.Call, delegateMethod); - addIl.Emit(OpCodes.Castclass, typeof(PropertyChangedEventHandler)); - addIl.Emit(OpCodes.Stfld, propertyChangedField); - addIl.Emit(OpCodes.Ret); - typeBuilder.DefineMethodOverride(eventAccessor, method); - } - void GenerateFields() + var propertyNames = string.Join("_", typeDescription.AdditionalProperties.Select(p => p.Name)); + var typeName = $"Proxy_{interfaceType.FullName}_{typeDescription.GetHashCode()}_{propertyNames}"; + const int MaxTypeNameLength = 1023; + typeName = typeName.Substring(0, Math.Min(MaxTypeNameLength, typeName.Length)); + Debug.WriteLine(typeName, "Emitting proxy type"); + return ProxyModule.DefineType(typeName, + TypeAttributes.Class | TypeAttributes.Sealed | TypeAttributes.Public, typeof(ProxyBase), + interfaceType.IsInterface ? new[] { interfaceType } : Type.EmptyTypes); + } + void GeneratePropertyChanged() + { + propertyChangedField = typeBuilder.DefineField(PropertyChanged.Name, typeof(PropertyChangedEventHandler), FieldAttributes.Private); + EventAccessor(PropertyChanged.AddMethod, DelegateCombine); + EventAccessor(PropertyChanged.RemoveMethod, DelegateRemove); + } + void EventAccessor(MethodInfo method, MethodInfo delegateMethod) + { + var eventAccessor = typeBuilder.DefineMethod(method.Name, + MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | + MethodAttributes.NewSlot | MethodAttributes.Virtual, typeof(void), + new[] { typeof(PropertyChangedEventHandler) }); + var addIl = eventAccessor.GetILGenerator(); + addIl.Emit(OpCodes.Ldarg_0); + addIl.Emit(OpCodes.Dup); + addIl.Emit(OpCodes.Ldfld, propertyChangedField); + addIl.Emit(OpCodes.Ldarg_1); + addIl.Emit(OpCodes.Call, delegateMethod); + addIl.Emit(OpCodes.Castclass, typeof(PropertyChangedEventHandler)); + addIl.Emit(OpCodes.Stfld, propertyChangedField); + addIl.Emit(OpCodes.Ret); + typeBuilder.DefineMethodOverride(eventAccessor, method); + } + void GenerateFields() + { + var fieldBuilders = new Dictionary(); + foreach (var property in PropertiesToImplement()) { - var fieldBuilders = new Dictionary(); - foreach (var property in PropertiesToImplement()) + if (fieldBuilders.TryGetValue(property.Name, out var propertyEmitter)) { - if (fieldBuilders.TryGetValue(property.Name, out var propertyEmitter)) + if (propertyEmitter.PropertyType != property.Type && (property.CanWrite || !property.Type.IsAssignableFrom(propertyEmitter.PropertyType))) { - if (propertyEmitter.PropertyType != property.Type && (property.CanWrite || !property.Type.IsAssignableFrom(propertyEmitter.PropertyType))) - { - throw new ArgumentException($"The interface has a conflicting property {property.Name}", nameof(interfaceType)); - } - } - else - { - fieldBuilders.Add(property.Name, new PropertyEmitter(typeBuilder, property, propertyChangedField)); + throw new ArgumentException($"The interface has a conflicting property {property.Name}", nameof(interfaceType)); } } - } - List PropertiesToImplement() - { - var propertiesToImplement = new List(); - var allInterfaces = new List(interfaceType.GetInterfaces()) { interfaceType }; - // first we collect all properties, those with setters before getters in order to enable less specific redundant getters - foreach (var property in - allInterfaces.Where(intf => intf != typeof(INotifyPropertyChanged)) - .SelectMany(intf => intf.GetProperties()) - .Select(p => new PropertyDescription(p)) - .Concat(typeDescription.AdditionalProperties)) + else { - if (property.CanWrite) - { - propertiesToImplement.Insert(0, property); - } - else - { - propertiesToImplement.Add(property); - } + fieldBuilders.Add(property.Name, new PropertyEmitter(typeBuilder, property, propertyChangedField)); } - return propertiesToImplement; - } - void GenerateConstructor() - { - var constructorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, Type.EmptyTypes); - var ctorIl = constructorBuilder.GetILGenerator(); - ctorIl.Emit(OpCodes.Ldarg_0); - ctorIl.Emit(OpCodes.Call, ProxyBaseCtor); - ctorIl.Emit(OpCodes.Ret); } } - public static Type GetProxyType(Type interfaceType) => ProxyTypes.GetOrAdd(new(interfaceType, Array.Empty())); - public static Type GetSimilarType(Type sourceType, IEnumerable additionalProperties) => - ProxyTypes.GetOrAdd(new(sourceType, additionalProperties.OrderBy(p=>p.Name).ToArray())); - class PropertyEmitter + List PropertiesToImplement() { - private static readonly MethodInfo ProxyBaseNotifyPropertyChanged = typeof(ProxyBase).GetInstanceMethod("NotifyPropertyChanged"); - private readonly FieldBuilder _fieldBuilder; - private readonly MethodBuilder _getterBuilder; - private readonly PropertyBuilder _propertyBuilder; - private readonly MethodBuilder _setterBuilder; - public PropertyEmitter(TypeBuilder owner, PropertyDescription property, FieldBuilder propertyChangedField) + var propertiesToImplement = new List(); + var allInterfaces = new List(interfaceType.GetInterfaces()) { interfaceType }; + // first we collect all properties, those with setters before getters in order to enable less specific redundant getters + foreach (var property in + allInterfaces.Where(intf => intf != typeof(INotifyPropertyChanged)) + .SelectMany(intf => intf.GetProperties()) + .Select(p => new PropertyDescription(p)) + .Concat(typeDescription.AdditionalProperties)) { - var name = property.Name; - var propertyType = property.Type; - _fieldBuilder = owner.DefineField($"<{name}>", propertyType, FieldAttributes.Private); - _propertyBuilder = owner.DefineProperty(name, PropertyAttributes.None, propertyType, null); - _getterBuilder = owner.DefineMethod($"get_{name}", - MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig | - MethodAttributes.SpecialName, propertyType, Type.EmptyTypes); - ILGenerator getterIl = _getterBuilder.GetILGenerator(); - getterIl.Emit(OpCodes.Ldarg_0); - getterIl.Emit(OpCodes.Ldfld, _fieldBuilder); - getterIl.Emit(OpCodes.Ret); - _propertyBuilder.SetGetMethod(_getterBuilder); - if (!property.CanWrite) + if (property.CanWrite) { - return; + propertiesToImplement.Insert(0, property); } - _setterBuilder = owner.DefineMethod($"set_{name}", - MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig | - MethodAttributes.SpecialName, typeof(void), new[] { propertyType }); - ILGenerator setterIl = _setterBuilder.GetILGenerator(); - setterIl.Emit(OpCodes.Ldarg_0); - setterIl.Emit(OpCodes.Ldarg_1); - setterIl.Emit(OpCodes.Stfld, _fieldBuilder); - if (propertyChangedField != null) + else { - setterIl.Emit(OpCodes.Ldarg_0); - setterIl.Emit(OpCodes.Dup); - setterIl.Emit(OpCodes.Ldfld, propertyChangedField); - setterIl.Emit(OpCodes.Ldstr, name); - setterIl.Emit(OpCodes.Call, ProxyBaseNotifyPropertyChanged); + propertiesToImplement.Add(property); } - setterIl.Emit(OpCodes.Ret); - _propertyBuilder.SetSetMethod(_setterBuilder); } - public Type PropertyType => _propertyBuilder.PropertyType; + return propertiesToImplement; + } + void GenerateConstructor() + { + var constructorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, Type.EmptyTypes); + var ctorIl = constructorBuilder.GetILGenerator(); + ctorIl.Emit(OpCodes.Ldarg_0); + ctorIl.Emit(OpCodes.Call, ProxyBaseCtor); + ctorIl.Emit(OpCodes.Ret); } } - public abstract class ProxyBase - { - public ProxyBase() { } - protected void NotifyPropertyChanged(PropertyChangedEventHandler handler, string method) => - handler?.Invoke(this, new PropertyChangedEventArgs(method)); - } - public readonly record struct TypeDescription(Type Type, PropertyDescription[] AdditionalProperties) + public static Type GetProxyType(Type interfaceType) => ProxyTypes.GetOrAdd(new(interfaceType, Array.Empty())); + public static Type GetSimilarType(Type sourceType, IEnumerable additionalProperties) => + ProxyTypes.GetOrAdd(new(sourceType, additionalProperties.OrderBy(p=>p.Name).ToArray())); + class PropertyEmitter { - public override int GetHashCode() + private static readonly MethodInfo ProxyBaseNotifyPropertyChanged = typeof(ProxyBase).GetInstanceMethod("NotifyPropertyChanged"); + private readonly FieldBuilder _fieldBuilder; + private readonly MethodBuilder _getterBuilder; + private readonly PropertyBuilder _propertyBuilder; + private readonly MethodBuilder _setterBuilder; + public PropertyEmitter(TypeBuilder owner, PropertyDescription property, FieldBuilder propertyChangedField) { - var hashCode = new HashCode(); - hashCode.Add(Type); - foreach (var property in AdditionalProperties) + var name = property.Name; + var propertyType = property.Type; + _fieldBuilder = owner.DefineField($"<{name}>", propertyType, FieldAttributes.Private); + _propertyBuilder = owner.DefineProperty(name, PropertyAttributes.None, propertyType, null); + _getterBuilder = owner.DefineMethod($"get_{name}", + MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig | + MethodAttributes.SpecialName, propertyType, Type.EmptyTypes); + ILGenerator getterIl = _getterBuilder.GetILGenerator(); + getterIl.Emit(OpCodes.Ldarg_0); + getterIl.Emit(OpCodes.Ldfld, _fieldBuilder); + getterIl.Emit(OpCodes.Ret); + _propertyBuilder.SetGetMethod(_getterBuilder); + if (!property.CanWrite) { - hashCode.Add(property); + return; + } + _setterBuilder = owner.DefineMethod($"set_{name}", + MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig | + MethodAttributes.SpecialName, typeof(void), new[] { propertyType }); + ILGenerator setterIl = _setterBuilder.GetILGenerator(); + setterIl.Emit(OpCodes.Ldarg_0); + setterIl.Emit(OpCodes.Ldarg_1); + setterIl.Emit(OpCodes.Stfld, _fieldBuilder); + if (propertyChangedField != null) + { + setterIl.Emit(OpCodes.Ldarg_0); + setterIl.Emit(OpCodes.Dup); + setterIl.Emit(OpCodes.Ldfld, propertyChangedField); + setterIl.Emit(OpCodes.Ldstr, name); + setterIl.Emit(OpCodes.Call, ProxyBaseNotifyPropertyChanged); } - return hashCode.ToHashCode(); + setterIl.Emit(OpCodes.Ret); + _propertyBuilder.SetSetMethod(_setterBuilder); } - public bool Equals(TypeDescription other) => Type == other.Type && AdditionalProperties.SequenceEqual(other.AdditionalProperties); + public Type PropertyType => _propertyBuilder.PropertyType; } - [DebuggerDisplay("{Name}-{Type.Name}")] - public readonly record struct PropertyDescription(string Name, Type Type, bool CanWrite = true) +} +public abstract class ProxyBase +{ + public ProxyBase() { } + protected void NotifyPropertyChanged(PropertyChangedEventHandler handler, string method) => + handler?.Invoke(this, new PropertyChangedEventArgs(method)); +} +public readonly record struct TypeDescription(Type Type, PropertyDescription[] AdditionalProperties) +{ + public override int GetHashCode() { - public PropertyDescription(PropertyInfo property) : this(property.Name, property.PropertyType, property.CanWrite) { } + var hashCode = new HashCode(); + hashCode.Add(Type); + foreach (var property in AdditionalProperties) + { + hashCode.Add(property); + } + return hashCode.ToHashCode(); } + public bool Equals(TypeDescription other) => Type == other.Type && AdditionalProperties.SequenceEqual(other.AdditionalProperties); +} +[DebuggerDisplay("{Name}-{Type.Name}")] +public readonly record struct PropertyDescription(string Name, Type Type, bool CanWrite = true) +{ + public PropertyDescription(PropertyInfo property) : this(property.Name, property.PropertyType, property.CanWrite) { } } \ No newline at end of file diff --git a/src/AutoMapper/Execution/TypeMapPlanBuilder.cs b/src/AutoMapper/Execution/TypeMapPlanBuilder.cs index 9705804ff2..a48ebedf80 100644 --- a/src/AutoMapper/Execution/TypeMapPlanBuilder.cs +++ b/src/AutoMapper/Execution/TypeMapPlanBuilder.cs @@ -4,572 +4,571 @@ using System.Linq.Expressions; using System.Diagnostics; using System.Reflection; -namespace AutoMapper.Execution +namespace AutoMapper.Execution; + +using static Expression; +using static ExpressionBuilder; +using Internal; +using Configuration; +public struct TypeMapPlanBuilder { - using static Expression; - using static ExpressionBuilder; - using Internal; - using Configuration; - public struct TypeMapPlanBuilder + private static readonly MethodInfo MappingError = typeof(TypeMapPlanBuilder).GetStaticMethod(nameof(MemberMappingError)); + private readonly IGlobalConfiguration _configuration; + private readonly ParameterExpression _destination; + private readonly ParameterExpression _initialDestination; + private readonly ParameterExpression[] _parameters; + private readonly TypeMap _typeMap; + private readonly ParameterExpression _source; + private List _variables; + private List _expressions; + private CatchBlock[] _catches; + public TypeMapPlanBuilder(IGlobalConfiguration configuration, TypeMap typeMap) { - private static readonly MethodInfo MappingError = typeof(TypeMapPlanBuilder).GetStaticMethod(nameof(MemberMappingError)); - private readonly IGlobalConfiguration _configuration; - private readonly ParameterExpression _destination; - private readonly ParameterExpression _initialDestination; - private readonly ParameterExpression[] _parameters; - private readonly TypeMap _typeMap; - private readonly ParameterExpression _source; - private List _variables; - private List _expressions; - private CatchBlock[] _catches; - public TypeMapPlanBuilder(IGlobalConfiguration configuration, TypeMap typeMap) - { - _configuration = configuration; - _typeMap = typeMap; - _source = Parameter(typeMap.SourceType, "source"); - _initialDestination = Parameter(typeMap.DestinationType, "destination"); - _destination = Variable(typeMap.DestinationType, "typeMapDestination"); - _variables = configuration.Variables; - _expressions = configuration.Expressions; - _catches = configuration.Catches; - _parameters = _configuration.Parameters ?? new ParameterExpression[] { null, null, ContextParameter }; - } - public Type DestinationType => _destination.Type; - private static AutoMapperMappingException MemberMappingError(Exception innerException, MemberMap memberMap) => new("Error mapping types.", innerException, memberMap); - ParameterExpression[] GetParameters(ParameterExpression first = null, ParameterExpression second = null) + _configuration = configuration; + _typeMap = typeMap; + _source = Parameter(typeMap.SourceType, "source"); + _initialDestination = Parameter(typeMap.DestinationType, "destination"); + _destination = Variable(typeMap.DestinationType, "typeMapDestination"); + _variables = configuration.Variables; + _expressions = configuration.Expressions; + _catches = configuration.Catches; + _parameters = _configuration.Parameters ?? new ParameterExpression[] { null, null, ContextParameter }; + } + public Type DestinationType => _destination.Type; + private static AutoMapperMappingException MemberMappingError(Exception innerException, MemberMap memberMap) => new("Error mapping types.", innerException, memberMap); + ParameterExpression[] GetParameters(ParameterExpression first = null, ParameterExpression second = null) + { + _parameters[0] = first ?? _source; + _parameters[1] = second ?? _destination; + return _parameters; + } + public LambdaExpression CreateMapperLambda() + { + var parameters = GetParameters(second: _initialDestination); + var customExpression = _typeMap.TypeConverter?.GetExpression(_configuration, parameters); + if (customExpression != null) { - _parameters[0] = first ?? _source; - _parameters[1] = second ?? _destination; - return _parameters; + return Lambda(customExpression, parameters); } - public LambdaExpression CreateMapperLambda() + _variables ??= new(); + _expressions ??= new(); + _catches ??= new CatchBlock[1]; + var typeMapsPath = _configuration.TypeMapsPath; + Clear(ref typeMapsPath); + CheckForCycles(_configuration, _typeMap, typeMapsPath); + var createDestinationFunc = CreateDestinationFunc(); + var assignmentFunc = CreateAssignmentFunc(createDestinationFunc); + var mapperFunc = CreateMapperFunc(assignmentFunc); + _variables.Clear(); + _expressions.Clear(); + if (_typeMap.IncludedMembersTypeMaps.Count > 0) { - var parameters = GetParameters(second: _initialDestination); - var customExpression = _typeMap.TypeConverter?.GetExpression(_configuration, parameters); - if (customExpression != null) - { - return Lambda(customExpression, parameters); - } - _variables ??= new(); - _expressions ??= new(); - _catches ??= new CatchBlock[1]; - var typeMapsPath = _configuration.TypeMapsPath; - Clear(ref typeMapsPath); - CheckForCycles(_configuration, _typeMap, typeMapsPath); - var createDestinationFunc = CreateDestinationFunc(); - var assignmentFunc = CreateAssignmentFunc(createDestinationFunc); - var mapperFunc = CreateMapperFunc(assignmentFunc); - _variables.Clear(); - _expressions.Clear(); - if (_typeMap.IncludedMembersTypeMaps.Count > 0) - { - IncludeMembers(); - } - var checkContext = CheckContext(_typeMap); - if (checkContext != null) - { - _expressions.Add(checkContext); - } - _expressions.Add(mapperFunc); - _variables.Add(_destination); - return Lambda(Block(_variables, _expressions), GetParameters(second: _initialDestination)); - static void Clear(ref HashSet typeMapsPath) - { - if (typeMapsPath == null) - { - typeMapsPath = new HashSet(); - } - else - { - typeMapsPath.Clear(); - } - } + IncludeMembers(); } - void IncludeMembers() + var checkContext = CheckContext(_typeMap); + if (checkContext != null) { - var configuration = _configuration; - _variables.AddRange(_typeMap.IncludedMembersTypeMaps.Select(i => i.Variable)); - var source = _source; - _expressions.AddRange(_variables.Zip(_typeMap.IncludedMembersTypeMaps, (v, i) => Assign(v, configuration.ReplaceParameters(i.MemberExpression, source).NullCheck(null)))); + _expressions.Add(checkContext); } - private static void CheckForCycles(IGlobalConfiguration configuration, TypeMap typeMap, HashSet typeMapsPath) + _expressions.Add(mapperFunc); + _variables.Add(_destination); + return Lambda(Block(_variables, _expressions), GetParameters(second: _initialDestination)); + static void Clear(ref HashSet typeMapsPath) { - typeMapsPath.Add(typeMap); - foreach (var memberMap in MemberMaps()) - { - var memberTypeMap = ResolveMemberTypeMap(memberMap); - if (memberTypeMap == null || memberTypeMap.HasTypeConverter) - { - continue; - } - if (memberMap.Inline && (memberTypeMap.PreserveReferences || typeMapsPath.Count == configuration.MaxExecutionPlanDepth)) - { - memberMap.Inline = false; - TraceInline(typeMap, memberMap); - } - if (memberTypeMap.PreserveReferences || memberTypeMap.MapExpression != null) - { - continue; - } - if (typeMapsPath.Contains(memberTypeMap)) - { - if (memberTypeMap.SourceType.IsValueType) - { - if (memberTypeMap.MaxDepth == 0) - { - memberTypeMap.MaxDepth = 10; - } - continue; - } - memberTypeMap.PreserveReferences = true; - Trace(typeMap, memberTypeMap, memberMap); - if (memberMap.Inline) - { - memberMap.Inline = false; - TraceInline(typeMap, memberMap); - } - foreach (var derivedTypeMap in configuration.GetIncludedTypeMaps(memberTypeMap)) - { - derivedTypeMap.PreserveReferences = true; - Trace(typeMap, derivedTypeMap, memberMap); - } - } - CheckForCycles(configuration, memberTypeMap, typeMapsPath); - } - typeMapsPath.Remove(typeMap); - return; - IEnumerable MemberMaps() + if (typeMapsPath == null) { - var memberMaps = typeMap.MemberMaps; - return typeMap.HasDerivedTypesToInclude ? - memberMaps.Concat(configuration.GetIncludedTypeMaps(typeMap).SelectMany(tm => tm.MemberMaps)) : - memberMaps; + typeMapsPath = new HashSet(); } - TypeMap ResolveMemberTypeMap(MemberMap memberMap) + else { - if (!memberMap.CanResolveValue) - { - return null; - } - var types = memberMap.Types(); - return types.ContainsGenericParameters ? null : configuration.ResolveAssociatedTypeMap(types); + typeMapsPath.Clear(); } - [Conditional("DEBUG")] - static void Trace(TypeMap typeMap, TypeMap memberTypeMap, MemberMap memberMap) => - Debug.WriteLine($"Setting PreserveReferences: {memberMap.DestinationName} {typeMap.SourceType} - {typeMap.DestinationType} => {memberTypeMap.SourceType} - {memberTypeMap.DestinationType}"); - [Conditional("DEBUG")] - static void TraceInline(TypeMap typeMap, MemberMap memberMap) => - Debug.WriteLine($"Resetting Inline: {memberMap.DestinationName} in {typeMap.SourceType} - {typeMap.DestinationType}"); - } - private Expression CreateDestinationFunc() - { - var newDestFunc = CreateNewDestinationFunc(); - var getDest = DestinationType.IsValueType ? newDestFunc : Coalesce(_initialDestination, ToType(newDestFunc, DestinationType)); - var destinationFunc = Assign(_destination, getDest); - return _typeMap.PreserveReferences ? - Block(destinationFunc, Call(ContextParameter, CacheDestinationMethod, _source, Constant(DestinationType), _destination), _destination) : - destinationFunc; } - Expression ReplaceParameters(LambdaExpression lambda) => _configuration.ReplaceParameters(lambda, GetParameters()); - private Expression CreateAssignmentFunc(Expression createDestination) + } + void IncludeMembers() + { + var configuration = _configuration; + _variables.AddRange(_typeMap.IncludedMembersTypeMaps.Select(i => i.Variable)); + var source = _source; + _expressions.AddRange(_variables.Zip(_typeMap.IncludedMembersTypeMaps, (v, i) => Assign(v, configuration.ReplaceParameters(i.MemberExpression, source).NullCheck(null)))); + } + private static void CheckForCycles(IGlobalConfiguration configuration, TypeMap typeMap, HashSet typeMapsPath) + { + typeMapsPath.Add(typeMap); + foreach (var memberMap in MemberMaps()) { - List actions = new() { createDestination }; - Expression typeMapExpression = null; - var hasMaxDepth = _typeMap.MaxDepth > 0; - if (hasMaxDepth) + var memberTypeMap = ResolveMemberTypeMap(memberMap); + if (memberTypeMap == null || memberTypeMap.HasTypeConverter) { - typeMapExpression = Constant(_typeMap); - actions.Add(Call(ContextParameter, IncTypeDepthInfo, typeMapExpression)); + continue; } - foreach (var beforeMapAction in _typeMap.BeforeMapActions) + if (memberMap.Inline && (memberTypeMap.PreserveReferences || typeMapsPath.Count == configuration.MaxExecutionPlanDepth)) { - actions.Add(ReplaceParameters(beforeMapAction)); + memberMap.Inline = false; + TraceInline(typeMap, memberMap); } - foreach (var propertyMap in _typeMap.OrderedPropertyMaps()) + if (memberTypeMap.PreserveReferences || memberTypeMap.MapExpression != null) { - if (propertyMap.CanResolveValue) + continue; + } + if (typeMapsPath.Contains(memberTypeMap)) + { + if (memberTypeMap.SourceType.IsValueType) { - var property = TryPropertyMap(propertyMap); - if (_typeMap.ConstructorParameterMatches(propertyMap.DestinationName)) + if (memberTypeMap.MaxDepth == 0) { - property = _initialDestination.IfNullElse(_configuration.Default(property.Type), property); + memberTypeMap.MaxDepth = 10; } - actions.Add(property); + continue; } - } - foreach (var pathMap in _typeMap.PathMaps) - { - if (!pathMap.Ignored) + memberTypeMap.PreserveReferences = true; + Trace(typeMap, memberTypeMap, memberMap); + if (memberMap.Inline) { - actions.Add(TryPathMap(pathMap)); + memberMap.Inline = false; + TraceInline(typeMap, memberMap); } - } - foreach (var afterMapAction in _typeMap.AfterMapActions) - { - actions.Add(ReplaceParameters(afterMapAction)); - } - if (hasMaxDepth) - { - actions.Add(Call(ContextParameter, DecTypeDepthInfo, typeMapExpression)); - } - actions.Add(_destination); - return Block(actions); - } - private Expression TryPathMap(PathMap pathMap) - { - var destination = ((MemberExpression)_configuration.ConvertReplaceParameters(pathMap.DestinationExpression, _destination)).Expression; - var configuration = _configuration; - var createInnerObjects = CreateInnerObjects(destination); - var setFinalValue = CreatePropertyMapFunc(pathMap, destination, pathMap.MemberPath.Last); - var pathMapExpression = Block(createInnerObjects, setFinalValue); - return TryMemberMap(pathMap, pathMapExpression); - Expression CreateInnerObjects(Expression destination) - { - return Block(destination.GetMemberExpressions().Select(NullCheck).Append(ExpressionBuilder.Empty)); - Expression NullCheck(MemberExpression memberExpression) + foreach (var derivedTypeMap in configuration.GetIncludedTypeMaps(memberTypeMap)) { - var setter = GetSetter(memberExpression); - var ifNull = setter == null - ? Throw(Constant(new NullReferenceException($"{memberExpression} cannot be null because it's used by ForPath.")), memberExpression.Type) - : (Expression)Assign(setter, ObjectFactory.GenerateConstructorExpression(memberExpression.Type, configuration)); - return memberExpression.IfNullElse(ifNull, configuration.Default(memberExpression.Type)); + derivedTypeMap.PreserveReferences = true; + Trace(typeMap, derivedTypeMap, memberMap); } - static Expression GetSetter(MemberExpression memberExpression) => memberExpression.Member switch - { - PropertyInfo { CanWrite: true } property => Property(memberExpression.Expression, property), - FieldInfo { IsInitOnly: false } field => Field(memberExpression.Expression, field), - _ => null, - }; } + CheckForCycles(configuration, memberTypeMap, typeMapsPath); } - private Expression CreateMapperFunc(Expression assignmentFunc) + typeMapsPath.Remove(typeMap); + return; + IEnumerable MemberMaps() { - var mapperFunc = assignmentFunc; - var overMaxDepth = OverMaxDepth(_typeMap); - if (overMaxDepth != null) - { - mapperFunc = Condition(overMaxDepth, _configuration.Default(DestinationType), mapperFunc); - } - mapperFunc = _configuration.NullCheckSource(_typeMap.Profile, _source, _initialDestination, mapperFunc, null); - return CheckReferencesCache(mapperFunc); + var memberMaps = typeMap.MemberMaps; + return typeMap.HasDerivedTypesToInclude ? + memberMaps.Concat(configuration.GetIncludedTypeMaps(typeMap).SelectMany(tm => tm.MemberMaps)) : + memberMaps; } - private Expression CheckReferencesCache(Expression valueBuilder) + TypeMap ResolveMemberTypeMap(MemberMap memberMap) { - if(!_typeMap.PreserveReferences) + if (!memberMap.CanResolveValue) { - return valueBuilder; + return null; } - var getCachedDestination = Call(ContextParameter, GetDestinationMethod, _source, Constant(DestinationType)); - return Coalesce(ToType(getCachedDestination, DestinationType), valueBuilder); - } - private Expression CreateNewDestinationFunc() => _typeMap switch - { - { CustomCtorFunction: LambdaExpression constructUsingFunc } => _configuration.ReplaceParameters(constructUsingFunc, GetParameters(second: ContextParameter)), - { ConstructorMap: { CanResolve: true } constructorMap } => ConstructorMapping(constructorMap), - { DestinationType: { IsInterface: true } interfaceType } => Throw(Constant(new AutoMapperMappingException("Cannot create interface "+interfaceType, null, _typeMap)), interfaceType), - _ => ObjectFactory.GenerateConstructorExpression(DestinationType, _configuration) - }; - private Expression ConstructorMapping(ConstructorMap constructorMap) - { - var ctorArgs = constructorMap.CtorParams.Select(CreateConstructorParameterExpression); - var variables = constructorMap.Ctor.GetParameters().Select(parameter => Variable(parameter.ParameterType, parameter.Name)).ToArray(); - var body = variables.Zip(ctorArgs, (variable, expression) => (Expression)Assign(variable, ToType(expression, variable.Type))) - .Append(CheckReferencesCache(New(constructorMap.Ctor, variables))); - return Block(variables, body); - } - private Expression CreateConstructorParameterExpression(ConstructorParameterMap ctorParamMap) - { - var defaultValue = ctorParamMap.DefaultValue(_configuration); - var customSource = GetCustomSource(ctorParamMap); - var resolvedExpression = BuildValueResolverFunc(ctorParamMap, customSource, defaultValue); - var resolvedValue = Variable(resolvedExpression.Type, "resolvedValue"); - var mapMember = MapMember(ctorParamMap, defaultValue, resolvedValue); - _variables.Clear(); - _variables.Add(resolvedValue); - _expressions.Clear(); - _expressions.Add(Assign(resolvedValue, resolvedExpression)); - _expressions.Add(mapMember); - return TryMemberMap(ctorParamMap, Block(_variables, _expressions)); + var types = memberMap.Types(); + return types.ContainsGenericParameters ? null : configuration.ResolveAssociatedTypeMap(types); } - private Expression TryPropertyMap(PropertyMap propertyMap) + [Conditional("DEBUG")] + static void Trace(TypeMap typeMap, TypeMap memberTypeMap, MemberMap memberMap) => + Debug.WriteLine($"Setting PreserveReferences: {memberMap.DestinationName} {typeMap.SourceType} - {typeMap.DestinationType} => {memberTypeMap.SourceType} - {memberTypeMap.DestinationType}"); + [Conditional("DEBUG")] + static void TraceInline(TypeMap typeMap, MemberMap memberMap) => + Debug.WriteLine($"Resetting Inline: {memberMap.DestinationName} in {typeMap.SourceType} - {typeMap.DestinationType}"); + } + private Expression CreateDestinationFunc() + { + var newDestFunc = CreateNewDestinationFunc(); + var getDest = DestinationType.IsValueType ? newDestFunc : Coalesce(_initialDestination, ToType(newDestFunc, DestinationType)); + var destinationFunc = Assign(_destination, getDest); + return _typeMap.PreserveReferences ? + Block(destinationFunc, Call(ContextParameter, CacheDestinationMethod, _source, Constant(DestinationType), _destination), _destination) : + destinationFunc; + } + Expression ReplaceParameters(LambdaExpression lambda) => _configuration.ReplaceParameters(lambda, GetParameters()); + private Expression CreateAssignmentFunc(Expression createDestination) + { + List actions = new() { createDestination }; + Expression typeMapExpression = null; + var hasMaxDepth = _typeMap.MaxDepth > 0; + if (hasMaxDepth) { - var propertyMapExpression = CreatePropertyMapFunc(propertyMap, _destination, propertyMap.DestinationMember); - return TryMemberMap(propertyMap, propertyMapExpression); + typeMapExpression = Constant(_typeMap); + actions.Add(Call(ContextParameter, IncTypeDepthInfo, typeMapExpression)); } - private Expression TryMemberMap(MemberMap memberMap, Expression memberMapExpression) + foreach (var beforeMapAction in _typeMap.BeforeMapActions) { - var newException = Call(MappingError, ExceptionParameter, Constant(memberMap)); - _catches[0] = Catch(ExceptionParameter, Throw(newException, memberMapExpression.Type)); - return TryCatch(memberMapExpression, _catches); + actions.Add(ReplaceParameters(beforeMapAction)); } - private Expression CreatePropertyMapFunc(MemberMap memberMap, Expression destination, MemberInfo destinationMember) + foreach (var propertyMap in _typeMap.OrderedPropertyMaps()) { - Expression destinationMemberAccess, destinationMemberGetter; - bool destinationMemberReadOnly; - if (destinationMember is PropertyInfo destinationProperty) - { - destinationMemberAccess = Property(destination, destinationProperty); - destinationMemberReadOnly = !destinationProperty.CanWrite; - destinationMemberGetter = destinationProperty.CanRead ? destinationMemberAccess : _configuration.Default(memberMap.DestinationType); - } - else - { - var destinationField = (FieldInfo)destinationMember; - destinationMemberAccess = Field(destination, destinationField); - destinationMemberReadOnly = destinationField.IsInitOnly; - destinationMemberGetter = destinationMemberAccess; - } - var customSource = GetCustomSource(memberMap); - var valueResolver = BuildValueResolverFunc(memberMap, customSource, destinationMemberGetter); - var resolvedValueVariable = Variable(valueResolver.Type, "resolvedValue"); - var destinationMemberValue = DestinationMemberValue(memberMap, destinationMemberGetter, destinationMemberReadOnly); - var mappedMember = MapMember(memberMap, destinationMemberValue, resolvedValueVariable); - var mappedMemberVariable = SetVariables(valueResolver, resolvedValueVariable, mappedMember); - var mapperExpr = destinationMemberReadOnly ? (Expression)mappedMemberVariable : Assign(destinationMemberAccess, mappedMemberVariable); - if (memberMap.Condition != null) + if (propertyMap.CanResolveValue) { - _expressions.Add(IfThen( - _configuration.ConvertReplaceParameters(memberMap.Condition, new[] { customSource, _destination, mappedMemberVariable, destinationMemberGetter, ContextParameter }), - mapperExpr)); - } - else if (!destinationMemberReadOnly) - { - _expressions.Add(mapperExpr); - } - if (memberMap.PreCondition != null) - { - Precondition(memberMap, customSource); + var property = TryPropertyMap(propertyMap); + if (_typeMap.ConstructorParameterMatches(propertyMap.DestinationName)) + { + property = _initialDestination.IfNullElse(_configuration.Default(property.Type), property); + } + actions.Add(property); } - return Block(_variables, _expressions); } - Expression DestinationMemberValue(MemberMap memberMap, Expression destinationMemberGetter, bool destinationMemberReadOnly) + foreach (var pathMap in _typeMap.PathMaps) { - if (destinationMemberReadOnly || memberMap.UseDestinationValue is true) + if (!pathMap.Ignored) { - return destinationMemberGetter; + actions.Add(TryPathMap(pathMap)); } - var defaultValue = _configuration.Default(memberMap.DestinationType); - return DestinationType.IsValueType ? defaultValue : Condition(ReferenceEqual(_initialDestination, Null), defaultValue, destinationMemberGetter); - } - void Precondition(MemberMap memberMap, ParameterExpression customSource) - { - var preCondition = _configuration.ConvertReplaceParameters(memberMap.PreCondition, GetParameters(first: customSource)); - var ifThen = IfThen(preCondition, Block(_expressions)); - _expressions.Clear(); - _expressions.Add(ifThen); } - ParameterExpression SetVariables(Expression valueResolver, ParameterExpression resolvedValueVariable, Expression mappedMember) + foreach (var afterMapAction in _typeMap.AfterMapActions) { - _expressions.Clear(); - _variables.Clear(); - _variables.Add(resolvedValueVariable); - _expressions.Add(Assign(resolvedValueVariable, valueResolver)); - ParameterExpression mappedMemberVariable; - if (mappedMember == resolvedValueVariable) - { - mappedMemberVariable = resolvedValueVariable; - } - else - { - mappedMemberVariable = Variable(mappedMember.Type, "mappedValue"); - _variables.Add(mappedMemberVariable); - _expressions.Add(Assign(mappedMemberVariable, mappedMember)); - } - return mappedMemberVariable; + actions.Add(ReplaceParameters(afterMapAction)); } - Expression MapMember(MemberMap memberMap, Expression destinationMemberValue, ParameterExpression resolvedValue) + if (hasMaxDepth) { - var typePair = memberMap.Types(); - var profile = _typeMap.Profile; - var mapMember = memberMap.Inline ? - _configuration.MapExpression(profile, typePair, resolvedValue, memberMap, destinationMemberValue) : - _configuration.NullCheckSource(profile, resolvedValue, destinationMemberValue, ContextMap(typePair, resolvedValue, destinationMemberValue, memberMap), memberMap); - return memberMap.ApplyTransformers(mapMember, _configuration); + actions.Add(Call(ContextParameter, DecTypeDepthInfo, typeMapExpression)); } - private Expression BuildValueResolverFunc(MemberMap memberMap, Expression customSource, Expression destValueExpr) + actions.Add(_destination); + return Block(actions); + } + private Expression TryPathMap(PathMap pathMap) + { + var destination = ((MemberExpression)_configuration.ConvertReplaceParameters(pathMap.DestinationExpression, _destination)).Expression; + var configuration = _configuration; + var createInnerObjects = CreateInnerObjects(destination); + var setFinalValue = CreatePropertyMapFunc(pathMap, destination, pathMap.MemberPath.Last); + var pathMapExpression = Block(createInnerObjects, setFinalValue); + return TryMemberMap(pathMap, pathMapExpression); + Expression CreateInnerObjects(Expression destination) { - var valueResolverFunc = memberMap.Resolver?.GetExpression(_configuration, memberMap, customSource, _destination, destValueExpr) ?? destValueExpr; - if (memberMap.NullSubstitute != null) + return Block(destination.GetMemberExpressions().Select(NullCheck).Append(ExpressionBuilder.Empty)); + Expression NullCheck(MemberExpression memberExpression) { - valueResolverFunc = memberMap.NullSubstitute(valueResolverFunc); + var setter = GetSetter(memberExpression); + var ifNull = setter == null + ? Throw(Constant(new NullReferenceException($"{memberExpression} cannot be null because it's used by ForPath.")), memberExpression.Type) + : (Expression)Assign(setter, ObjectFactory.GenerateConstructorExpression(memberExpression.Type, configuration)); + return memberExpression.IfNullElse(ifNull, configuration.Default(memberExpression.Type)); } - else if (!memberMap.AllowsNullDestinationValues) + static Expression GetSetter(MemberExpression memberExpression) => memberExpression.Member switch { - var toCreate = memberMap.SourceType; - if (!toCreate.IsAbstract && toCreate.IsClass && !toCreate.IsArray) - { - var ctor = ObjectFactory.GenerateConstructorExpression(toCreate, _configuration); - valueResolverFunc = Coalesce(valueResolverFunc, ToType(ctor, valueResolverFunc.Type)); - } - } - return valueResolverFunc; + PropertyInfo { CanWrite: true } property => Property(memberExpression.Expression, property), + FieldInfo { IsInitOnly: false } field => Field(memberExpression.Expression, field), + _ => null, + }; } - private ParameterExpression GetCustomSource(MemberMap memberMap) => memberMap.IncludedMember?.Variable ?? _source; } - public interface IValueResolver + private Expression CreateMapperFunc(Expression assignmentFunc) { - Expression GetExpression(IGlobalConfiguration configuration, MemberMap memberMap, Expression source, Expression destination, Expression destinationMember); - MemberInfo GetSourceMember(MemberMap memberMap); - Type ResolvedType { get; } - string SourceMemberName => null; - LambdaExpression ProjectToExpression => null; + var mapperFunc = assignmentFunc; + var overMaxDepth = OverMaxDepth(_typeMap); + if (overMaxDepth != null) + { + mapperFunc = Condition(overMaxDepth, _configuration.Default(DestinationType), mapperFunc); + } + mapperFunc = _configuration.NullCheckSource(_typeMap.Profile, _source, _initialDestination, mapperFunc, null); + return CheckReferencesCache(mapperFunc); } - public class MemberPathResolver : IValueResolver + private Expression CheckReferencesCache(Expression valueBuilder) { - private readonly MemberInfo[] _members; - public MemberPathResolver(MemberInfo[] members) => _members = members; - public Type ResolvedType => _members?[^1].GetMemberType(); - public Expression GetExpression(IGlobalConfiguration configuration, MemberMap memberMap, Expression source, Expression destination, Expression destinationMember) + if(!_typeMap.PreserveReferences) { - var expression = _members.Chain(source); - return memberMap.IncludedMember == null && _members.Length < 2 ? expression : expression.NullCheck(configuration, memberMap, destinationMember); + return valueBuilder; } - public MemberInfo GetSourceMember(MemberMap memberMap) => _members.Length == 1 ? _members[0] : null; - public LambdaExpression ProjectToExpression => _members.Lambda(); + var getCachedDestination = Call(ContextParameter, GetDestinationMethod, _source, Constant(DestinationType)); + return Coalesce(ToType(getCachedDestination, DestinationType), valueBuilder); } - public abstract class LambdaValueResolver + private Expression CreateNewDestinationFunc() => _typeMap switch + { + { CustomCtorFunction: LambdaExpression constructUsingFunc } => _configuration.ReplaceParameters(constructUsingFunc, GetParameters(second: ContextParameter)), + { ConstructorMap: { CanResolve: true } constructorMap } => ConstructorMapping(constructorMap), + { DestinationType: { IsInterface: true } interfaceType } => Throw(Constant(new AutoMapperMappingException("Cannot create interface "+interfaceType, null, _typeMap)), interfaceType), + _ => ObjectFactory.GenerateConstructorExpression(DestinationType, _configuration) + }; + private Expression ConstructorMapping(ConstructorMap constructorMap) { - public LambdaExpression Lambda { get; } - public Type ResolvedType => Lambda.ReturnType; - protected LambdaValueResolver(LambdaExpression lambda) => Lambda = lambda; + var ctorArgs = constructorMap.CtorParams.Select(CreateConstructorParameterExpression); + var variables = constructorMap.Ctor.GetParameters().Select(parameter => Variable(parameter.ParameterType, parameter.Name)).ToArray(); + var body = variables.Zip(ctorArgs, (variable, expression) => (Expression)Assign(variable, ToType(expression, variable.Type))) + .Append(CheckReferencesCache(New(constructorMap.Ctor, variables))); + return Block(variables, body); } - public class FuncResolver : LambdaValueResolver, IValueResolver + private Expression CreateConstructorParameterExpression(ConstructorParameterMap ctorParamMap) { - public FuncResolver(LambdaExpression lambda) : base(lambda) { } - public Expression GetExpression(IGlobalConfiguration configuration, MemberMap memberMap, Expression source, Expression destination, Expression destinationMember) => - configuration.ConvertReplaceParameters(Lambda, new[] { source, destination, destinationMember, ContextParameter }); - public MemberInfo GetSourceMember(MemberMap _) => null; + var defaultValue = ctorParamMap.DefaultValue(_configuration); + var customSource = GetCustomSource(ctorParamMap); + var resolvedExpression = BuildValueResolverFunc(ctorParamMap, customSource, defaultValue); + var resolvedValue = Variable(resolvedExpression.Type, "resolvedValue"); + var mapMember = MapMember(ctorParamMap, defaultValue, resolvedValue); + _variables.Clear(); + _variables.Add(resolvedValue); + _expressions.Clear(); + _expressions.Add(Assign(resolvedValue, resolvedExpression)); + _expressions.Add(mapMember); + return TryMemberMap(ctorParamMap, Block(_variables, _expressions)); } - public class ExpressionResolver : LambdaValueResolver, IValueResolver + private Expression TryPropertyMap(PropertyMap propertyMap) { - public ExpressionResolver(LambdaExpression lambda) : base(lambda) { } - public Expression GetExpression(IGlobalConfiguration configuration, MemberMap memberMap, Expression source, Expression _, Expression destinationMember) - { - var mapFrom = configuration.ReplaceParameters(Lambda, source); - var nullCheckedExpression = mapFrom.NullCheck(configuration, memberMap, destinationMember); - if (nullCheckedExpression != mapFrom) - { - return nullCheckedExpression; - } - var defaultExpression = configuration.Default(mapFrom.Type); - return TryCatch(mapFrom, Catch(typeof(NullReferenceException), defaultExpression), Catch(typeof(ArgumentNullException), defaultExpression)); - } - public MemberInfo GetSourceMember(MemberMap _) => Lambda.GetMember(); - public LambdaExpression ProjectToExpression => Lambda; + var propertyMapExpression = CreatePropertyMapFunc(propertyMap, _destination, propertyMap.DestinationMember); + return TryMemberMap(propertyMap, propertyMapExpression); + } + private Expression TryMemberMap(MemberMap memberMap, Expression memberMapExpression) + { + var newException = Call(MappingError, ExceptionParameter, Constant(memberMap)); + _catches[0] = Catch(ExceptionParameter, Throw(newException, memberMapExpression.Type)); + return TryCatch(memberMapExpression, _catches); } - public abstract class ValueResolverConfig + private Expression CreatePropertyMapFunc(MemberMap memberMap, Expression destination, MemberInfo destinationMember) { - private protected readonly Expression _instance; - public Type ConcreteType { get; } - public Type InterfaceType { get; } - public LambdaExpression SourceMemberLambda { get; init; } - protected ValueResolverConfig(Type concreteType, Type interfaceType, Expression instance = null) + Expression destinationMemberAccess, destinationMemberGetter; + bool destinationMemberReadOnly; + if (destinationMember is PropertyInfo destinationProperty) + { + destinationMemberAccess = Property(destination, destinationProperty); + destinationMemberReadOnly = !destinationProperty.CanWrite; + destinationMemberGetter = destinationProperty.CanRead ? destinationMemberAccess : _configuration.Default(memberMap.DestinationType); + } + else { - ConcreteType = concreteType; - InterfaceType = interfaceType; - _instance = instance; + var destinationField = (FieldInfo)destinationMember; + destinationMemberAccess = Field(destination, destinationField); + destinationMemberReadOnly = destinationField.IsInitOnly; + destinationMemberGetter = destinationMemberAccess; } - protected ValueResolverConfig(object instance, Type interfaceType) + var customSource = GetCustomSource(memberMap); + var valueResolver = BuildValueResolverFunc(memberMap, customSource, destinationMemberGetter); + var resolvedValueVariable = Variable(valueResolver.Type, "resolvedValue"); + var destinationMemberValue = DestinationMemberValue(memberMap, destinationMemberGetter, destinationMemberReadOnly); + var mappedMember = MapMember(memberMap, destinationMemberValue, resolvedValueVariable); + var mappedMemberVariable = SetVariables(valueResolver, resolvedValueVariable, mappedMember); + var mapperExpr = destinationMemberReadOnly ? (Expression)mappedMemberVariable : Assign(destinationMemberAccess, mappedMemberVariable); + if (memberMap.Condition != null) { - _instance = Constant(instance); - InterfaceType = interfaceType; + _expressions.Add(IfThen( + _configuration.ConvertReplaceParameters(memberMap.Condition, new[] { customSource, _destination, mappedMemberVariable, destinationMemberGetter, ContextParameter }), + mapperExpr)); } - public string SourceMemberName { get; init; } - public Type ResolvedType => InterfaceType.GenericTypeArguments[^1]; + else if (!destinationMemberReadOnly) + { + _expressions.Add(mapperExpr); + } + if (memberMap.PreCondition != null) + { + Precondition(memberMap, customSource); + } + return Block(_variables, _expressions); } - public class ValueConverter : ValueResolverConfig, IValueResolver + Expression DestinationMemberValue(MemberMap memberMap, Expression destinationMemberGetter, bool destinationMemberReadOnly) { - public ValueConverter(Type concreteType, Type interfaceType) : base(concreteType, interfaceType, ServiceLocator(concreteType)) { } - public ValueConverter(object instance, Type interfaceType) : base(instance, interfaceType) { } - public Expression GetExpression(IGlobalConfiguration configuration, MemberMap memberMap, Expression source, Expression _, Expression destinationMember) + if (destinationMemberReadOnly || memberMap.UseDestinationValue is true) { - var sourceMemberType = InterfaceType.GenericTypeArguments[0]; - var sourceMember = this switch - { - { SourceMemberLambda: { } } => configuration.ReplaceParameters(SourceMemberLambda, source), - { SourceMemberName: { } } => PropertyOrField(source, SourceMemberName), - _ when memberMap.SourceMembers.Length > 0 => memberMap.ChainSourceMembers(configuration, source, destinationMember), - _ => Throw(Constant(BuildExceptionMessage()), sourceMemberType) - }; - return Call(ToType(_instance, InterfaceType), InterfaceType.GetMethod("Convert"), ToType(sourceMember, sourceMemberType), ContextParameter); - AutoMapperConfigurationException BuildExceptionMessage() - => new($"Cannot find a source member to pass to the value converter of type {ConcreteType}. Configure a source member to map from."); + return destinationMemberGetter; + } + var defaultValue = _configuration.Default(memberMap.DestinationType); + return DestinationType.IsValueType ? defaultValue : Condition(ReferenceEqual(_initialDestination, Null), defaultValue, destinationMemberGetter); + } + void Precondition(MemberMap memberMap, ParameterExpression customSource) + { + var preCondition = _configuration.ConvertReplaceParameters(memberMap.PreCondition, GetParameters(first: customSource)); + var ifThen = IfThen(preCondition, Block(_expressions)); + _expressions.Clear(); + _expressions.Add(ifThen); + } + ParameterExpression SetVariables(Expression valueResolver, ParameterExpression resolvedValueVariable, Expression mappedMember) + { + _expressions.Clear(); + _variables.Clear(); + _variables.Add(resolvedValueVariable); + _expressions.Add(Assign(resolvedValueVariable, valueResolver)); + ParameterExpression mappedMemberVariable; + if (mappedMember == resolvedValueVariable) + { + mappedMemberVariable = resolvedValueVariable; } - public MemberInfo GetSourceMember(MemberMap memberMap) => this switch + else { - { SourceMemberLambda: { } lambda } => lambda.GetMember(), - { SourceMemberName: { } } => null, - _ => memberMap.SourceMembers.Length == 1 ? memberMap.SourceMembers[0] : null - }; + mappedMemberVariable = Variable(mappedMember.Type, "mappedValue"); + _variables.Add(mappedMemberVariable); + _expressions.Add(Assign(mappedMemberVariable, mappedMember)); + } + return mappedMemberVariable; + } + Expression MapMember(MemberMap memberMap, Expression destinationMemberValue, ParameterExpression resolvedValue) + { + var typePair = memberMap.Types(); + var profile = _typeMap.Profile; + var mapMember = memberMap.Inline ? + _configuration.MapExpression(profile, typePair, resolvedValue, memberMap, destinationMemberValue) : + _configuration.NullCheckSource(profile, resolvedValue, destinationMemberValue, ContextMap(typePair, resolvedValue, destinationMemberValue, memberMap), memberMap); + return memberMap.ApplyTransformers(mapMember, _configuration); } - public class ClassValueResolver : ValueResolverConfig, IValueResolver + private Expression BuildValueResolverFunc(MemberMap memberMap, Expression customSource, Expression destValueExpr) { - public ClassValueResolver(Type concreteType, Type interfaceType) : base(concreteType, interfaceType) { } - public ClassValueResolver(object instance, Type interfaceType) : base(instance, interfaceType) { } - public Expression GetExpression(IGlobalConfiguration configuration, MemberMap memberMap, Expression source, Expression destination, Expression destinationMember) + var valueResolverFunc = memberMap.Resolver?.GetExpression(_configuration, memberMap, customSource, _destination, destValueExpr) ?? destValueExpr; + if (memberMap.NullSubstitute != null) { - var typeMap = memberMap.TypeMap; - var resolverInstance = _instance ?? ServiceLocator(typeMap.MakeGenericType(ConcreteType)); - Expression sourceMember; - if (SourceMemberLambda == null) - { - sourceMember = SourceMemberName == null ? null : PropertyOrField(source, SourceMemberName); - } - else - { - sourceMember = configuration.ReplaceParameters(SourceMemberLambda, source); - } - var iValueResolver = InterfaceType; - if (iValueResolver.ContainsGenericParameters) + valueResolverFunc = memberMap.NullSubstitute(valueResolverFunc); + } + else if (!memberMap.AllowsNullDestinationValues) + { + var toCreate = memberMap.SourceType; + if (!toCreate.IsAbstract && toCreate.IsClass && !toCreate.IsArray) { - var typeArgs = - iValueResolver.GenericTypeArguments.Zip(new[] { typeMap.SourceType, typeMap.DestinationType, sourceMember?.Type, destinationMember.Type }.Where(t => t != null), - (declaredType, runtimeType) => declaredType.ContainsGenericParameters ? runtimeType : declaredType).ToArray(); - iValueResolver = iValueResolver.GetGenericTypeDefinition().MakeGenericType(typeArgs); + var ctor = ObjectFactory.GenerateConstructorExpression(toCreate, _configuration); + valueResolverFunc = Coalesce(valueResolverFunc, ToType(ctor, valueResolverFunc.Type)); } - var parameters = new[] { source, destination, sourceMember, destinationMember }.Where(p => p != null) - .Zip(iValueResolver.GenericTypeArguments, ToType) - .Append(ContextParameter) - .ToArray(); - return Call(ToType(resolverInstance, iValueResolver), "Resolve", parameters); } - public MemberInfo GetSourceMember(MemberMap _) => SourceMemberLambda?.GetMember(); + return valueResolverFunc; + } + private ParameterExpression GetCustomSource(MemberMap memberMap) => memberMap.IncludedMember?.Variable ?? _source; +} +public interface IValueResolver +{ + Expression GetExpression(IGlobalConfiguration configuration, MemberMap memberMap, Expression source, Expression destination, Expression destinationMember); + MemberInfo GetSourceMember(MemberMap memberMap); + Type ResolvedType { get; } + string SourceMemberName => null; + LambdaExpression ProjectToExpression => null; +} +public class MemberPathResolver : IValueResolver +{ + private readonly MemberInfo[] _members; + public MemberPathResolver(MemberInfo[] members) => _members = members; + public Type ResolvedType => _members?[^1].GetMemberType(); + public Expression GetExpression(IGlobalConfiguration configuration, MemberMap memberMap, Expression source, Expression destination, Expression destinationMember) + { + var expression = _members.Chain(source); + return memberMap.IncludedMember == null && _members.Length < 2 ? expression : expression.NullCheck(configuration, memberMap, destinationMember); + } + public MemberInfo GetSourceMember(MemberMap memberMap) => _members.Length == 1 ? _members[0] : null; + public LambdaExpression ProjectToExpression => _members.Lambda(); +} +public abstract class LambdaValueResolver +{ + public LambdaExpression Lambda { get; } + public Type ResolvedType => Lambda.ReturnType; + protected LambdaValueResolver(LambdaExpression lambda) => Lambda = lambda; +} +public class FuncResolver : LambdaValueResolver, IValueResolver +{ + public FuncResolver(LambdaExpression lambda) : base(lambda) { } + public Expression GetExpression(IGlobalConfiguration configuration, MemberMap memberMap, Expression source, Expression destination, Expression destinationMember) => + configuration.ConvertReplaceParameters(Lambda, new[] { source, destination, destinationMember, ContextParameter }); + public MemberInfo GetSourceMember(MemberMap _) => null; +} +public class ExpressionResolver : LambdaValueResolver, IValueResolver +{ + public ExpressionResolver(LambdaExpression lambda) : base(lambda) { } + public Expression GetExpression(IGlobalConfiguration configuration, MemberMap memberMap, Expression source, Expression _, Expression destinationMember) + { + var mapFrom = configuration.ReplaceParameters(Lambda, source); + var nullCheckedExpression = mapFrom.NullCheck(configuration, memberMap, destinationMember); + if (nullCheckedExpression != mapFrom) + { + return nullCheckedExpression; + } + var defaultExpression = configuration.Default(mapFrom.Type); + return TryCatch(mapFrom, Catch(typeof(NullReferenceException), defaultExpression), Catch(typeof(ArgumentNullException), defaultExpression)); } - public abstract class TypeConverter + public MemberInfo GetSourceMember(MemberMap _) => Lambda.GetMember(); + public LambdaExpression ProjectToExpression => Lambda; +} +public abstract class ValueResolverConfig +{ + private protected readonly Expression _instance; + public Type ConcreteType { get; } + public Type InterfaceType { get; } + public LambdaExpression SourceMemberLambda { get; init; } + protected ValueResolverConfig(Type concreteType, Type interfaceType, Expression instance = null) { - public abstract Expression GetExpression(IGlobalConfiguration configuration, ParameterExpression[] parameters); - public virtual void CloseGenerics(TypeMapConfiguration openMapConfig, TypePair closedTypes) { } - public virtual LambdaExpression ProjectToExpression => null; + ConcreteType = concreteType; + InterfaceType = interfaceType; + _instance = instance; } - public class LambdaTypeConverter : TypeConverter + protected ValueResolverConfig(object instance, Type interfaceType) { - public LambdaTypeConverter(LambdaExpression lambda) => Lambda = lambda; - public LambdaExpression Lambda { get; } - public override Expression GetExpression(IGlobalConfiguration configuration, ParameterExpression[] parameters) => - configuration.ConvertReplaceParameters(Lambda, parameters); + _instance = Constant(instance); + InterfaceType = interfaceType; } - public class ExpressionTypeConverter : LambdaTypeConverter + public string SourceMemberName { get; init; } + public Type ResolvedType => InterfaceType.GenericTypeArguments[^1]; +} +public class ValueConverter : ValueResolverConfig, IValueResolver +{ + public ValueConverter(Type concreteType, Type interfaceType) : base(concreteType, interfaceType, ServiceLocator(concreteType)) { } + public ValueConverter(object instance, Type interfaceType) : base(instance, interfaceType) { } + public Expression GetExpression(IGlobalConfiguration configuration, MemberMap memberMap, Expression source, Expression _, Expression destinationMember) { - public ExpressionTypeConverter(LambdaExpression lambda) : base(lambda){} - public override LambdaExpression ProjectToExpression => Lambda; + var sourceMemberType = InterfaceType.GenericTypeArguments[0]; + var sourceMember = this switch + { + { SourceMemberLambda: { } } => configuration.ReplaceParameters(SourceMemberLambda, source), + { SourceMemberName: { } } => PropertyOrField(source, SourceMemberName), + _ when memberMap.SourceMembers.Length > 0 => memberMap.ChainSourceMembers(configuration, source, destinationMember), + _ => Throw(Constant(BuildExceptionMessage()), sourceMemberType) + }; + return Call(ToType(_instance, InterfaceType), InterfaceType.GetMethod("Convert"), ToType(sourceMember, sourceMemberType), ContextParameter); + AutoMapperConfigurationException BuildExceptionMessage() + => new($"Cannot find a source member to pass to the value converter of type {ConcreteType}. Configure a source member to map from."); } - public class ClassTypeConverter : TypeConverter + public MemberInfo GetSourceMember(MemberMap memberMap) => this switch + { + { SourceMemberLambda: { } lambda } => lambda.GetMember(), + { SourceMemberName: { } } => null, + _ => memberMap.SourceMembers.Length == 1 ? memberMap.SourceMembers[0] : null + }; +} +public class ClassValueResolver : ValueResolverConfig, IValueResolver +{ + public ClassValueResolver(Type concreteType, Type interfaceType) : base(concreteType, interfaceType) { } + public ClassValueResolver(object instance, Type interfaceType) : base(instance, interfaceType) { } + public Expression GetExpression(IGlobalConfiguration configuration, MemberMap memberMap, Expression source, Expression destination, Expression destinationMember) { - public ClassTypeConverter(Type converterType, Type converterInterface) + var typeMap = memberMap.TypeMap; + var resolverInstance = _instance ?? ServiceLocator(typeMap.MakeGenericType(ConcreteType)); + Expression sourceMember; + if (SourceMemberLambda == null) { - ConverterType = converterType; - ConverterInterface = converterInterface; + sourceMember = SourceMemberName == null ? null : PropertyOrField(source, SourceMemberName); } - public Type ConverterType { get; private set; } - public Type ConverterInterface { get; } - public override Expression GetExpression(IGlobalConfiguration configuration, ParameterExpression[] parameters) => - Call(ToType(ServiceLocator(ConverterType), ConverterInterface), "Convert", parameters); - public override void CloseGenerics(TypeMapConfiguration openMapConfig, TypePair closedTypes) + else { - var typeParams = (openMapConfig.SourceType.IsGenericTypeDefinition ? closedTypes.SourceType.GenericTypeArguments : Type.EmptyTypes) - .Concat(openMapConfig.DestinationType.IsGenericTypeDefinition ? closedTypes.DestinationType.GenericTypeArguments : Type.EmptyTypes); - var neededParameters = ConverterType.GenericParametersCount(); - ConverterType = ConverterType.MakeGenericType(typeParams.Take(neededParameters).ToArray()); + sourceMember = configuration.ReplaceParameters(SourceMemberLambda, source); } + var iValueResolver = InterfaceType; + if (iValueResolver.ContainsGenericParameters) + { + var typeArgs = + iValueResolver.GenericTypeArguments.Zip(new[] { typeMap.SourceType, typeMap.DestinationType, sourceMember?.Type, destinationMember.Type }.Where(t => t != null), + (declaredType, runtimeType) => declaredType.ContainsGenericParameters ? runtimeType : declaredType).ToArray(); + iValueResolver = iValueResolver.GetGenericTypeDefinition().MakeGenericType(typeArgs); + } + var parameters = new[] { source, destination, sourceMember, destinationMember }.Where(p => p != null) + .Zip(iValueResolver.GenericTypeArguments, ToType) + .Append(ContextParameter) + .ToArray(); + return Call(ToType(resolverInstance, iValueResolver), "Resolve", parameters); + } + public MemberInfo GetSourceMember(MemberMap _) => SourceMemberLambda?.GetMember(); +} +public abstract class TypeConverter +{ + public abstract Expression GetExpression(IGlobalConfiguration configuration, ParameterExpression[] parameters); + public virtual void CloseGenerics(TypeMapConfiguration openMapConfig, TypePair closedTypes) { } + public virtual LambdaExpression ProjectToExpression => null; +} +public class LambdaTypeConverter : TypeConverter +{ + public LambdaTypeConverter(LambdaExpression lambda) => Lambda = lambda; + public LambdaExpression Lambda { get; } + public override Expression GetExpression(IGlobalConfiguration configuration, ParameterExpression[] parameters) => + configuration.ConvertReplaceParameters(Lambda, parameters); +} +public class ExpressionTypeConverter : LambdaTypeConverter +{ + public ExpressionTypeConverter(LambdaExpression lambda) : base(lambda){} + public override LambdaExpression ProjectToExpression => Lambda; +} +public class ClassTypeConverter : TypeConverter +{ + public ClassTypeConverter(Type converterType, Type converterInterface) + { + ConverterType = converterType; + ConverterInterface = converterInterface; + } + public Type ConverterType { get; private set; } + public Type ConverterInterface { get; } + public override Expression GetExpression(IGlobalConfiguration configuration, ParameterExpression[] parameters) => + Call(ToType(ServiceLocator(ConverterType), ConverterInterface), "Convert", parameters); + public override void CloseGenerics(TypeMapConfiguration openMapConfig, TypePair closedTypes) + { + var typeParams = (openMapConfig.SourceType.IsGenericTypeDefinition ? closedTypes.SourceType.GenericTypeArguments : Type.EmptyTypes) + .Concat(openMapConfig.DestinationType.IsGenericTypeDefinition ? closedTypes.DestinationType.GenericTypeArguments : Type.EmptyTypes); + var neededParameters = ConverterType.GenericParametersCount(); + ConverterType = ConverterType.MakeGenericType(typeParams.Take(neededParameters).ToArray()); } } \ No newline at end of file diff --git a/src/AutoMapper/Features.cs b/src/AutoMapper/Features.cs index ed2e2f0310..8e00dc655b 100644 --- a/src/AutoMapper/Features.cs +++ b/src/AutoMapper/Features.cs @@ -3,104 +3,103 @@ using System.Collections; using System.Collections.Generic; using System.Linq; -namespace AutoMapper.Features +namespace AutoMapper.Features; + +public interface IGlobalFeature { - public interface IGlobalFeature + void Configure(IGlobalConfiguration configuration); +} +public interface IMappingFeature +{ + void Configure(TypeMap typeMap); + IMappingFeature Reverse(); +} +public interface IRuntimeFeature +{ + void Seal(IGlobalConfiguration configuration); +} +public class Features : IReadOnlyCollection +{ + private Dictionary _features; + public int Count => _features?.Count ?? 0; + /// + /// Gets the feature of type . + /// + /// The type of the feature. + /// The feature or null if feature not exists. + public TFeatureToFind Get() where TFeatureToFind : TFeature => + _features == null ? default : (TFeatureToFind)_features.GetValueOrDefault(typeof(TFeatureToFind)); + /// + /// Add or update the feature. Existing feature of the same type will be replaced. + /// + /// The feature. + public void Set(TFeature feature) { - void Configure(IGlobalConfiguration configuration); + _features ??= new Dictionary(); + _features[feature.GetType()] = feature; } - public interface IMappingFeature + public IEnumerator GetEnumerator() => + _features == null ? Enumerable.Empty().GetEnumerator() : _features.Values.GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); +} +public static class FeatureExtensions +{ + public static IMapperConfigurationExpression SetFeature(this IMapperConfigurationExpression configuration, IGlobalFeature feature) { - void Configure(TypeMap typeMap); - IMappingFeature Reverse(); + configuration.Internal().Features.Set(feature); + return configuration; } - public interface IRuntimeFeature + public static IMappingExpression SetFeature(this IMappingExpression mapping, IMappingFeature feature) { - void Seal(IGlobalConfiguration configuration); + mapping.Features.Set(feature); + return mapping; } - public class Features : IReadOnlyCollection + internal static void Configure(this Features features, MapperConfiguration mapperConfiguration) { - private Dictionary _features; - public int Count => _features?.Count ?? 0; - /// - /// Gets the feature of type . - /// - /// The type of the feature. - /// The feature or null if feature not exists. - public TFeatureToFind Get() where TFeatureToFind : TFeature => - _features == null ? default : (TFeatureToFind)_features.GetValueOrDefault(typeof(TFeatureToFind)); - /// - /// Add or update the feature. Existing feature of the same type will be replaced. - /// - /// The feature. - public void Set(TFeature feature) + if (features.Count == 0) { - _features ??= new Dictionary(); - _features[feature.GetType()] = feature; + return; } - public IEnumerator GetEnumerator() => - _features == null ? Enumerable.Empty().GetEnumerator() : _features.Values.GetEnumerator(); - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - } - public static class FeatureExtensions - { - public static IMapperConfigurationExpression SetFeature(this IMapperConfigurationExpression configuration, IGlobalFeature feature) + foreach (var feature in features) { - configuration.Internal().Features.Set(feature); - return configuration; + feature.Configure(mapperConfiguration); } - public static IMappingExpression SetFeature(this IMappingExpression mapping, IMappingFeature feature) + } + public static void ReverseTo(this Features features, Features reversedFeatures) + { + if (features.Count == 0) { - mapping.Features.Set(feature); - return mapping; + return; } - internal static void Configure(this Features features, MapperConfiguration mapperConfiguration) + foreach (var feature in features) { - if (features.Count == 0) - { - return; - } - foreach (var feature in features) + var reverse = feature.Reverse(); + if (reverse != null) { - feature.Configure(mapperConfiguration); + reversedFeatures.Set(reverse); } } - public static void ReverseTo(this Features features, Features reversedFeatures) + } + internal static void Configure(this Features features, TypeMap typeMap) + { + if (features.Count == 0) { - if (features.Count == 0) - { - return; - } - foreach (var feature in features) - { - var reverse = feature.Reverse(); - if (reverse != null) - { - reversedFeatures.Set(reverse); - } - } + return; } - internal static void Configure(this Features features, TypeMap typeMap) + foreach (var feature in features) { - if (features.Count == 0) - { - return; - } - foreach (var feature in features) - { - feature.Configure(typeMap); - } + feature.Configure(typeMap); + } + } + internal static void Seal(this Features features, IGlobalConfiguration configuration) + { + if (features.Count == 0) + { + return; } - internal static void Seal(this Features features, IGlobalConfiguration configuration) + foreach (var feature in features) { - if (features.Count == 0) - { - return; - } - foreach (var feature in features) - { - feature.Seal(configuration); - } + feature.Seal(configuration); } } } \ No newline at end of file diff --git a/src/AutoMapper/Internal/InternalApi.cs b/src/AutoMapper/Internal/InternalApi.cs index 37bdb059a3..ec1600110e 100644 --- a/src/AutoMapper/Internal/InternalApi.cs +++ b/src/AutoMapper/Internal/InternalApi.cs @@ -10,191 +10,190 @@ using AutoMapper.Internal.Mappers; using AutoMapper.QueryableExtensions.Impl; -namespace AutoMapper.Internal +namespace AutoMapper.Internal; + +using Validator = Action; +[EditorBrowsable(EditorBrowsableState.Never)] +public static class InternalApi +{ + public static IGlobalConfiguration Internal(this IConfigurationProvider configuration) => (IGlobalConfiguration)configuration; + public static IGlobalConfigurationExpression Internal(this IMapperConfigurationExpression configuration) => (IGlobalConfigurationExpression)configuration; + public static IProfileExpressionInternal Internal(this IProfileExpression profile) => (IProfileExpressionInternal)profile; +} +[EditorBrowsable(EditorBrowsableState.Never)] +public interface IGlobalConfigurationExpression : IMapperConfigurationExpression, IProfileExpressionInternal +{ + Func ServiceCtor { get; } + IReadOnlyCollection Profiles { get; } + /// + /// Get the features collection. + /// + Features Features { get; } + /// + /// Object mappers + /// + List Mappers { get; } + /// + /// Add an action to be called when validating the configuration. + /// + /// the validation callback + void Validator(Validator validator); + /// + /// Allow the same map to exist in different profiles. + /// The default is to throw an exception, true means the maps are merged. + /// + bool AllowAdditiveTypeMapCreation { get; set; } + /// + /// How many levels deep should AutoMapper try to inline the execution plan for child classes. + /// See the docs for details. + /// + int MaxExecutionPlanDepth { get; set; } + List Validators { get; } + List ProjectionMappers { get; } + /// + /// How many levels deep should recursive queries be expanded. + /// Must be zero for EF6. Can be greater than zero for EF Core. + /// + int RecursiveQueriesMaxDepth { get; set; } +} +[EditorBrowsable(EditorBrowsableState.Never)] +public interface IGlobalConfiguration : IConfigurationProvider +{ + TypeMap ResolveAssociatedTypeMap(TypePair types); + /// + /// Get all configured type maps created + /// + /// All configured type maps + IReadOnlyCollection GetAllTypeMaps(); + /// + /// Find the for the configured source and destination type + /// + /// Configured source type + /// Configured destination type + /// Type map configuration + TypeMap FindTypeMapFor(Type sourceType, Type destinationType); + /// + /// Find the for the configured type pair + /// + /// Type pair + /// Type map configuration + TypeMap FindTypeMapFor(TypePair typePair); + /// + /// Find the for the configured source and destination type + /// + /// Source type + /// Destination type + /// Type map configuration + TypeMap FindTypeMapFor(); + /// + /// Resolve the for the configured source and destination type, checking parent types + /// + /// Configured source type + /// Configured destination type + /// Type map configuration + TypeMap ResolveTypeMap(Type sourceType, Type destinationType); + /// + /// Resolve the for the configured type pair, checking parent types + /// + /// Type pair + /// Type map configuration + TypeMap ResolveTypeMap(TypePair typePair); + /// + /// Dry run single type map + /// + /// Type map to check + void AssertConfigurationIsValid(TypeMap typeMap); + /// + /// Dry run all type maps in given profile + /// + /// Profile name of type maps to test + void AssertConfigurationIsValid(string profileName); + /// + /// Dry run all type maps in given profile + /// + /// Profile type + void AssertConfigurationIsValid() where TProfile : Profile, new(); + /// + /// Get all configured mappers + /// + /// List of mappers + IEnumerable GetMappers(); + /// + /// Gets the features collection. + /// + /// The feature collection. + Features Features { get; } + /// + /// Find a matching object mapper. + /// + /// the types to match + /// the matching mapper or null + IObjectMapper FindMapper(TypePair types); + IProjectionBuilder ProjectionBuilder { get; } + Func GetExecutionPlan(in MapRequest mapRequest); + void RegisterTypeMap(TypeMap typeMap); + /// + /// Builds the execution plan used to map the source to destination. + /// Useful to understand what exactly is happening during mapping. + /// See the wiki for details. + /// + /// The source/destination map request + /// the execution plan + LambdaExpression BuildExecutionPlan(in MapRequest mapRequest); + /// + /// Allows to enable null-value propagation for query mapping. + /// Some providers (such as EntityFrameworkQueryVisitor) do not work with this feature enabled! + /// + bool EnableNullPropagationForQueryMapping { get; } + /// + /// Factory method to create formatters, resolvers and type converters + /// + Func ServiceCtor { get; } + int MaxExecutionPlanDepth { get; } + int RecursiveQueriesMaxDepth { get; } + ProfileMap[] Profiles { get; } + TypeMap GetIncludedTypeMap(TypePair typePair); + TypeMap GetIncludedTypeMap(Type sourceType, Type destinationType); + TypeMap[] GetIncludedTypeMaps(IReadOnlyCollection includedTypes); + void RegisterAsMap(TypeMapConfiguration typeMapConfiguration); + ParameterExpression[] Parameters { get; } + List SourceMembers { get; } + List Variables { get; } + List Expressions { get; } + HashSet TypeMapsPath { get; } + CatchBlock[] Catches { get; } + DefaultExpression GetDefault(Type type); + ParameterReplaceVisitor ParameterReplaceVisitor(); + ConvertParameterReplaceVisitor ConvertParameterReplaceVisitor(); +} +[EditorBrowsable(EditorBrowsableState.Never)] +public interface IProfileExpressionInternal : IProfileExpression { - using Validator = Action; - [EditorBrowsable(EditorBrowsableState.Never)] - public static class InternalApi - { - public static IGlobalConfiguration Internal(this IConfigurationProvider configuration) => (IGlobalConfiguration)configuration; - public static IGlobalConfigurationExpression Internal(this IMapperConfigurationExpression configuration) => (IGlobalConfigurationExpression)configuration; - public static IProfileExpressionInternal Internal(this IProfileExpression profile) => (IProfileExpressionInternal)profile; - } - [EditorBrowsable(EditorBrowsableState.Never)] - public interface IGlobalConfigurationExpression : IMapperConfigurationExpression, IProfileExpressionInternal - { - Func ServiceCtor { get; } - IReadOnlyCollection Profiles { get; } - /// - /// Get the features collection. - /// - Features Features { get; } - /// - /// Object mappers - /// - List Mappers { get; } - /// - /// Add an action to be called when validating the configuration. - /// - /// the validation callback - void Validator(Validator validator); - /// - /// Allow the same map to exist in different profiles. - /// The default is to throw an exception, true means the maps are merged. - /// - bool AllowAdditiveTypeMapCreation { get; set; } - /// - /// How many levels deep should AutoMapper try to inline the execution plan for child classes. - /// See the docs for details. - /// - int MaxExecutionPlanDepth { get; set; } - List Validators { get; } - List ProjectionMappers { get; } - /// - /// How many levels deep should recursive queries be expanded. - /// Must be zero for EF6. Can be greater than zero for EF Core. - /// - int RecursiveQueriesMaxDepth { get; set; } - } - [EditorBrowsable(EditorBrowsableState.Never)] - public interface IGlobalConfiguration : IConfigurationProvider - { - TypeMap ResolveAssociatedTypeMap(TypePair types); - /// - /// Get all configured type maps created - /// - /// All configured type maps - IReadOnlyCollection GetAllTypeMaps(); - /// - /// Find the for the configured source and destination type - /// - /// Configured source type - /// Configured destination type - /// Type map configuration - TypeMap FindTypeMapFor(Type sourceType, Type destinationType); - /// - /// Find the for the configured type pair - /// - /// Type pair - /// Type map configuration - TypeMap FindTypeMapFor(TypePair typePair); - /// - /// Find the for the configured source and destination type - /// - /// Source type - /// Destination type - /// Type map configuration - TypeMap FindTypeMapFor(); - /// - /// Resolve the for the configured source and destination type, checking parent types - /// - /// Configured source type - /// Configured destination type - /// Type map configuration - TypeMap ResolveTypeMap(Type sourceType, Type destinationType); - /// - /// Resolve the for the configured type pair, checking parent types - /// - /// Type pair - /// Type map configuration - TypeMap ResolveTypeMap(TypePair typePair); - /// - /// Dry run single type map - /// - /// Type map to check - void AssertConfigurationIsValid(TypeMap typeMap); - /// - /// Dry run all type maps in given profile - /// - /// Profile name of type maps to test - void AssertConfigurationIsValid(string profileName); - /// - /// Dry run all type maps in given profile - /// - /// Profile type - void AssertConfigurationIsValid() where TProfile : Profile, new(); - /// - /// Get all configured mappers - /// - /// List of mappers - IEnumerable GetMappers(); - /// - /// Gets the features collection. - /// - /// The feature collection. - Features Features { get; } - /// - /// Find a matching object mapper. - /// - /// the types to match - /// the matching mapper or null - IObjectMapper FindMapper(TypePair types); - IProjectionBuilder ProjectionBuilder { get; } - Func GetExecutionPlan(in MapRequest mapRequest); - void RegisterTypeMap(TypeMap typeMap); - /// - /// Builds the execution plan used to map the source to destination. - /// Useful to understand what exactly is happening during mapping. - /// See the wiki for details. - /// - /// The source/destination map request - /// the execution plan - LambdaExpression BuildExecutionPlan(in MapRequest mapRequest); - /// - /// Allows to enable null-value propagation for query mapping. - /// Some providers (such as EntityFrameworkQueryVisitor) do not work with this feature enabled! - /// - bool EnableNullPropagationForQueryMapping { get; } - /// - /// Factory method to create formatters, resolvers and type converters - /// - Func ServiceCtor { get; } - int MaxExecutionPlanDepth { get; } - int RecursiveQueriesMaxDepth { get; } - ProfileMap[] Profiles { get; } - TypeMap GetIncludedTypeMap(TypePair typePair); - TypeMap GetIncludedTypeMap(Type sourceType, Type destinationType); - TypeMap[] GetIncludedTypeMaps(IReadOnlyCollection includedTypes); - void RegisterAsMap(TypeMapConfiguration typeMapConfiguration); - ParameterExpression[] Parameters { get; } - List SourceMembers { get; } - List Variables { get; } - List Expressions { get; } - HashSet TypeMapsPath { get; } - CatchBlock[] Catches { get; } - DefaultExpression GetDefault(Type type); - ParameterReplaceVisitor ParameterReplaceVisitor(); - ConvertParameterReplaceVisitor ConvertParameterReplaceVisitor(); - } - [EditorBrowsable(EditorBrowsableState.Never)] - public interface IProfileExpressionInternal : IProfileExpression - { - List Prefixes { get; } - List Postfixes { get; } - MemberConfiguration MemberConfiguration { get; } - /// - /// Allows to enable null-value propagation for query mapping. - /// Some providers (such as EntityFrameworkQueryVisitor) do not work with this feature enabled! - /// - bool? EnableNullPropagationForQueryMapping { get; set; } - /// - /// Disable method mapping. Use this if you don't intend to have AutoMapper try to map from methods. - /// - bool? MethodMappingEnabled { get; set; } - /// - /// Disable fields mapping. Use this if you don't intend to have AutoMapper try to map from/to fields. - /// - bool? FieldMappingEnabled { get; set; } - /// - /// Specify common configuration for all type maps. - /// - /// configuration callback - void ForAllMaps(Action configuration); - /// - /// Customize configuration for all members across all maps - /// - /// Condition - /// Callback for member options. Use the property map for conditional maps. - void ForAllPropertyMaps(Func condition, Action memberOptions); - } + List Prefixes { get; } + List Postfixes { get; } + MemberConfiguration MemberConfiguration { get; } + /// + /// Allows to enable null-value propagation for query mapping. + /// Some providers (such as EntityFrameworkQueryVisitor) do not work with this feature enabled! + /// + bool? EnableNullPropagationForQueryMapping { get; set; } + /// + /// Disable method mapping. Use this if you don't intend to have AutoMapper try to map from methods. + /// + bool? MethodMappingEnabled { get; set; } + /// + /// Disable fields mapping. Use this if you don't intend to have AutoMapper try to map from/to fields. + /// + bool? FieldMappingEnabled { get; set; } + /// + /// Specify common configuration for all type maps. + /// + /// configuration callback + void ForAllMaps(Action configuration); + /// + /// Customize configuration for all members across all maps + /// + /// Condition + /// Callback for member options. Use the property map for conditional maps. + void ForAllPropertyMaps(Func condition, Action memberOptions); } \ No newline at end of file diff --git a/src/AutoMapper/Internal/LockingConcurrentDictionary.cs b/src/AutoMapper/Internal/LockingConcurrentDictionary.cs index d9c3ce74ad..65e7b3abc3 100644 --- a/src/AutoMapper/Internal/LockingConcurrentDictionary.cs +++ b/src/AutoMapper/Internal/LockingConcurrentDictionary.cs @@ -1,24 +1,23 @@ using System; using System.Collections.Concurrent; -namespace AutoMapper.Internal +namespace AutoMapper.Internal; + +public readonly struct LockingConcurrentDictionary { - public readonly struct LockingConcurrentDictionary - { - private readonly ConcurrentDictionaryWrapper> _dictionary; - public LockingConcurrentDictionary(Func valueFactory, int capacity = 31) => - _dictionary = new(key => new(() => valueFactory(key)), capacity); - public TValue GetOrAdd(in TKey key) => _dictionary.GetOrAdd(key).Value; - } - public readonly struct ConcurrentDictionaryWrapper + private readonly ConcurrentDictionaryWrapper> _dictionary; + public LockingConcurrentDictionary(Func valueFactory, int capacity = 31) => + _dictionary = new(key => new(() => valueFactory(key)), capacity); + public TValue GetOrAdd(in TKey key) => _dictionary.GetOrAdd(key).Value; +} +public readonly struct ConcurrentDictionaryWrapper +{ + private readonly ConcurrentDictionary _dictionary; + private readonly Func _valueFactory; + public ConcurrentDictionaryWrapper(Func valueFactory, int capacity = 31) { - private readonly ConcurrentDictionary _dictionary; - private readonly Func _valueFactory; - public ConcurrentDictionaryWrapper(Func valueFactory, int capacity = 31) - { - _dictionary = new(Environment.ProcessorCount, capacity); - _valueFactory = valueFactory; - } - public TValue GetOrAdd(in TKey key) => _dictionary.GetOrAdd(key, _valueFactory); + _dictionary = new(Environment.ProcessorCount, capacity); + _valueFactory = valueFactory; } + public TValue GetOrAdd(in TKey key) => _dictionary.GetOrAdd(key, _valueFactory); } \ No newline at end of file diff --git a/src/AutoMapper/Internal/MemberPath.cs b/src/AutoMapper/Internal/MemberPath.cs index 1ca0e82a2e..07c1499680 100644 --- a/src/AutoMapper/Internal/MemberPath.cs +++ b/src/AutoMapper/Internal/MemberPath.cs @@ -3,43 +3,42 @@ using System.ComponentModel; using System.Linq; using System.Reflection; -namespace AutoMapper.Internal +namespace AutoMapper.Internal; + +using Execution; +[EditorBrowsable(EditorBrowsableState.Never)] +public readonly record struct MemberPath(MemberInfo[] Members) { - using Execution; - [EditorBrowsable(EditorBrowsableState.Never)] - public readonly record struct MemberPath(MemberInfo[] Members) + public static readonly MemberPath Empty = new(Array.Empty()); + public MemberPath(Stack members) : this(members.ToMemberInfos()){} + public MemberInfo Last => Members[^1]; + public MemberInfo First => Members[0]; + public int Length => Members.Length; + public bool Equals(MemberPath other) => Members.SequenceEqual(other.Members); + public override int GetHashCode() { - public static readonly MemberPath Empty = new(Array.Empty()); - public MemberPath(Stack members) : this(members.ToMemberInfos()){} - public MemberInfo Last => Members[^1]; - public MemberInfo First => Members[0]; - public int Length => Members.Length; - public bool Equals(MemberPath other) => Members.SequenceEqual(other.Members); - public override int GetHashCode() + var hashCode = new HashCode(); + foreach(var member in Members) { - var hashCode = new HashCode(); - foreach(var member in Members) - { - hashCode.Add(member); - } - return hashCode.ToHashCode(); + hashCode.Add(member); + } + return hashCode.ToHashCode(); + } + public override string ToString() => string.Join(".", Members.Select(mi => mi.Name)); + public bool StartsWith(MemberPath path) + { + if (path.Length > Length) + { + return false; } - public override string ToString() => string.Join(".", Members.Select(mi => mi.Name)); - public bool StartsWith(MemberPath path) + for (int index = 0; index < path.Length; index++) { - if (path.Length > Length) + if (Members[index] != path.Members[index]) { return false; } - for (int index = 0; index < path.Length; index++) - { - if (Members[index] != path.Members[index]) - { - return false; - } - } - return true; } - public MemberPath Concat(IEnumerable memberInfos) => new(Members.Concat(memberInfos).ToArray()); + return true; } + public MemberPath Concat(IEnumerable memberInfos) => new(Members.Concat(memberInfos).ToArray()); } \ No newline at end of file diff --git a/src/AutoMapper/Internal/PrimitiveHelper.cs b/src/AutoMapper/Internal/PrimitiveHelper.cs index 401bb74b83..b2f8f1185d 100644 --- a/src/AutoMapper/Internal/PrimitiveHelper.cs +++ b/src/AutoMapper/Internal/PrimitiveHelper.cs @@ -5,35 +5,34 @@ using System.Linq; using System.Linq.Expressions; using System.Runtime.CompilerServices; -namespace AutoMapper.Internal +namespace AutoMapper.Internal; + +[EditorBrowsable(EditorBrowsableState.Never)] +public static class PrimitiveHelper { - [EditorBrowsable(EditorBrowsableState.Never)] - public static class PrimitiveHelper + public static ReadOnlyCollection ToReadOnly(this T item) where T : Expression => new ReadOnlyCollectionBuilder{ item }.ToReadOnlyCollection(); + public static IReadOnlyCollection NullCheck(this IReadOnlyCollection source) => source ?? Array.Empty(); + public static IEnumerable Concat(this IReadOnlyCollection collection, IReadOnlyCollection otherCollection) { - public static ReadOnlyCollection ToReadOnly(this T item) where T : Expression => new ReadOnlyCollectionBuilder{ item }.ToReadOnlyCollection(); - public static IReadOnlyCollection NullCheck(this IReadOnlyCollection source) => source ?? Array.Empty(); - public static IEnumerable Concat(this IReadOnlyCollection collection, IReadOnlyCollection otherCollection) + if (otherCollection == null || otherCollection.Count == 0) { - if (otherCollection == null || otherCollection.Count == 0) - { - return collection; - } - if (collection.Count == 0) - { - return otherCollection; - } - return Enumerable.Concat(collection, otherCollection); + return collection; } - public static void CheckIsDerivedFrom(this TypePair types, TypePair baseTypes) + if (collection.Count == 0) { - types.SourceType.CheckIsDerivedFrom(baseTypes.SourceType); - types.DestinationType.CheckIsDerivedFrom(baseTypes.DestinationType); + return otherCollection; } - public static bool IsCollection(this TypePair context) => context.SourceType.IsCollection() && context.DestinationType.IsCollection(); - public static bool IsEnumToEnum(this TypePair context) => context.SourceType.IsEnum && context.DestinationType.IsEnum; - public static bool IsUnderlyingTypeToEnum(this TypePair context) => - context.DestinationType.IsEnum && context.SourceType.IsAssignableFrom(Enum.GetUnderlyingType(context.DestinationType)); - public static bool IsEnumToUnderlyingType(this TypePair context) => - context.SourceType.IsEnum && context.DestinationType.IsAssignableFrom(Enum.GetUnderlyingType(context.SourceType)); + return Enumerable.Concat(collection, otherCollection); } + public static void CheckIsDerivedFrom(this TypePair types, TypePair baseTypes) + { + types.SourceType.CheckIsDerivedFrom(baseTypes.SourceType); + types.DestinationType.CheckIsDerivedFrom(baseTypes.DestinationType); + } + public static bool IsCollection(this TypePair context) => context.SourceType.IsCollection() && context.DestinationType.IsCollection(); + public static bool IsEnumToEnum(this TypePair context) => context.SourceType.IsEnum && context.DestinationType.IsEnum; + public static bool IsUnderlyingTypeToEnum(this TypePair context) => + context.DestinationType.IsEnum && context.SourceType.IsAssignableFrom(Enum.GetUnderlyingType(context.DestinationType)); + public static bool IsEnumToUnderlyingType(this TypePair context) => + context.SourceType.IsEnum && context.DestinationType.IsAssignableFrom(Enum.GetUnderlyingType(context.SourceType)); } \ No newline at end of file diff --git a/src/AutoMapper/Internal/ReflectionHelper.cs b/src/AutoMapper/Internal/ReflectionHelper.cs index d43b789d4a..bedb9cd821 100644 --- a/src/AutoMapper/Internal/ReflectionHelper.cs +++ b/src/AutoMapper/Internal/ReflectionHelper.cs @@ -2,117 +2,116 @@ using System.ComponentModel; using System.Linq.Expressions; using System.Reflection; -namespace AutoMapper.Internal +namespace AutoMapper.Internal; + +using static Expression; +using static Execution.ExpressionBuilder; +[EditorBrowsable(EditorBrowsableState.Never)] +public static class ReflectionHelper { - using static Expression; - using static Execution.ExpressionBuilder; - [EditorBrowsable(EditorBrowsableState.Never)] - public static class ReflectionHelper + public static Type FirstParameterType(this MethodBase method) => method.GetParameters()[0].ParameterType; + public static Type GetElementType(Type type) => type.IsArray ? type.GetElementType() : GetEnumerableElementType(type); + public static Type GetEnumerableElementType(Type type) => type.GetIEnumerableType()?.GenericTypeArguments[0] ?? typeof(object); + public static TypeMap[] GetIncludedTypeMaps(this IGlobalConfiguration configuration, TypeMap typeMap) => + configuration.GetIncludedTypeMaps(typeMap.IncludedDerivedTypes); + public static bool IsPublic(this PropertyInfo propertyInfo) => (propertyInfo.GetGetMethod() ?? propertyInfo.GetSetMethod()) != null; + public static bool Has(this MemberInfo member) where TAttribute : Attribute => member.IsDefined(typeof(TAttribute)); + public static bool CanBeSet(this MemberInfo member) => member is PropertyInfo property ? property.CanWrite : !((FieldInfo)member).IsInitOnly; + public static Expression GetDefaultValue(this ParameterInfo parameter, IGlobalConfiguration configuration) => + parameter is { DefaultValue: null, ParameterType: { IsValueType: true } type } ? configuration.Default(type) : ToType(Constant(parameter.DefaultValue), parameter.ParameterType); + public static object MapMember(this ResolutionContext context, MemberInfo member, object source, object destination = null) { - public static Type FirstParameterType(this MethodBase method) => method.GetParameters()[0].ParameterType; - public static Type GetElementType(Type type) => type.IsArray ? type.GetElementType() : GetEnumerableElementType(type); - public static Type GetEnumerableElementType(Type type) => type.GetIEnumerableType()?.GenericTypeArguments[0] ?? typeof(object); - public static TypeMap[] GetIncludedTypeMaps(this IGlobalConfiguration configuration, TypeMap typeMap) => - configuration.GetIncludedTypeMaps(typeMap.IncludedDerivedTypes); - public static bool IsPublic(this PropertyInfo propertyInfo) => (propertyInfo.GetGetMethod() ?? propertyInfo.GetSetMethod()) != null; - public static bool Has(this MemberInfo member) where TAttribute : Attribute => member.IsDefined(typeof(TAttribute)); - public static bool CanBeSet(this MemberInfo member) => member is PropertyInfo property ? property.CanWrite : !((FieldInfo)member).IsInitOnly; - public static Expression GetDefaultValue(this ParameterInfo parameter, IGlobalConfiguration configuration) => - parameter is { DefaultValue: null, ParameterType: { IsValueType: true } type } ? configuration.Default(type) : ToType(Constant(parameter.DefaultValue), parameter.ParameterType); - public static object MapMember(this ResolutionContext context, MemberInfo member, object source, object destination = null) - { - var memberType = GetMemberType(member); - var destValue = destination == null ? null : GetMemberValue(member, destination); - return context.Map(source, destValue, null, memberType, MemberMap.Instance); - } - public static void SetMemberValue(this MemberInfo propertyOrField, object target, object value) + var memberType = GetMemberType(member); + var destValue = destination == null ? null : GetMemberValue(member, destination); + return context.Map(source, destValue, null, memberType, MemberMap.Instance); + } + public static void SetMemberValue(this MemberInfo propertyOrField, object target, object value) + { + if (propertyOrField is PropertyInfo property) { - if (propertyOrField is PropertyInfo property) + if (property.CanWrite) { - if (property.CanWrite) - { - property.SetValue(target, value, null); - } - return; + property.SetValue(target, value, null); } - if (propertyOrField is FieldInfo field) + return; + } + if (propertyOrField is FieldInfo field) + { + if (!field.IsInitOnly) { - if (!field.IsInitOnly) - { - field.SetValue(target, value); - } - return; + field.SetValue(target, value); } - throw Expected(propertyOrField); + return; } - private static ArgumentOutOfRangeException Expected(MemberInfo propertyOrField) => new(nameof(propertyOrField), "Expected a property or field, not " + propertyOrField); - public static object GetMemberValue(this MemberInfo propertyOrField, object target) => propertyOrField switch + throw Expected(propertyOrField); + } + private static ArgumentOutOfRangeException Expected(MemberInfo propertyOrField) => new(nameof(propertyOrField), "Expected a property or field, not " + propertyOrField); + public static object GetMemberValue(this MemberInfo propertyOrField, object target) => propertyOrField switch + { + PropertyInfo property => property.GetValue(target, null), + FieldInfo field => field.GetValue(target), + _ => throw Expected(propertyOrField) + }; + public static MemberInfo[] GetMemberPath(Type type, string fullMemberName, TypeMap typeMap = null) + { + var memberNames = fullMemberName.Split('.'); + var sourceDetails = typeMap?.SourceTypeDetails; + if (sourceDetails != null && memberNames.Length == 1) { - PropertyInfo property => property.GetValue(target, null), - FieldInfo field => field.GetValue(target), - _ => throw Expected(propertyOrField) - }; - public static MemberInfo[] GetMemberPath(Type type, string fullMemberName, TypeMap typeMap = null) + return new[] { sourceDetails.GetMember(memberNames[0]) }; + } + var members = new MemberInfo[memberNames.Length]; + Type previousType = type; + for(int index = 0; index < memberNames.Length; index++) { - var memberNames = fullMemberName.Split('.'); - var sourceDetails = typeMap?.SourceTypeDetails; - if (sourceDetails != null && memberNames.Length == 1) + var currentType = GetCurrentType(previousType); + var memberName = memberNames[index]; + var property = currentType.GetInheritedProperty(memberName); + if (property != null) + { + previousType = property.PropertyType; + members[index] = property; + } + else if (currentType.GetInheritedField(memberName) is FieldInfo field) { - return new[] { sourceDetails.GetMember(memberNames[0]) }; + previousType = field.FieldType; + members[index] = field; } - var members = new MemberInfo[memberNames.Length]; - Type previousType = type; - for(int index = 0; index < memberNames.Length; index++) + else { - var currentType = GetCurrentType(previousType); - var memberName = memberNames[index]; - var property = currentType.GetInheritedProperty(memberName); - if (property != null) - { - previousType = property.PropertyType; - members[index] = property; - } - else if (currentType.GetInheritedField(memberName) is FieldInfo field) - { - previousType = field.FieldType; - members[index] = field; - } - else - { - var method = currentType.GetInheritedMethod(memberName); - previousType = method.ReturnType; - members[index] = method; - } + var method = currentType.GetInheritedMethod(memberName); + previousType = method.ReturnType; + members[index] = method; } - return members; - static Type GetCurrentType(Type type) => type.IsGenericType && type.IsCollection() ? type.GenericTypeArguments[0] : type; } - public static MemberInfo FindProperty(LambdaExpression lambdaExpression) + return members; + static Type GetCurrentType(Type type) => type.IsGenericType && type.IsCollection() ? type.GenericTypeArguments[0] : type; + } + public static MemberInfo FindProperty(LambdaExpression lambdaExpression) + { + Expression expressionToCheck = lambdaExpression.Body; + while (true) { - Expression expressionToCheck = lambdaExpression.Body; - while (true) + switch (expressionToCheck) { - switch (expressionToCheck) - { - case MemberExpression { Member: var member, Expression: { NodeType: ExpressionType.Parameter or ExpressionType.Convert } }: - return member; - case UnaryExpression { Operand: var operand }: - expressionToCheck = operand; - break; - default: - throw new ArgumentException( - $"Expression '{lambdaExpression}' must resolve to top-level member and not any child object's properties. You can use ForPath, a custom resolver on the child type or the AfterMap option instead.", - nameof(lambdaExpression)); - } + case MemberExpression { Member: var member, Expression: { NodeType: ExpressionType.Parameter or ExpressionType.Convert } }: + return member; + case UnaryExpression { Operand: var operand }: + expressionToCheck = operand; + break; + default: + throw new ArgumentException( + $"Expression '{lambdaExpression}' must resolve to top-level member and not any child object's properties. You can use ForPath, a custom resolver on the child type or the AfterMap option instead.", + nameof(lambdaExpression)); } } - public static Type GetMemberType(this MemberInfo member) => member switch - { - PropertyInfo property => property.PropertyType, - MethodInfo method => method.ReturnType, - FieldInfo field => field.FieldType, - null => throw new ArgumentNullException(nameof(member)), - _ => throw new ArgumentOutOfRangeException(nameof(member)) - }; } + public static Type GetMemberType(this MemberInfo member) => member switch + { + PropertyInfo property => property.PropertyType, + MethodInfo method => method.ReturnType, + FieldInfo field => field.FieldType, + null => throw new ArgumentNullException(nameof(member)), + _ => throw new ArgumentOutOfRangeException(nameof(member)) + }; } \ No newline at end of file diff --git a/src/AutoMapper/Internal/TypeDetails.cs b/src/AutoMapper/Internal/TypeDetails.cs index 608d73750f..5be436b0c7 100644 --- a/src/AutoMapper/Internal/TypeDetails.cs +++ b/src/AutoMapper/Internal/TypeDetails.cs @@ -5,206 +5,205 @@ using System.Diagnostics; using System.Linq; using System.Reflection; -namespace AutoMapper.Internal +namespace AutoMapper.Internal; + +/// +/// Contains cached reflection information for easy retrieval +/// +[DebuggerDisplay("{Type}")] +[EditorBrowsable(EditorBrowsableState.Never)] +public class TypeDetails { - /// - /// Contains cached reflection information for easy retrieval - /// - [DebuggerDisplay("{Type}")] - [EditorBrowsable(EditorBrowsableState.Never)] - public class TypeDetails + private Dictionary _nameToMember; + private ConstructorParameters[] _constructors; + private MemberInfo[] _readAccessors; + private MemberInfo[] _writeAccessors; + public TypeDetails(Type type, ProfileMap config) { - private Dictionary _nameToMember; - private ConstructorParameters[] _constructors; - private MemberInfo[] _readAccessors; - private MemberInfo[] _writeAccessors; - public TypeDetails(Type type, ProfileMap config) + Type = type; + Config = config; + } + private ConstructorParameters[] GetConstructors() => + GetConstructors(Type, Config).Where(c=>c.ParametersCount > 0).OrderByDescending(c => c.ParametersCount).ToArray(); + public static IEnumerable GetConstructors(Type type, ProfileMap profileMap) => + type.GetDeclaredConstructors().Where(profileMap.ShouldUseConstructor).Select(c => new ConstructorParameters(c)); + public MemberInfo GetMember(string name) + { + if (_nameToMember == null) { - Type = type; - Config = config; + SetNameToMember(); } - private ConstructorParameters[] GetConstructors() => - GetConstructors(Type, Config).Where(c=>c.ParametersCount > 0).OrderByDescending(c => c.ParametersCount).ToArray(); - public static IEnumerable GetConstructors(Type type, ProfileMap profileMap) => - type.GetDeclaredConstructors().Where(profileMap.ShouldUseConstructor).Select(c => new ConstructorParameters(c)); - public MemberInfo GetMember(string name) + if (_nameToMember.TryGetValue(name, out var member) && Config.MethodMappingEnabled && member is GenericMethod genericMethod) { - if (_nameToMember == null) - { - SetNameToMember(); - } - if (_nameToMember.TryGetValue(name, out var member) && Config.MethodMappingEnabled && member is GenericMethod genericMethod) - { - return genericMethod.Close(); - } - return member; - void SetNameToMember() - { - _nameToMember = new(ReadAccessors.Length, StringComparer.OrdinalIgnoreCase); - IEnumerable accessors = ReadAccessors; - if (Config.MethodMappingEnabled) - { - accessors = AddMethods(accessors); - } - foreach (var member in accessors) - { - _nameToMember.TryAdd(member.Name, member); - if (Config.Postfixes.Count == 0 && Config.Prefixes.Count == 0) - { - continue; - } - CheckPrePostfixes(member); - } - } - IEnumerable AddMethods(IEnumerable accessors) + return genericMethod.Close(); + } + return member; + void SetNameToMember() + { + _nameToMember = new(ReadAccessors.Length, StringComparer.OrdinalIgnoreCase); + IEnumerable accessors = ReadAccessors; + if (Config.MethodMappingEnabled) { - var publicNoArgMethods = GetPublicNoArgMethods(); - var noArgExtensionMethods = GetNoArgExtensionMethods(Config.SourceExtensionMethods.Where(m => - !_nameToMember.ContainsKey(m.Name) && Config.ShouldMapMethod(m))); - return accessors.Concat(publicNoArgMethods).Concat(noArgExtensionMethods); + accessors = AddMethods(accessors); } - IEnumerable GetPublicNoArgMethods() => Type.GetMethods(BindingFlags.Instance | BindingFlags.Public).Where(m => - m.DeclaringType != typeof(object) && m.ReturnType != typeof(void) && !m.IsGenericMethodDefinition && !_nameToMember.ContainsKey(m.Name) && - Config.ShouldMapMethod(m) && m.GetParameters().Length == 0); - void CheckPrePostfixes(MemberInfo member) + foreach (var member in accessors) { - foreach (var memberName in PossibleNames(member.Name, Config.Prefixes, Config.Postfixes)) + _nameToMember.TryAdd(member.Name, member); + if (Config.Postfixes.Count == 0 && Config.Prefixes.Count == 0) { - _nameToMember.TryAdd(memberName, member); + continue; } + CheckPrePostfixes(member); } - IEnumerable GetNoArgExtensionMethods(IEnumerable sourceExtensionMethodSearch) + } + IEnumerable AddMethods(IEnumerable accessors) + { + var publicNoArgMethods = GetPublicNoArgMethods(); + var noArgExtensionMethods = GetNoArgExtensionMethods(Config.SourceExtensionMethods.Where(m => + !_nameToMember.ContainsKey(m.Name) && Config.ShouldMapMethod(m))); + return accessors.Concat(publicNoArgMethods).Concat(noArgExtensionMethods); + } + IEnumerable GetPublicNoArgMethods() => Type.GetMethods(BindingFlags.Instance | BindingFlags.Public).Where(m => + m.DeclaringType != typeof(object) && m.ReturnType != typeof(void) && !m.IsGenericMethodDefinition && !_nameToMember.ContainsKey(m.Name) && + Config.ShouldMapMethod(m) && m.GetParameters().Length == 0); + void CheckPrePostfixes(MemberInfo member) + { + foreach (var memberName in PossibleNames(member.Name, Config.Prefixes, Config.Postfixes)) { - var extensionMethods = (IEnumerable) - sourceExtensionMethodSearch.Where(method => !method.ContainsGenericParameters && method.FirstParameterType().IsAssignableFrom(Type)); - var genericInterfaces = Type.GetInterfaces().Where(t => t.IsGenericType); - if (Type.IsInterface && Type.IsGenericType) - { - genericInterfaces = genericInterfaces.Prepend(Type); - } - if (!genericInterfaces.Any()) - { - return extensionMethods; - } - var definitions = genericInterfaces.GroupBy(t => t.GetGenericTypeDefinition()).ToDictionary(g => g.Key, g => g.First()); - return extensionMethods.Concat( - from method in sourceExtensionMethodSearch - let targetType = method.FirstParameterType() - where targetType.IsInterface && targetType.ContainsGenericParameters - let genericInterface = definitions.GetValueOrDefault(targetType.GetGenericTypeDefinition()) - where genericInterface != null - select new GenericMethod(method, genericInterface)); + _nameToMember.TryAdd(memberName, member); } } - class GenericMethod : MemberInfo + IEnumerable GetNoArgExtensionMethods(IEnumerable sourceExtensionMethodSearch) { - readonly MethodInfo _genericMethod; - readonly Type _genericInterface; - MethodInfo _closedMethod = ExpressionBuilder.DecTypeDepthInfo; - public GenericMethod(MethodInfo genericMethod, Type genericInterface) + var extensionMethods = (IEnumerable) + sourceExtensionMethodSearch.Where(method => !method.ContainsGenericParameters && method.FirstParameterType().IsAssignableFrom(Type)); + var genericInterfaces = Type.GetInterfaces().Where(t => t.IsGenericType); + if (Type.IsInterface && Type.IsGenericType) { - _genericMethod = genericMethod; - _genericInterface = genericInterface; + genericInterfaces = genericInterfaces.Prepend(Type); } - public MethodInfo Close() + if (!genericInterfaces.Any()) { - if (_closedMethod == ExpressionBuilder.DecTypeDepthInfo) - { - // Use method.MakeGenericMethod(genericArguments) wrapped in a try/catch(ArgumentException) - // in order to catch exceptions resulting from the generic arguments not being compatible - // with any constraints that may be on the generic method's generic parameters. - try - { - _closedMethod = _genericMethod.MakeGenericMethod(_genericInterface.GenericTypeArguments); - } - catch (ArgumentException) - { - _closedMethod = null; - } - } - return _closedMethod; + return extensionMethods; } - public override Type DeclaringType => throw new NotImplementedException(); - public override MemberTypes MemberType => throw new NotImplementedException(); - public override string Name => _genericMethod.Name; - public override string ToString() => Name; - public override Type ReflectedType => throw new NotImplementedException(); - public override object[] GetCustomAttributes(bool inherit) => throw new NotImplementedException(); - public override object[] GetCustomAttributes(Type attributeType, bool inherit) => throw new NotImplementedException(); - public override bool IsDefined(Type attributeType, bool inherit) => throw new NotImplementedException(); + var definitions = genericInterfaces.GroupBy(t => t.GetGenericTypeDefinition()).ToDictionary(g => g.Key, g => g.First()); + return extensionMethods.Concat( + from method in sourceExtensionMethodSearch + let targetType = method.FirstParameterType() + where targetType.IsInterface && targetType.ContainsGenericParameters + let genericInterface = definitions.GetValueOrDefault(targetType.GetGenericTypeDefinition()) + where genericInterface != null + select new GenericMethod(method, genericInterface)); + } + } + class GenericMethod : MemberInfo + { + readonly MethodInfo _genericMethod; + readonly Type _genericInterface; + MethodInfo _closedMethod = ExpressionBuilder.DecTypeDepthInfo; + public GenericMethod(MethodInfo genericMethod, Type genericInterface) + { + _genericMethod = genericMethod; + _genericInterface = genericInterface; } - public static string[] PossibleNames(string memberName, HashSet prefixes, HashSet postfixes) + public MethodInfo Close() { - List result = null; - foreach (var prefix in prefixes) + if (_closedMethod == ExpressionBuilder.DecTypeDepthInfo) { - if (!memberName.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)) + // Use method.MakeGenericMethod(genericArguments) wrapped in a try/catch(ArgumentException) + // in order to catch exceptions resulting from the generic arguments not being compatible + // with any constraints that may be on the generic method's generic parameters. + try { - continue; + _closedMethod = _genericMethod.MakeGenericMethod(_genericInterface.GenericTypeArguments); } - var withoutPrefix = memberName[prefix.Length..]; - result ??= new(); - result.Add(withoutPrefix); - PostFixes(ref result, postfixes, withoutPrefix); - } - PostFixes(ref result, postfixes, memberName); - return result == null ? Array.Empty() : result.ToArray(); - static void PostFixes(ref List result, HashSet postfixes, string name) - { - foreach (var postfix in postfixes) + catch (ArgumentException) { - if (!name.EndsWith(postfix, StringComparison.OrdinalIgnoreCase)) - { - continue; - } - result ??= new(); - result.Add(name[..^postfix.Length]); + _closedMethod = null; } } + return _closedMethod; } - public Type Type { get; } - public ProfileMap Config { get; } - public MemberInfo[] ReadAccessors => _readAccessors ??= BuildReadAccessors(); - public MemberInfo[] WriteAccessors => _writeAccessors ??= BuildWriteAccessors(); - public ConstructorParameters[] Constructors => _constructors ??= GetConstructors(); - private MemberInfo[] BuildReadAccessors() + public override Type DeclaringType => throw new NotImplementedException(); + public override MemberTypes MemberType => throw new NotImplementedException(); + public override string Name => _genericMethod.Name; + public override string ToString() => Name; + public override Type ReflectedType => throw new NotImplementedException(); + public override object[] GetCustomAttributes(bool inherit) => throw new NotImplementedException(); + public override object[] GetCustomAttributes(Type attributeType, bool inherit) => throw new NotImplementedException(); + public override bool IsDefined(Type attributeType, bool inherit) => throw new NotImplementedException(); + } + public static string[] PossibleNames(string memberName, HashSet prefixes, HashSet postfixes) + { + List result = null; + foreach (var prefix in prefixes) { - // Multiple types may define the same property (e.g. the class and multiple interfaces) - filter this to one of those properties - IEnumerable members = GetProperties(PropertyReadable) - .GroupBy(x => x.Name) // group properties of the same name together - .Select(x => x.First()); - if (Config.FieldMappingEnabled) + if (!memberName.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)) { - members = members.Concat(GetFields(FieldReadable)); + continue; } - return members.ToArray(); + var withoutPrefix = memberName[prefix.Length..]; + result ??= new(); + result.Add(withoutPrefix); + PostFixes(ref result, postfixes, withoutPrefix); } - private MemberInfo[] BuildWriteAccessors() + PostFixes(ref result, postfixes, memberName); + return result == null ? Array.Empty() : result.ToArray(); + static void PostFixes(ref List result, HashSet postfixes, string name) { - // Multiple types may define the same property (e.g. the class and multiple interfaces) - filter this to one of those properties - IEnumerable members = GetProperties(PropertyWritable) - .GroupBy(x => x.Name) // group properties of the same name together - .Select(x => x.FirstOrDefault(y => y.CanWrite && y.CanRead) ?? x.First()); // favor the first property that can both read & write - otherwise pick the first one - if (Config.FieldMappingEnabled) + foreach (var postfix in postfixes) { - members = members.Concat(GetFields(FieldWritable)); + if (!name.EndsWith(postfix, StringComparison.OrdinalIgnoreCase)) + { + continue; + } + result ??= new(); + result.Add(name[..^postfix.Length]); } - return members.ToArray(); } - private static bool PropertyReadable(PropertyInfo propertyInfo) => propertyInfo.CanRead; - private static bool FieldReadable(FieldInfo fieldInfo) => true; - private static bool PropertyWritable(PropertyInfo propertyInfo) => propertyInfo.CanWrite || propertyInfo.PropertyType.IsCollection(); - private static bool FieldWritable(FieldInfo fieldInfo) => !fieldInfo.IsInitOnly; - private IEnumerable GetTypeInheritance() => Type.IsInterface ? Type.GetInterfaces().Prepend(Type) : Type.GetTypeInheritance(); - private IEnumerable GetProperties(Func propertyAvailableFor) => - GetTypeInheritance().SelectMany(type => type.GetProperties(TypeExtensions.InstanceFlags).Where(property => propertyAvailableFor(property) && Config.ShouldMapProperty(property))); - private IEnumerable GetFields(Func fieldAvailableFor) => - GetTypeInheritance().SelectMany(type => type.GetFields(TypeExtensions.InstanceFlags).Where(field => fieldAvailableFor(field) && Config.ShouldMapField(field))); } - public readonly record struct ConstructorParameters(ConstructorInfo Constructor, ParameterInfo[] Parameters) + public Type Type { get; } + public ProfileMap Config { get; } + public MemberInfo[] ReadAccessors => _readAccessors ??= BuildReadAccessors(); + public MemberInfo[] WriteAccessors => _writeAccessors ??= BuildWriteAccessors(); + public ConstructorParameters[] Constructors => _constructors ??= GetConstructors(); + private MemberInfo[] BuildReadAccessors() { - public ConstructorParameters(ConstructorInfo constructor) : this(constructor, constructor.GetParameters()){} - public int ParametersCount => Parameters.Length; - public bool AllParametersOptional() => Parameters.All(p => p.IsOptional); + // Multiple types may define the same property (e.g. the class and multiple interfaces) - filter this to one of those properties + IEnumerable members = GetProperties(PropertyReadable) + .GroupBy(x => x.Name) // group properties of the same name together + .Select(x => x.First()); + if (Config.FieldMappingEnabled) + { + members = members.Concat(GetFields(FieldReadable)); + } + return members.ToArray(); } + private MemberInfo[] BuildWriteAccessors() + { + // Multiple types may define the same property (e.g. the class and multiple interfaces) - filter this to one of those properties + IEnumerable members = GetProperties(PropertyWritable) + .GroupBy(x => x.Name) // group properties of the same name together + .Select(x => x.FirstOrDefault(y => y.CanWrite && y.CanRead) ?? x.First()); // favor the first property that can both read & write - otherwise pick the first one + if (Config.FieldMappingEnabled) + { + members = members.Concat(GetFields(FieldWritable)); + } + return members.ToArray(); + } + private static bool PropertyReadable(PropertyInfo propertyInfo) => propertyInfo.CanRead; + private static bool FieldReadable(FieldInfo fieldInfo) => true; + private static bool PropertyWritable(PropertyInfo propertyInfo) => propertyInfo.CanWrite || propertyInfo.PropertyType.IsCollection(); + private static bool FieldWritable(FieldInfo fieldInfo) => !fieldInfo.IsInitOnly; + private IEnumerable GetTypeInheritance() => Type.IsInterface ? Type.GetInterfaces().Prepend(Type) : Type.GetTypeInheritance(); + private IEnumerable GetProperties(Func propertyAvailableFor) => + GetTypeInheritance().SelectMany(type => type.GetProperties(TypeExtensions.InstanceFlags).Where(property => propertyAvailableFor(property) && Config.ShouldMapProperty(property))); + private IEnumerable GetFields(Func fieldAvailableFor) => + GetTypeInheritance().SelectMany(type => type.GetFields(TypeExtensions.InstanceFlags).Where(field => fieldAvailableFor(field) && Config.ShouldMapField(field))); +} +public readonly record struct ConstructorParameters(ConstructorInfo Constructor, ParameterInfo[] Parameters) +{ + public ConstructorParameters(ConstructorInfo constructor) : this(constructor, constructor.GetParameters()){} + public int ParametersCount => Parameters.Length; + public bool AllParametersOptional() => Parameters.All(p => p.IsOptional); } \ No newline at end of file diff --git a/src/AutoMapper/Internal/TypeExtensions.cs b/src/AutoMapper/Internal/TypeExtensions.cs index 77e6499103..d919027b0d 100644 --- a/src/AutoMapper/Internal/TypeExtensions.cs +++ b/src/AutoMapper/Internal/TypeExtensions.cs @@ -4,107 +4,106 @@ using System.Dynamic; using System.Linq; using System.Reflection; -namespace AutoMapper.Internal +namespace AutoMapper.Internal; + +public static class TypeExtensions { - public static class TypeExtensions - { - public const BindingFlags InstanceFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly; - public const BindingFlags StaticFlags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly; + public const BindingFlags InstanceFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly; + public const BindingFlags StaticFlags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly; - public static MethodInfo StaticGenericMethod(this Type type, string methodName, int parametersCount) + public static MethodInfo StaticGenericMethod(this Type type, string methodName, int parametersCount) + { + foreach (MethodInfo foundMethod in type.GetMember(methodName, MemberTypes.Method, StaticFlags & ~BindingFlags.NonPublic)) { - foreach (MethodInfo foundMethod in type.GetMember(methodName, MemberTypes.Method, StaticFlags & ~BindingFlags.NonPublic)) + if (foundMethod.IsGenericMethodDefinition && foundMethod.GetParameters().Length == parametersCount) { - if (foundMethod.IsGenericMethodDefinition && foundMethod.GetParameters().Length == parametersCount) - { - return foundMethod; - } + return foundMethod; } - throw new ArgumentOutOfRangeException(nameof(methodName), $"Cannot find suitable method {type}.{methodName}({parametersCount} parameters)."); } + throw new ArgumentOutOfRangeException(nameof(methodName), $"Cannot find suitable method {type}.{methodName}({parametersCount} parameters)."); + } - public static void CheckIsDerivedFrom(this Type derivedType, Type baseType) + public static void CheckIsDerivedFrom(this Type derivedType, Type baseType) + { + if (!baseType.IsAssignableFrom(derivedType) && !derivedType.IsGenericTypeDefinition && !baseType.IsGenericTypeDefinition) { - if (!baseType.IsAssignableFrom(derivedType) && !derivedType.IsGenericTypeDefinition && !baseType.IsGenericTypeDefinition) - { - throw new ArgumentOutOfRangeException(nameof(derivedType), $"{derivedType} is not derived from {baseType}."); - } + throw new ArgumentOutOfRangeException(nameof(derivedType), $"{derivedType} is not derived from {baseType}."); } + } - public static bool IsDynamic(this Type type) => typeof(IDynamicMetaObjectProvider).IsAssignableFrom(type); + public static bool IsDynamic(this Type type) => typeof(IDynamicMetaObjectProvider).IsAssignableFrom(type); - public static IEnumerable BaseClassesAndInterfaces(this Type type) + public static IEnumerable BaseClassesAndInterfaces(this Type type) + { + var currentType = type; + while ((currentType = currentType.BaseType) != null) { - var currentType = type; - while ((currentType = currentType.BaseType) != null) - { - yield return currentType; - } - foreach (var interfaceType in type.GetInterfaces()) - { - yield return interfaceType; - } + yield return currentType; } + foreach (var interfaceType in type.GetInterfaces()) + { + yield return interfaceType; + } + } - public static PropertyInfo GetInheritedProperty(this Type type, string name) => type.GetProperty(name, InstanceFlags) ?? type.GetBaseProperty(name); - static PropertyInfo GetBaseProperty(this Type type, string name) => - type.BaseClassesAndInterfaces().Select(t => t.GetProperty(name, InstanceFlags)).FirstOrDefault(p => p != null); - public static FieldInfo GetInheritedField(this Type type, string name) => type.GetField(name, InstanceFlags) ?? type.GetBaseField(name); - static FieldInfo GetBaseField(this Type type, string name) => - type.BaseClassesAndInterfaces().Select(t => t.GetField(name, InstanceFlags)).FirstOrDefault(f => f != null); - public static MethodInfo GetInheritedMethod(this Type type, string name) => type.GetInstanceMethod(name) ?? type.GetBaseMethod(name) ?? - throw new ArgumentOutOfRangeException(nameof(name), $"Cannot find member {name} of type {type}."); - static MethodInfo GetBaseMethod(this Type type, string name) => - type.BaseClassesAndInterfaces().Select(t => t.GetInstanceMethod(name)).FirstOrDefault(m => m != null); + public static PropertyInfo GetInheritedProperty(this Type type, string name) => type.GetProperty(name, InstanceFlags) ?? type.GetBaseProperty(name); + static PropertyInfo GetBaseProperty(this Type type, string name) => + type.BaseClassesAndInterfaces().Select(t => t.GetProperty(name, InstanceFlags)).FirstOrDefault(p => p != null); + public static FieldInfo GetInheritedField(this Type type, string name) => type.GetField(name, InstanceFlags) ?? type.GetBaseField(name); + static FieldInfo GetBaseField(this Type type, string name) => + type.BaseClassesAndInterfaces().Select(t => t.GetField(name, InstanceFlags)).FirstOrDefault(f => f != null); + public static MethodInfo GetInheritedMethod(this Type type, string name) => type.GetInstanceMethod(name) ?? type.GetBaseMethod(name) ?? + throw new ArgumentOutOfRangeException(nameof(name), $"Cannot find member {name} of type {type}."); + static MethodInfo GetBaseMethod(this Type type, string name) => + type.BaseClassesAndInterfaces().Select(t => t.GetInstanceMethod(name)).FirstOrDefault(m => m != null); - public static MemberInfo GetFieldOrProperty(this Type type, string name) - => type.GetInheritedProperty(name) ?? (MemberInfo)type.GetInheritedField(name) ?? throw new ArgumentOutOfRangeException(nameof(name), $"Cannot find member {name} of type {type}."); + public static MemberInfo GetFieldOrProperty(this Type type, string name) + => type.GetInheritedProperty(name) ?? (MemberInfo)type.GetInheritedField(name) ?? throw new ArgumentOutOfRangeException(nameof(name), $"Cannot find member {name} of type {type}."); - public static bool IsNullableType(this Type type) => type.IsGenericType(typeof(Nullable<>)); + public static bool IsNullableType(this Type type) => type.IsGenericType(typeof(Nullable<>)); - public static Type GetICollectionType(this Type type) => type.GetGenericInterface(typeof(ICollection<>)); + public static Type GetICollectionType(this Type type) => type.GetGenericInterface(typeof(ICollection<>)); - public static bool IsCollection(this Type type) => type != typeof(string) && typeof(IEnumerable).IsAssignableFrom(type); + public static bool IsCollection(this Type type) => type != typeof(string) && typeof(IEnumerable).IsAssignableFrom(type); - public static bool IsListType(this Type type) => typeof(IList).IsAssignableFrom(type); + public static bool IsListType(this Type type) => typeof(IList).IsAssignableFrom(type); - public static bool IsGenericType(this Type type, Type genericType) => type.IsGenericType && type.GetGenericTypeDefinition() == genericType; + public static bool IsGenericType(this Type type, Type genericType) => type.IsGenericType && type.GetGenericTypeDefinition() == genericType; - public static Type GetIEnumerableType(this Type type) => type.GetGenericInterface(typeof(IEnumerable<>)); + public static Type GetIEnumerableType(this Type type) => type.GetGenericInterface(typeof(IEnumerable<>)); - public static Type GetGenericInterface(this Type type, Type genericInterface) + public static Type GetGenericInterface(this Type type, Type genericInterface) + { + if (type.IsGenericType(genericInterface)) { - if (type.IsGenericType(genericInterface)) - { - return type; - } - var interfaces = type.GetInterfaces(); - for (int index = interfaces.Length - 1; index >= 0; index--) + return type; + } + var interfaces = type.GetInterfaces(); + for (int index = interfaces.Length - 1; index >= 0; index--) + { + var interfaceType = interfaces[index]; + if (interfaceType.IsGenericType(genericInterface)) { - var interfaceType = interfaces[index]; - if (interfaceType.IsGenericType(genericInterface)) - { - return interfaceType; - } + return interfaceType; } - return null; } + return null; + } - public static ConstructorInfo[] GetDeclaredConstructors(this Type type) => type.GetConstructors(InstanceFlags); + public static ConstructorInfo[] GetDeclaredConstructors(this Type type) => type.GetConstructors(InstanceFlags); - public static int GenericParametersCount(this Type type) => type.GetTypeInfo().GenericTypeParameters.Length; + public static int GenericParametersCount(this Type type) => type.GetTypeInfo().GenericTypeParameters.Length; - public static IEnumerable GetTypeInheritance(this Type type) + public static IEnumerable GetTypeInheritance(this Type type) + { + while (type != null) { - while (type != null) - { - yield return type; - type = type.BaseType; - } + yield return type; + type = type.BaseType; } - - public static MethodInfo GetStaticMethod(this Type type, string name) => type.GetMethod(name, StaticFlags); - public static MethodInfo GetInstanceMethod(this Type type, string name) => - (MethodInfo)type.GetMember(name, MemberTypes.Method, InstanceFlags).FirstOrDefault(); } + + public static MethodInfo GetStaticMethod(this Type type, string name) => type.GetMethod(name, StaticFlags); + public static MethodInfo GetInstanceMethod(this Type type, string name) => + (MethodInfo)type.GetMember(name, MemberTypes.Method, InstanceFlags).FirstOrDefault(); } \ No newline at end of file diff --git a/src/AutoMapper/Internal/TypePair.cs b/src/AutoMapper/Internal/TypePair.cs index 5aed7ac2c9..27a3f10789 100644 --- a/src/AutoMapper/Internal/TypePair.cs +++ b/src/AutoMapper/Internal/TypePair.cs @@ -1,36 +1,35 @@ using System; using System.Diagnostics; -namespace AutoMapper.Internal +namespace AutoMapper.Internal; + +[DebuggerDisplay("{RequestedTypes.SourceType.Name}, {RequestedTypes.DestinationType.Name} : {RuntimeTypes.SourceType.Name}, {RuntimeTypes.DestinationType.Name}")] +public readonly record struct MapRequest(TypePair RequestedTypes, TypePair RuntimeTypes, MemberMap MemberMap) { - [DebuggerDisplay("{RequestedTypes.SourceType.Name}, {RequestedTypes.DestinationType.Name} : {RuntimeTypes.SourceType.Name}, {RuntimeTypes.DestinationType.Name}")] - public readonly record struct MapRequest(TypePair RequestedTypes, TypePair RuntimeTypes, MemberMap MemberMap) - { - public bool Equals(MapRequest other) => RequestedTypes.Equals(other.RequestedTypes) && RuntimeTypes.Equals(other.RuntimeTypes); - public override int GetHashCode() => HashCode.Combine(RequestedTypes, RuntimeTypes); - } - [DebuggerDisplay("{SourceType.Name}, {DestinationType.Name}")] - public readonly record struct TypePair(Type SourceType, Type DestinationType) + public bool Equals(MapRequest other) => RequestedTypes.Equals(other.RequestedTypes) && RuntimeTypes.Equals(other.RuntimeTypes); + public override int GetHashCode() => HashCode.Combine(RequestedTypes, RuntimeTypes); +} +[DebuggerDisplay("{SourceType.Name}, {DestinationType.Name}")] +public readonly record struct TypePair(Type SourceType, Type DestinationType) +{ + public bool IsConstructedGenericType => SourceType.IsConstructedGenericType || DestinationType.IsConstructedGenericType; + public bool ContainsGenericParameters => SourceType.ContainsGenericParameters || DestinationType.ContainsGenericParameters; + public TypePair CloseGenericTypes(TypePair closedTypes) { - public bool IsConstructedGenericType => SourceType.IsConstructedGenericType || DestinationType.IsConstructedGenericType; - public bool ContainsGenericParameters => SourceType.ContainsGenericParameters || DestinationType.ContainsGenericParameters; - public TypePair CloseGenericTypes(TypePair closedTypes) + var sourceArguments = closedTypes.SourceType.GenericTypeArguments; + var destinationArguments = closedTypes.DestinationType.GenericTypeArguments; + if(sourceArguments.Length == 0) + { + sourceArguments = destinationArguments; + } + else if(destinationArguments.Length == 0) { - var sourceArguments = closedTypes.SourceType.GenericTypeArguments; - var destinationArguments = closedTypes.DestinationType.GenericTypeArguments; - if(sourceArguments.Length == 0) - { - sourceArguments = destinationArguments; - } - else if(destinationArguments.Length == 0) - { - destinationArguments = sourceArguments; - } - var closedSourceType = SourceType.IsGenericTypeDefinition ? SourceType.MakeGenericType(sourceArguments) : SourceType; - var closedDestinationType = DestinationType.IsGenericTypeDefinition ? DestinationType.MakeGenericType(destinationArguments) : DestinationType; - return new TypePair(closedSourceType, closedDestinationType); + destinationArguments = sourceArguments; } - public Type ITypeConverter() => ContainsGenericParameters ? null : typeof(ITypeConverter<,>).MakeGenericType(SourceType, DestinationType); - public TypePair GetTypeDefinitionIfGeneric() => new(GetTypeDefinitionIfGeneric(SourceType), GetTypeDefinitionIfGeneric(DestinationType)); - private static Type GetTypeDefinitionIfGeneric(Type type) => type.IsGenericType ? type.GetGenericTypeDefinition() : type; + var closedSourceType = SourceType.IsGenericTypeDefinition ? SourceType.MakeGenericType(sourceArguments) : SourceType; + var closedDestinationType = DestinationType.IsGenericTypeDefinition ? DestinationType.MakeGenericType(destinationArguments) : DestinationType; + return new TypePair(closedSourceType, closedDestinationType); } + public Type ITypeConverter() => ContainsGenericParameters ? null : typeof(ITypeConverter<,>).MakeGenericType(SourceType, DestinationType); + public TypePair GetTypeDefinitionIfGeneric() => new(GetTypeDefinitionIfGeneric(SourceType), GetTypeDefinitionIfGeneric(DestinationType)); + private static Type GetTypeDefinitionIfGeneric(Type type) => type.IsGenericType ? type.GetGenericTypeDefinition() : type; } \ No newline at end of file diff --git a/src/AutoMapper/Mapper.cs b/src/AutoMapper/Mapper.cs index 88e79bde89..9c043c2f14 100644 --- a/src/AutoMapper/Mapper.cs +++ b/src/AutoMapper/Mapper.cs @@ -2,204 +2,203 @@ using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; -namespace AutoMapper +namespace AutoMapper; + +using QueryableExtensions; +using IObjectMappingOperationOptions = IMappingOperationOptions; +using Factory = Func; +using Internal; +public interface IMapperBase { - using QueryableExtensions; - using IObjectMappingOperationOptions = IMappingOperationOptions; - using Factory = Func; - using Internal; - public interface IMapperBase - { - /// - /// Execute a mapping from the source object to a new destination object. - /// The source type is inferred from the source object. - /// - /// Destination type to create - /// Source object to map from - /// Mapped destination object - TDestination Map(object source); - /// - /// Execute a mapping from the source object to a new destination object. - /// - /// Source type to use, regardless of the runtime type - /// Destination type to create - /// Source object to map from - /// Mapped destination object - TDestination Map(TSource source); - /// - /// Execute a mapping from the source object to the existing destination object. - /// - /// Source type to use - /// Destination type - /// Source object to map from - /// Destination object to map into - /// The mapped destination object, same instance as the object - TDestination Map(TSource source, TDestination destination); - /// - /// Execute a mapping from the source object to a new destination object with explicit objects - /// - /// Source object to map from - /// Source type to use - /// Destination type to create - /// Mapped destination object - object Map(object source, Type sourceType, Type destinationType); - /// - /// Execute a mapping from the source object to existing destination object with explicit objects - /// - /// Source object to map from - /// Destination object to map into - /// Source type to use - /// Destination type to use - /// Mapped destination object, same instance as the object - object Map(object source, object destination, Type sourceType, Type destinationType); - } - public interface IMapper : IMapperBase - { - /// - /// Execute a mapping from the source object to a new destination object with supplied mapping options. - /// - /// Destination type to create - /// Source object to map from - /// Mapping options - /// Mapped destination object - TDestination Map(object source, Action> opts); - /// - /// Execute a mapping from the source object to a new destination object with supplied mapping options. - /// - /// Source type to use - /// Destination type to create - /// Source object to map from - /// Mapping options - /// Mapped destination object - TDestination Map(TSource source, Action> opts); - /// - /// Execute a mapping from the source object to the existing destination object with supplied mapping options. - /// - /// Source type to use - /// Destination type - /// Source object to map from - /// Destination object to map into - /// Mapping options - /// The mapped destination object, same instance as the object - TDestination Map(TSource source, TDestination destination, Action> opts); - /// - /// Execute a mapping from the source object to a new destination object with explicit objects and supplied mapping options. - /// - /// Source object to map from - /// Source type to use - /// Destination type to create - /// Mapping options - /// Mapped destination object - object Map(object source, Type sourceType, Type destinationType, Action opts); - /// - /// Execute a mapping from the source object to existing destination object with supplied mapping options and explicit objects - /// - /// Source object to map from - /// Destination object to map into - /// Source type to use - /// Destination type to use - /// Mapping options - /// Mapped destination object, same instance as the object - object Map(object source, object destination, Type sourceType, Type destinationType, Action opts); - /// - /// Configuration provider for performing maps - /// - IConfigurationProvider ConfigurationProvider { get; } - /// - /// Project the input queryable. - /// - /// Projections are only calculated once and cached - /// Destination type - /// Queryable source - /// Optional parameter object for parameterized mapping expressions - /// Explicit members to expand - /// Queryable result, use queryable extension methods to project and execute result - IQueryable ProjectTo(IQueryable source, object parameters = null, params Expression>[] membersToExpand); - /// - /// Project the input queryable. - /// - /// Destination type to map to - /// Queryable source - /// Optional parameter object for parameterized mapping expressions - /// Explicit members to expand - /// Queryable result, use queryable extension methods to project and execute result - IQueryable ProjectTo(IQueryable source, IDictionary parameters, params string[] membersToExpand); - /// - /// Project the input queryable. - /// - /// Queryable source - /// Destination type to map to - /// Optional parameter object for parameterized mapping expressions - /// Explicit members to expand - /// Queryable result, use queryable extension methods to project and execute result - IQueryable ProjectTo(IQueryable source, Type destinationType, IDictionary parameters = null, params string[] membersToExpand); - } - public interface IRuntimeMapper : IMapperBase + /// + /// Execute a mapping from the source object to a new destination object. + /// The source type is inferred from the source object. + /// + /// Destination type to create + /// Source object to map from + /// Mapped destination object + TDestination Map(object source); + /// + /// Execute a mapping from the source object to a new destination object. + /// + /// Source type to use, regardless of the runtime type + /// Destination type to create + /// Source object to map from + /// Mapped destination object + TDestination Map(TSource source); + /// + /// Execute a mapping from the source object to the existing destination object. + /// + /// Source type to use + /// Destination type + /// Source object to map from + /// Destination object to map into + /// The mapped destination object, same instance as the object + TDestination Map(TSource source, TDestination destination); + /// + /// Execute a mapping from the source object to a new destination object with explicit objects + /// + /// Source object to map from + /// Source type to use + /// Destination type to create + /// Mapped destination object + object Map(object source, Type sourceType, Type destinationType); + /// + /// Execute a mapping from the source object to existing destination object with explicit objects + /// + /// Source object to map from + /// Destination object to map into + /// Source type to use + /// Destination type to use + /// Mapped destination object, same instance as the object + object Map(object source, object destination, Type sourceType, Type destinationType); +} +public interface IMapper : IMapperBase +{ + /// + /// Execute a mapping from the source object to a new destination object with supplied mapping options. + /// + /// Destination type to create + /// Source object to map from + /// Mapping options + /// Mapped destination object + TDestination Map(object source, Action> opts); + /// + /// Execute a mapping from the source object to a new destination object with supplied mapping options. + /// + /// Source type to use + /// Destination type to create + /// Source object to map from + /// Mapping options + /// Mapped destination object + TDestination Map(TSource source, Action> opts); + /// + /// Execute a mapping from the source object to the existing destination object with supplied mapping options. + /// + /// Source type to use + /// Destination type + /// Source object to map from + /// Destination object to map into + /// Mapping options + /// The mapped destination object, same instance as the object + TDestination Map(TSource source, TDestination destination, Action> opts); + /// + /// Execute a mapping from the source object to a new destination object with explicit objects and supplied mapping options. + /// + /// Source object to map from + /// Source type to use + /// Destination type to create + /// Mapping options + /// Mapped destination object + object Map(object source, Type sourceType, Type destinationType, Action opts); + /// + /// Execute a mapping from the source object to existing destination object with supplied mapping options and explicit objects + /// + /// Source object to map from + /// Destination object to map into + /// Source type to use + /// Destination type to use + /// Mapping options + /// Mapped destination object, same instance as the object + object Map(object source, object destination, Type sourceType, Type destinationType, Action opts); + /// + /// Configuration provider for performing maps + /// + IConfigurationProvider ConfigurationProvider { get; } + /// + /// Project the input queryable. + /// + /// Projections are only calculated once and cached + /// Destination type + /// Queryable source + /// Optional parameter object for parameterized mapping expressions + /// Explicit members to expand + /// Queryable result, use queryable extension methods to project and execute result + IQueryable ProjectTo(IQueryable source, object parameters = null, params Expression>[] membersToExpand); + /// + /// Project the input queryable. + /// + /// Destination type to map to + /// Queryable source + /// Optional parameter object for parameterized mapping expressions + /// Explicit members to expand + /// Queryable result, use queryable extension methods to project and execute result + IQueryable ProjectTo(IQueryable source, IDictionary parameters, params string[] membersToExpand); + /// + /// Project the input queryable. + /// + /// Queryable source + /// Destination type to map to + /// Optional parameter object for parameterized mapping expressions + /// Explicit members to expand + /// Queryable result, use queryable extension methods to project and execute result + IQueryable ProjectTo(IQueryable source, Type destinationType, IDictionary parameters = null, params string[] membersToExpand); +} +public interface IRuntimeMapper : IMapperBase +{ +} +internal interface IInternalRuntimeMapper : IRuntimeMapper +{ + TDestination Map(TSource source, TDestination destination, ResolutionContext context, Type sourceType = null, Type destinationType = null, MemberMap memberMap = null); + ResolutionContext DefaultContext { get; } + Factory ServiceCtor { get; } +} +public class Mapper : IMapper, IInternalRuntimeMapper +{ + private readonly IGlobalConfiguration _configuration; + private readonly Factory _serviceCtor; + public Mapper(IConfigurationProvider configuration) : this(configuration, configuration.Internal().ServiceCtor) { } + public Mapper(IConfigurationProvider configuration, Factory serviceCtor) { + _configuration = (IGlobalConfiguration)configuration ?? throw new ArgumentNullException(nameof(configuration)); + _serviceCtor = serviceCtor ?? throw new NullReferenceException(nameof(serviceCtor)); + DefaultContext = new(this); } - internal interface IInternalRuntimeMapper : IRuntimeMapper + internal ResolutionContext DefaultContext { get; } + ResolutionContext IInternalRuntimeMapper.DefaultContext => DefaultContext; + Factory IInternalRuntimeMapper.ServiceCtor => _serviceCtor; + public IConfigurationProvider ConfigurationProvider => _configuration; + public TDestination Map(object source) => Map(source, default(TDestination)); + public TDestination Map(object source, Action> opts) => Map(source, default, opts); + public TDestination Map(TSource source) => Map(source, default(TDestination)); + public TDestination Map(TSource source, Action> opts) => + Map(source, default, opts); + public TDestination Map(TSource source, TDestination destination) => + MapCore(source, destination, DefaultContext); + public TDestination Map(TSource source, TDestination destination, Action> opts) => + MapWithOptions(source, destination, opts); + public object Map(object source, Type sourceType, Type destinationType) => Map(source, null, sourceType, destinationType); + public object Map(object source, Type sourceType, Type destinationType, Action opts) => + Map(source, null, sourceType, destinationType, opts); + public object Map(object source, object destination, Type sourceType, Type destinationType) => + MapCore(source, destination, DefaultContext, sourceType, destinationType); + public object Map(object source, object destination, Type sourceType, Type destinationType, Action opts) => + MapWithOptions(source, destination, opts, sourceType, destinationType); + public IQueryable ProjectTo(IQueryable source, object parameters, params Expression>[] membersToExpand) + => source.ProjectTo(ConfigurationProvider, parameters, membersToExpand); + public IQueryable ProjectTo(IQueryable source, IDictionary parameters, params string[] membersToExpand) + => source.ProjectTo(ConfigurationProvider, parameters, membersToExpand); + public IQueryable ProjectTo(IQueryable source, Type destinationType, IDictionary parameters, params string[] membersToExpand) + => source.ProjectTo(destinationType, ConfigurationProvider, parameters, membersToExpand); + TDestination IInternalRuntimeMapper.Map(TSource source, TDestination destination, + ResolutionContext context, Type sourceType, Type destinationType, MemberMap memberMap) => + MapCore(source, destination, context, sourceType, destinationType, memberMap); + private TDestination MapWithOptions(TSource source, TDestination destination, Action> opts, + Type sourceType = null, Type destinationType = null) { - TDestination Map(TSource source, TDestination destination, ResolutionContext context, Type sourceType = null, Type destinationType = null, MemberMap memberMap = null); - ResolutionContext DefaultContext { get; } - Factory ServiceCtor { get; } + MappingOperationOptions typedOptions = new(_serviceCtor); + opts(typedOptions); + typedOptions.BeforeMapAction?.Invoke(source, destination); + destination = MapCore(source, destination, new(this, typedOptions), sourceType, destinationType); + typedOptions.AfterMapAction?.Invoke(source, destination); + return destination; } - public class Mapper : IMapper, IInternalRuntimeMapper + private TDestination MapCore( + TSource source, TDestination destination, ResolutionContext context, Type sourceType = null, Type destinationType = null, MemberMap memberMap = null) { - private readonly IGlobalConfiguration _configuration; - private readonly Factory _serviceCtor; - public Mapper(IConfigurationProvider configuration) : this(configuration, configuration.Internal().ServiceCtor) { } - public Mapper(IConfigurationProvider configuration, Factory serviceCtor) - { - _configuration = (IGlobalConfiguration)configuration ?? throw new ArgumentNullException(nameof(configuration)); - _serviceCtor = serviceCtor ?? throw new NullReferenceException(nameof(serviceCtor)); - DefaultContext = new(this); - } - internal ResolutionContext DefaultContext { get; } - ResolutionContext IInternalRuntimeMapper.DefaultContext => DefaultContext; - Factory IInternalRuntimeMapper.ServiceCtor => _serviceCtor; - public IConfigurationProvider ConfigurationProvider => _configuration; - public TDestination Map(object source) => Map(source, default(TDestination)); - public TDestination Map(object source, Action> opts) => Map(source, default, opts); - public TDestination Map(TSource source) => Map(source, default(TDestination)); - public TDestination Map(TSource source, Action> opts) => - Map(source, default, opts); - public TDestination Map(TSource source, TDestination destination) => - MapCore(source, destination, DefaultContext); - public TDestination Map(TSource source, TDestination destination, Action> opts) => - MapWithOptions(source, destination, opts); - public object Map(object source, Type sourceType, Type destinationType) => Map(source, null, sourceType, destinationType); - public object Map(object source, Type sourceType, Type destinationType, Action opts) => - Map(source, null, sourceType, destinationType, opts); - public object Map(object source, object destination, Type sourceType, Type destinationType) => - MapCore(source, destination, DefaultContext, sourceType, destinationType); - public object Map(object source, object destination, Type sourceType, Type destinationType, Action opts) => - MapWithOptions(source, destination, opts, sourceType, destinationType); - public IQueryable ProjectTo(IQueryable source, object parameters, params Expression>[] membersToExpand) - => source.ProjectTo(ConfigurationProvider, parameters, membersToExpand); - public IQueryable ProjectTo(IQueryable source, IDictionary parameters, params string[] membersToExpand) - => source.ProjectTo(ConfigurationProvider, parameters, membersToExpand); - public IQueryable ProjectTo(IQueryable source, Type destinationType, IDictionary parameters, params string[] membersToExpand) - => source.ProjectTo(destinationType, ConfigurationProvider, parameters, membersToExpand); - TDestination IInternalRuntimeMapper.Map(TSource source, TDestination destination, - ResolutionContext context, Type sourceType, Type destinationType, MemberMap memberMap) => - MapCore(source, destination, context, sourceType, destinationType, memberMap); - private TDestination MapWithOptions(TSource source, TDestination destination, Action> opts, - Type sourceType = null, Type destinationType = null) - { - MappingOperationOptions typedOptions = new(_serviceCtor); - opts(typedOptions); - typedOptions.BeforeMapAction?.Invoke(source, destination); - destination = MapCore(source, destination, new(this, typedOptions), sourceType, destinationType); - typedOptions.AfterMapAction?.Invoke(source, destination); - return destination; - } - private TDestination MapCore( - TSource source, TDestination destination, ResolutionContext context, Type sourceType = null, Type destinationType = null, MemberMap memberMap = null) - { - TypePair requestedTypes = new(typeof(TSource), typeof(TDestination)); - TypePair runtimeTypes = new(source?.GetType() ?? sourceType ?? typeof(TSource), destination?.GetType() ?? destinationType ?? typeof(TDestination)); - MapRequest mapRequest = new(requestedTypes, runtimeTypes, memberMap); - return _configuration.GetExecutionPlan(mapRequest)(source, destination, context); - } + TypePair requestedTypes = new(typeof(TSource), typeof(TDestination)); + TypePair runtimeTypes = new(source?.GetType() ?? sourceType ?? typeof(TSource), destination?.GetType() ?? destinationType ?? typeof(TDestination)); + MapRequest mapRequest = new(requestedTypes, runtimeTypes, memberMap); + return _configuration.GetExecutionPlan(mapRequest)(source, destination, context); } } \ No newline at end of file diff --git a/src/AutoMapper/Mappers/AssignableMapper.cs b/src/AutoMapper/Mappers/AssignableMapper.cs index a5d0b5ffa6..d47d58b1ba 100644 --- a/src/AutoMapper/Mappers/AssignableMapper.cs +++ b/src/AutoMapper/Mappers/AssignableMapper.cs @@ -1,10 +1,9 @@ using System.Linq.Expressions; -namespace AutoMapper.Internal.Mappers +namespace AutoMapper.Internal.Mappers; + +public class AssignableMapper : IObjectMapper { - public class AssignableMapper : IObjectMapper - { - public bool IsMatch(TypePair context) => context.DestinationType.IsAssignableFrom(context.SourceType); - public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, - MemberMap memberMap, Expression sourceExpression, Expression destExpression) => sourceExpression; - } + public bool IsMatch(TypePair context) => context.DestinationType.IsAssignableFrom(context.SourceType); + public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, + MemberMap memberMap, Expression sourceExpression, Expression destExpression) => sourceExpression; } \ No newline at end of file diff --git a/src/AutoMapper/Mappers/CollectionMapper.cs b/src/AutoMapper/Mappers/CollectionMapper.cs index 58f2326d46..029c56f089 100644 --- a/src/AutoMapper/Mappers/CollectionMapper.cs +++ b/src/AutoMapper/Mappers/CollectionMapper.cs @@ -6,281 +6,280 @@ using System.Reflection; using System.Collections.Specialized; using System.Linq; -namespace AutoMapper.Internal.Mappers +namespace AutoMapper.Internal.Mappers; + +using Execution; +using static Execution.ExpressionBuilder; +using static Expression; +using static ReflectionHelper; +public class CollectionMapper : IObjectMapper { - using Execution; - using static Execution.ExpressionBuilder; - using static Expression; - using static ReflectionHelper; - public class CollectionMapper : IObjectMapper + public TypePair? GetAssociatedTypes(TypePair context) => new(GetElementType(context.SourceType), GetElementType(context.DestinationType)); + public bool IsMatch(TypePair context) => context.IsCollection(); + public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) { - public TypePair? GetAssociatedTypes(TypePair context) => new(GetElementType(context.SourceType), GetElementType(context.DestinationType)); - public bool IsMatch(TypePair context) => context.IsCollection(); - public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) + var destinationType = destExpression.Type; + if (destinationType.IsArray) + { + return ArrayMapper.MapToArray(configuration, profileMap, sourceExpression, destinationType); + } + if (destinationType.IsGenericType(typeof(ReadOnlyCollection<>))) + { + return MapReadOnlyCollection(typeof(List<>), typeof(ReadOnlyCollection<>)); + } + if (destinationType.IsGenericType(typeof(ReadOnlyDictionary<,>)) || destinationType.IsGenericType(typeof(IReadOnlyDictionary<,>))) + { + return MapReadOnlyCollection(typeof(Dictionary<,>), typeof(ReadOnlyDictionary<,>)); + } + if (destinationType == sourceExpression.Type && destinationType.Name == nameof(NameValueCollection)) + { + return CreateNameValueCollection(sourceExpression); + } + return MapCollectionCore(destExpression); + Expression MapReadOnlyCollection(Type genericCollectionType, Type genericReadOnlyCollectionType) + { + var destinationTypeArguments = destinationType.GenericTypeArguments; + var closedCollectionType = genericCollectionType.MakeGenericType(destinationTypeArguments); + var dict = MapCollectionCore(configuration.Default(closedCollectionType)); + var readOnlyClosedType = destinationType.IsInterface ? genericReadOnlyCollectionType.MakeGenericType(destinationTypeArguments) : destinationType; + return New(readOnlyClosedType.GetConstructors()[0], dict); + } + Expression MapCollectionCore(Expression destExpression) { var destinationType = destExpression.Type; - if (destinationType.IsArray) - { - return ArrayMapper.MapToArray(configuration, profileMap, sourceExpression, destinationType); - } - if (destinationType.IsGenericType(typeof(ReadOnlyCollection<>))) + var sourceType = sourceExpression.Type; + MethodInfo addMethod = null; + bool isIList = false, mustUseDestination = memberMap is { MustUseDestination: true }; + Type destinationCollectionType = null, destinationElementType = null; + GetDestinationType(); + var passedDestination = Variable(destExpression.Type, "passedDestination"); + var newExpression = Variable(passedDestination.Type, "collectionDestination"); + var sourceElementType = GetEnumerableElementType(sourceType); + if (destinationCollectionType == null || (sourceType == sourceElementType && destinationType == destinationElementType)) { - return MapReadOnlyCollection(typeof(List<>), typeof(ReadOnlyCollection<>)); - } - if (destinationType.IsGenericType(typeof(ReadOnlyDictionary<,>)) || destinationType.IsGenericType(typeof(IReadOnlyDictionary<,>))) - { - return MapReadOnlyCollection(typeof(Dictionary<,>), typeof(ReadOnlyDictionary<,>)); + if (destinationType.IsAssignableFrom(sourceType)) + { + return sourceExpression; + } + throw new NotSupportedException($"Unknown collection. Consider a custom type converter from {sourceType} to {destinationType}."); } - if (destinationType == sourceExpression.Type && destinationType.Name == nameof(NameValueCollection)) + var itemParam = Parameter(sourceElementType, "item"); + var itemExpr = configuration.MapExpression(profileMap, new TypePair(sourceElementType, destinationElementType), itemParam); + Expression destination, assignNewExpression; + UseDestinationValue(); + var (variables, statements) = configuration.Scratchpad(); + statements.Add(itemExpr); + var addCall = Call(destination, addMethod, statements); + statements.Clear(); + var addItems = ForEach(variables, statements, itemParam, sourceExpression, addCall); + var overMaxDepth = OverMaxDepth(memberMap?.TypeMap); + if (overMaxDepth != null) { - return CreateNameValueCollection(sourceExpression); + addItems = IfThenElse(overMaxDepth, ExpressionBuilder.Empty, addItems); } - return MapCollectionCore(destExpression); - Expression MapReadOnlyCollection(Type genericCollectionType, Type genericReadOnlyCollectionType) + var clearMethod = isIList ? IListClear : destinationCollectionType.GetMethod("Clear"); + statements.Clear(); + variables.Clear(); + variables.Add(newExpression); + variables.Add(passedDestination); + var checkContext = CheckContext(); + if (checkContext != null) { - var destinationTypeArguments = destinationType.GenericTypeArguments; - var closedCollectionType = genericCollectionType.MakeGenericType(destinationTypeArguments); - var dict = MapCollectionCore(configuration.Default(closedCollectionType)); - var readOnlyClosedType = destinationType.IsInterface ? genericReadOnlyCollectionType.MakeGenericType(destinationTypeArguments) : destinationType; - return New(readOnlyClosedType.GetConstructors()[0], dict); + statements.Add(checkContext); } - Expression MapCollectionCore(Expression destExpression) + statements.Add(Assign(passedDestination, destExpression)); + statements.Add(assignNewExpression); + statements.Add(Call(destination, clearMethod)); + statements.Add(addItems); + statements.Add(destination); + return Block(variables, statements); + void GetDestinationType() { - var destinationType = destExpression.Type; - var sourceType = sourceExpression.Type; - MethodInfo addMethod = null; - bool isIList = false, mustUseDestination = memberMap is { MustUseDestination: true }; - Type destinationCollectionType = null, destinationElementType = null; - GetDestinationType(); - var passedDestination = Variable(destExpression.Type, "passedDestination"); - var newExpression = Variable(passedDestination.Type, "collectionDestination"); - var sourceElementType = GetEnumerableElementType(sourceType); - if (destinationCollectionType == null || (sourceType == sourceElementType && destinationType == destinationElementType)) + var immutableCollection = !mustUseDestination && destinationType.IsValueType; + if (immutableCollection) { - if (destinationType.IsAssignableFrom(sourceType)) - { - return sourceExpression; - } - throw new NotSupportedException($"Unknown collection. Consider a custom type converter from {sourceType} to {destinationType}."); + return; } - var itemParam = Parameter(sourceElementType, "item"); - var itemExpr = configuration.MapExpression(profileMap, new TypePair(sourceElementType, destinationElementType), itemParam); - Expression destination, assignNewExpression; - UseDestinationValue(); - var (variables, statements) = configuration.Scratchpad(); - statements.Add(itemExpr); - var addCall = Call(destination, addMethod, statements); - statements.Clear(); - var addItems = ForEach(variables, statements, itemParam, sourceExpression, addCall); - var overMaxDepth = OverMaxDepth(memberMap?.TypeMap); - if (overMaxDepth != null) - { - addItems = IfThenElse(overMaxDepth, ExpressionBuilder.Empty, addItems); - } - var clearMethod = isIList ? IListClear : destinationCollectionType.GetMethod("Clear"); - statements.Clear(); - variables.Clear(); - variables.Add(newExpression); - variables.Add(passedDestination); - var checkContext = CheckContext(); - if (checkContext != null) + destinationCollectionType = destinationType.GetICollectionType(); + isIList = destExpression.Type.IsListType(); + if (destinationCollectionType == null) { - statements.Add(checkContext); - } - statements.Add(Assign(passedDestination, destExpression)); - statements.Add(assignNewExpression); - statements.Add(Call(destination, clearMethod)); - statements.Add(addItems); - statements.Add(destination); - return Block(variables, statements); - void GetDestinationType() - { - var immutableCollection = !mustUseDestination && destinationType.IsValueType; - if (immutableCollection) + if (isIList) { - return; + destinationCollectionType = typeof(IList); + addMethod = IListAdd; + destinationElementType = GetEnumerableElementType(destinationType); } - destinationCollectionType = destinationType.GetICollectionType(); - isIList = destExpression.Type.IsListType(); - if (destinationCollectionType == null) + else { - if (isIList) + if (!destinationType.IsInterface) { - destinationCollectionType = typeof(IList); - addMethod = IListAdd; - destinationElementType = GetEnumerableElementType(destinationType); + return; } - else - { - if (!destinationType.IsInterface) - { - return; - } - destinationElementType = GetEnumerableElementType(destinationType); - destinationCollectionType = typeof(ICollection<>).MakeGenericType(destinationElementType); - destExpression = Convert(mustUseDestination ? destExpression : Null, destinationCollectionType); - addMethod = destinationCollectionType.GetMethod("Add"); - } - } - else - { - destinationElementType = destinationCollectionType.GenericTypeArguments[0]; + destinationElementType = GetEnumerableElementType(destinationType); + destinationCollectionType = typeof(ICollection<>).MakeGenericType(destinationElementType); + destExpression = Convert(mustUseDestination ? destExpression : Null, destinationCollectionType); addMethod = destinationCollectionType.GetMethod("Add"); } } - void UseDestinationValue() + else + { + destinationElementType = destinationCollectionType.GenericTypeArguments[0]; + addMethod = destinationCollectionType.GetMethod("Add"); + } + } + void UseDestinationValue() + { + if (mustUseDestination) { - if (mustUseDestination) - { - destination = passedDestination; - assignNewExpression = ExpressionBuilder.Empty; - } - else - { - destination = newExpression; - var ctor = ObjectFactory.GenerateConstructorExpression(passedDestination.Type, configuration); - assignNewExpression = Assign(newExpression, Coalesce(passedDestination, ctor)); - } + destination = passedDestination; + assignNewExpression = ExpressionBuilder.Empty; } - Expression CheckContext() + else { - var elementTypeMap = configuration.ResolveTypeMap(sourceElementType, destinationElementType); - return elementTypeMap == null ? null : ExpressionBuilder.CheckContext(elementTypeMap); + destination = newExpression; + var ctor = ObjectFactory.GenerateConstructorExpression(passedDestination.Type, configuration); + assignNewExpression = Assign(newExpression, Coalesce(passedDestination, ctor)); } } + Expression CheckContext() + { + var elementTypeMap = configuration.ResolveTypeMap(sourceElementType, destinationElementType); + return elementTypeMap == null ? null : ExpressionBuilder.CheckContext(elementTypeMap); + } + } + } + private static Expression CreateNameValueCollection(Expression sourceExpression) => + New(typeof(NameValueCollection).GetConstructor(new[] { typeof(NameValueCollection) }), sourceExpression); + static class ArrayMapper + { + private static readonly MethodInfo ToArrayMethod = typeof(Enumerable).GetStaticMethod("ToArray"); + private static readonly MethodInfo CopyToMethod = typeof(Array).GetMethod("CopyTo", new[] { typeof(Array), typeof(int) }); + private static readonly MethodInfo CountMethod = typeof(Enumerable).StaticGenericMethod("Count", parametersCount: 1); + private static readonly MethodInfo MapMultidimensionalMethod = typeof(ArrayMapper).GetStaticMethod(nameof(MapMultidimensional)); + private static readonly ParameterExpression Index = Variable(typeof(int), "destinationArrayIndex"); + private static readonly BinaryExpression ResetIndex = Assign(Index, Zero); + private static readonly ReadOnlyCollection IncrementIndex = PostIncrementAssign(Index).ToReadOnly(); + private static Array MapMultidimensional(Array source, Type destinationElementType, ResolutionContext context) + { + var sourceElementType = source.GetType().GetElementType(); + var destinationArray = Array.CreateInstance(destinationElementType, Enumerable.Range(0, source.Rank).Select(source.GetLength).ToArray()); + var filler = new MultidimensionalArrayFiller(destinationArray); + foreach (var item in source) + { + filler.NewValue(context.Map(item, null, sourceElementType, destinationElementType, null)); + } + return destinationArray; } - private static Expression CreateNameValueCollection(Expression sourceExpression) => - New(typeof(NameValueCollection).GetConstructor(new[] { typeof(NameValueCollection) }), sourceExpression); - static class ArrayMapper + public static Expression MapToArray(IGlobalConfiguration configuration, ProfileMap profileMap, Expression sourceExpression, Type destinationType) { - private static readonly MethodInfo ToArrayMethod = typeof(Enumerable).GetStaticMethod("ToArray"); - private static readonly MethodInfo CopyToMethod = typeof(Array).GetMethod("CopyTo", new[] { typeof(Array), typeof(int) }); - private static readonly MethodInfo CountMethod = typeof(Enumerable).StaticGenericMethod("Count", parametersCount: 1); - private static readonly MethodInfo MapMultidimensionalMethod = typeof(ArrayMapper).GetStaticMethod(nameof(MapMultidimensional)); - private static readonly ParameterExpression Index = Variable(typeof(int), "destinationArrayIndex"); - private static readonly BinaryExpression ResetIndex = Assign(Index, Zero); - private static readonly ReadOnlyCollection IncrementIndex = PostIncrementAssign(Index).ToReadOnly(); - private static Array MapMultidimensional(Array source, Type destinationElementType, ResolutionContext context) + var destinationElementType = destinationType.GetElementType(); + if (destinationType.GetArrayRank() > 1) + { + return Call(MapMultidimensionalMethod, sourceExpression, Constant(destinationElementType), ContextParameter); + } + var sourceType = sourceExpression.Type; + Type sourceElementType = typeof(object); + Expression createDestination; + var destination = Parameter(destinationType, "destinationArray"); + var (variables, statements) = configuration.Scratchpad(); + if (sourceType.IsArray) { - var sourceElementType = source.GetType().GetElementType(); - var destinationArray = Array.CreateInstance(destinationElementType, Enumerable.Range(0, source.Rank).Select(source.GetLength).ToArray()); - var filler = new MultidimensionalArrayFiller(destinationArray); - foreach (var item in source) + var mapFromArray = MapFromArray(); + if (mapFromArray != null) { - filler.NewValue(context.Map(item, null, sourceElementType, destinationElementType, null)); + return mapFromArray; } - return destinationArray; } - public static Expression MapToArray(IGlobalConfiguration configuration, ProfileMap profileMap, Expression sourceExpression, Type destinationType) + else { - var destinationElementType = destinationType.GetElementType(); - if (destinationType.GetArrayRank() > 1) + var mapFromIEnumerable = MapFromIEnumerable(); + if (mapFromIEnumerable != null) { - return Call(MapMultidimensionalMethod, sourceExpression, Constant(destinationElementType), ContextParameter); + return mapFromIEnumerable; } - var sourceType = sourceExpression.Type; - Type sourceElementType = typeof(object); - Expression createDestination; - var destination = Parameter(destinationType, "destinationArray"); - var (variables, statements) = configuration.Scratchpad(); - if (sourceType.IsArray) - { - var mapFromArray = MapFromArray(); - if (mapFromArray != null) - { - return mapFromArray; - } - } - else + var count = Call(CountMethod.MakeGenericMethod(sourceElementType), sourceExpression); + statements.Add(count); + createDestination = Assign(destination, NewArrayBounds(destinationElementType, statements)); + } + var itemParam = Parameter(sourceElementType, "sourceItem"); + var itemExpr = configuration.MapExpression(profileMap, new TypePair(sourceElementType, destinationElementType), itemParam); + var setItem = Assign(ArrayAccess(destination, IncrementIndex), itemExpr); + variables.Clear(); + statements.Clear(); + var forEach = ForEach(variables, statements, itemParam, sourceExpression, setItem); + variables.Clear(); + statements.Clear(); + variables.Add(destination); + variables.Add(Index); + statements.Add(createDestination); + statements.Add(ResetIndex); + statements.Add(forEach); + statements.Add(destination); + return Block(variables, statements); + Expression MapFromArray() + { + sourceElementType = sourceType.GetElementType(); + statements.Add(ArrayLength(sourceExpression)); + createDestination = Assign(destination, NewArrayBounds(destinationElementType, statements)); + if (MustMap(sourceElementType, destinationElementType)) { - var mapFromIEnumerable = MapFromIEnumerable(); - if (mapFromIEnumerable != null) - { - return mapFromIEnumerable; - } - var count = Call(CountMethod.MakeGenericMethod(sourceElementType), sourceExpression); - statements.Add(count); - createDestination = Assign(destination, NewArrayBounds(destinationElementType, statements)); + return null; } - var itemParam = Parameter(sourceElementType, "sourceItem"); - var itemExpr = configuration.MapExpression(profileMap, new TypePair(sourceElementType, destinationElementType), itemParam); - var setItem = Assign(ArrayAccess(destination, IncrementIndex), itemExpr); - variables.Clear(); - statements.Clear(); - var forEach = ForEach(variables, statements, itemParam, sourceExpression, setItem); variables.Clear(); statements.Clear(); variables.Add(destination); - variables.Add(Index); statements.Add(createDestination); - statements.Add(ResetIndex); - statements.Add(forEach); + statements.Add(Call(sourceExpression, CopyToMethod, destination, Zero)); statements.Add(destination); return Block(variables, statements); - Expression MapFromArray() - { - sourceElementType = sourceType.GetElementType(); - statements.Add(ArrayLength(sourceExpression)); - createDestination = Assign(destination, NewArrayBounds(destinationElementType, statements)); - if (MustMap(sourceElementType, destinationElementType)) - { - return null; - } - variables.Clear(); - statements.Clear(); - variables.Add(destination); - statements.Add(createDestination); - statements.Add(Call(sourceExpression, CopyToMethod, destination, Zero)); - statements.Add(destination); - return Block(variables, statements); - } - Expression MapFromIEnumerable() + } + Expression MapFromIEnumerable() + { + var iEnumerableType = sourceType.GetIEnumerableType(); + if (iEnumerableType == null || MustMap(sourceElementType = iEnumerableType.GenericTypeArguments[0], destinationElementType)) { - var iEnumerableType = sourceType.GetIEnumerableType(); - if (iEnumerableType == null || MustMap(sourceElementType = iEnumerableType.GenericTypeArguments[0], destinationElementType)) - { - return null; - } - return Call(ToArrayMethod.MakeGenericMethod(sourceElementType), sourceExpression); + return null; } - bool MustMap(Type sourceType, Type destinationType) => !destinationType.IsAssignableFrom(sourceType) || - configuration.FindTypeMapFor(sourceType, destinationType) != null; + return Call(ToArrayMethod.MakeGenericMethod(sourceElementType), sourceExpression); } + bool MustMap(Type sourceType, Type destinationType) => !destinationType.IsAssignableFrom(sourceType) || + configuration.FindTypeMapFor(sourceType, destinationType) != null; } } - public class MultidimensionalArrayFiller +} +public class MultidimensionalArrayFiller +{ + private readonly int[] _indices; + private readonly Array _destination; + public MultidimensionalArrayFiller(Array destination) { - private readonly int[] _indices; - private readonly Array _destination; - public MultidimensionalArrayFiller(Array destination) - { - _indices = new int[destination.Rank]; - _destination = destination; - } - public void NewValue(object value) + _indices = new int[destination.Rank]; + _destination = destination; + } + public void NewValue(object value) + { + var dimension = _destination.Rank - 1; + var changedDimension = false; + while (_indices[dimension] == _destination.GetLength(dimension)) { - var dimension = _destination.Rank - 1; - var changedDimension = false; - while (_indices[dimension] == _destination.GetLength(dimension)) + _indices[dimension] = 0; + dimension--; + if (dimension < 0) { - _indices[dimension] = 0; - dimension--; - if (dimension < 0) - { - throw new InvalidOperationException("Not enough room in destination array " + _destination); - } - _indices[dimension]++; - changedDimension = true; - } - _destination.SetValue(value, _indices); - if (changedDimension) - { - _indices[dimension + 1]++; - } - else - { - _indices[dimension]++; + throw new InvalidOperationException("Not enough room in destination array " + _destination); } + _indices[dimension]++; + changedDimension = true; + } + _destination.SetValue(value, _indices); + if (changedDimension) + { + _indices[dimension + 1]++; + } + else + { + _indices[dimension]++; } } } \ No newline at end of file diff --git a/src/AutoMapper/Mappers/ConstructorMapper.cs b/src/AutoMapper/Mappers/ConstructorMapper.cs index d4d6177f64..e913226132 100644 --- a/src/AutoMapper/Mappers/ConstructorMapper.cs +++ b/src/AutoMapper/Mappers/ConstructorMapper.cs @@ -1,18 +1,17 @@ using System; using System.Linq.Expressions; using System.Reflection; -namespace AutoMapper.Internal.Mappers +namespace AutoMapper.Internal.Mappers; + +using static Execution.ExpressionBuilder; +public class ConstructorMapper : IObjectMapper { - using static Execution.ExpressionBuilder; - public class ConstructorMapper : IObjectMapper + public bool IsMatch(TypePair context) => GetConstructor(context.SourceType, context.DestinationType) != null; + private static ConstructorInfo GetConstructor(Type sourceType, Type destinationType) => + destinationType.GetConstructor(TypeExtensions.InstanceFlags, null, new[] { sourceType }, null); + public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) { - public bool IsMatch(TypePair context) => GetConstructor(context.SourceType, context.DestinationType) != null; - private static ConstructorInfo GetConstructor(Type sourceType, Type destinationType) => - destinationType.GetConstructor(TypeExtensions.InstanceFlags, null, new[] { sourceType }, null); - public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) - { - var constructor = GetConstructor(sourceExpression.Type, destExpression.Type); - return Expression.New(constructor, ToType(sourceExpression, constructor.FirstParameterType())); - } + var constructor = GetConstructor(sourceExpression.Type, destExpression.Type); + return Expression.New(constructor, ToType(sourceExpression, constructor.FirstParameterType())); } } \ No newline at end of file diff --git a/src/AutoMapper/Mappers/ConversionOperatorMapper.cs b/src/AutoMapper/Mappers/ConversionOperatorMapper.cs index 6af476b5d5..87ca3036cc 100644 --- a/src/AutoMapper/Mappers/ConversionOperatorMapper.cs +++ b/src/AutoMapper/Mappers/ConversionOperatorMapper.cs @@ -1,29 +1,28 @@ using System; using System.Linq.Expressions; using System.Reflection; -namespace AutoMapper.Internal.Mappers +namespace AutoMapper.Internal.Mappers; + +using static Execution.ExpressionBuilder; +public class ConversionOperatorMapper : IObjectMapper { - using static Execution.ExpressionBuilder; - public class ConversionOperatorMapper : IObjectMapper + private readonly string _operatorName; + public ConversionOperatorMapper(string operatorName) => _operatorName = operatorName; + public bool IsMatch(TypePair context) => GetConversionOperator(context.SourceType, context.DestinationType) != null; + private MethodInfo GetConversionOperator(Type sourceType, Type destinationType) { - private readonly string _operatorName; - public ConversionOperatorMapper(string operatorName) => _operatorName = operatorName; - public bool IsMatch(TypePair context) => GetConversionOperator(context.SourceType, context.DestinationType) != null; - private MethodInfo GetConversionOperator(Type sourceType, Type destinationType) + foreach (MethodInfo sourceMethod in sourceType.GetMember(_operatorName, MemberTypes.Method, BindingFlags.Static | BindingFlags.Public | BindingFlags.FlattenHierarchy)) { - foreach (MethodInfo sourceMethod in sourceType.GetMember(_operatorName, MemberTypes.Method, BindingFlags.Static | BindingFlags.Public | BindingFlags.FlattenHierarchy)) + if (destinationType.IsAssignableFrom(sourceMethod.ReturnType)) { - if (destinationType.IsAssignableFrom(sourceMethod.ReturnType)) - { - return sourceMethod; - } + return sourceMethod; } - return destinationType.GetMethod(_operatorName, TypeExtensions.StaticFlags, null, new[] { sourceType }, null); - } - public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) - { - var conversionOperator = GetConversionOperator(sourceExpression.Type, destExpression.Type); - return Expression.Call(conversionOperator, ToType(sourceExpression, conversionOperator.FirstParameterType())); } + return destinationType.GetMethod(_operatorName, TypeExtensions.StaticFlags, null, new[] { sourceType }, null); + } + public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) + { + var conversionOperator = GetConversionOperator(sourceExpression.Type, destExpression.Type); + return Expression.Call(conversionOperator, ToType(sourceExpression, conversionOperator.FirstParameterType())); } } diff --git a/src/AutoMapper/Mappers/ConvertMapper.cs b/src/AutoMapper/Mappers/ConvertMapper.cs index 0ff272e886..ccbf1e9379 100644 --- a/src/AutoMapper/Mappers/ConvertMapper.cs +++ b/src/AutoMapper/Mappers/ConvertMapper.cs @@ -1,18 +1,17 @@ using System; using System.Linq.Expressions; -namespace AutoMapper.Internal.Mappers +namespace AutoMapper.Internal.Mappers; + +using static Expression; +public class ConvertMapper : IObjectMapper { - using static Expression; - public class ConvertMapper : IObjectMapper + public static bool IsPrimitive(Type type) => type.IsPrimitive || type == typeof(string) || type == typeof(decimal); + public bool IsMatch(TypePair types) => (types.SourceType == typeof(string) && types.DestinationType == typeof(DateTime)) || + (IsPrimitive(types.SourceType) && IsPrimitive(types.DestinationType)); + public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, + MemberMap memberMap, Expression sourceExpression, Expression destExpression) { - public static bool IsPrimitive(Type type) => type.IsPrimitive || type == typeof(string) || type == typeof(decimal); - public bool IsMatch(TypePair types) => (types.SourceType == typeof(string) && types.DestinationType == typeof(DateTime)) || - (IsPrimitive(types.SourceType) && IsPrimitive(types.DestinationType)); - public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, - MemberMap memberMap, Expression sourceExpression, Expression destExpression) - { - var convertMethod = typeof(Convert).GetMethod("To" + destExpression.Type.Name, new[] { sourceExpression.Type }); - return Call(convertMethod, sourceExpression); - } + var convertMethod = typeof(Convert).GetMethod("To" + destExpression.Type.Name, new[] { sourceExpression.Type }); + return Call(convertMethod, sourceExpression); } } \ No newline at end of file diff --git a/src/AutoMapper/Mappers/EnumToEnumMapper.cs b/src/AutoMapper/Mappers/EnumToEnumMapper.cs index 5e76b6ec37..a23acae838 100644 --- a/src/AutoMapper/Mappers/EnumToEnumMapper.cs +++ b/src/AutoMapper/Mappers/EnumToEnumMapper.cs @@ -1,26 +1,25 @@ using System; using System.Linq.Expressions; using System.Reflection; -namespace AutoMapper.Internal.Mappers +namespace AutoMapper.Internal.Mappers; + +using static Expression; +using static Execution.ExpressionBuilder; +public class EnumToEnumMapper : IObjectMapper { - using static Expression; - using static Execution.ExpressionBuilder; - public class EnumToEnumMapper : IObjectMapper + private static readonly MethodInfo TryParseMethod = typeof(Enum).StaticGenericMethod("TryParse", parametersCount: 3); + public bool IsMatch(TypePair context) => context.IsEnumToEnum(); + public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, + MemberMap memberMap, Expression sourceExpression, Expression destExpression) { - private static readonly MethodInfo TryParseMethod = typeof(Enum).StaticGenericMethod("TryParse", parametersCount: 3); - public bool IsMatch(TypePair context) => context.IsEnumToEnum(); - public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, - MemberMap memberMap, Expression sourceExpression, Expression destExpression) - { - var destinationType = destExpression.Type; - var sourceToString = Call(sourceExpression, ObjectToString); - var result = Variable(destinationType, "destinationEnumValue"); - var ignoreCase = True; - var tryParse = Call(TryParseMethod.MakeGenericMethod(destinationType), sourceToString, ignoreCase, result); - var (variables, statements) = configuration.Scratchpad(); - variables.Add(result); - statements.Add(Condition(tryParse, result, Convert(sourceExpression, destinationType))); - return Block(variables, statements); - } + var destinationType = destExpression.Type; + var sourceToString = Call(sourceExpression, ObjectToString); + var result = Variable(destinationType, "destinationEnumValue"); + var ignoreCase = True; + var tryParse = Call(TryParseMethod.MakeGenericMethod(destinationType), sourceToString, ignoreCase, result); + var (variables, statements) = configuration.Scratchpad(); + variables.Add(result); + statements.Add(Condition(tryParse, result, Convert(sourceExpression, destinationType))); + return Block(variables, statements); } } \ No newline at end of file diff --git a/src/AutoMapper/Mappers/FromDynamicMapper.cs b/src/AutoMapper/Mappers/FromDynamicMapper.cs index 5314d90c6a..706a167060 100644 --- a/src/AutoMapper/Mappers/FromDynamicMapper.cs +++ b/src/AutoMapper/Mappers/FromDynamicMapper.cs @@ -5,43 +5,42 @@ using AutoMapper.Execution; using Microsoft.CSharp.RuntimeBinder; using Binder = Microsoft.CSharp.RuntimeBinder.Binder; -namespace AutoMapper.Internal.Mappers +namespace AutoMapper.Internal.Mappers; + +using static Expression; +using static ExpressionBuilder; +public class FromDynamicMapper : IObjectMapper { - using static Expression; - using static ExpressionBuilder; - public class FromDynamicMapper : IObjectMapper + private static readonly MethodInfo MapMethodInfo = typeof(FromDynamicMapper).GetStaticMethod(nameof(Map)); + private static object Map(object source, object destination, Type destinationType, ResolutionContext context, ProfileMap profileMap) { - private static readonly MethodInfo MapMethodInfo = typeof(FromDynamicMapper).GetStaticMethod(nameof(Map)); - private static object Map(object source, object destination, Type destinationType, ResolutionContext context, ProfileMap profileMap) + destination ??= ObjectFactory.CreateInstance(destinationType); + var destinationTypeDetails = profileMap.CreateTypeDetails(destinationType); + foreach (var member in destinationTypeDetails.WriteAccessors) { - destination ??= ObjectFactory.CreateInstance(destinationType); - var destinationTypeDetails = profileMap.CreateTypeDetails(destinationType); - foreach (var member in destinationTypeDetails.WriteAccessors) + object sourceMemberValue; + try { - object sourceMemberValue; - try - { - sourceMemberValue = GetDynamically(member.Name, source); - } - catch (RuntimeBinderException) - { - continue; - } - var destinationMemberValue = context.MapMember(member, sourceMemberValue, destination); - member.SetMemberValue(destination, destinationMemberValue); + sourceMemberValue = GetDynamically(member.Name, source); } - return destination; - } - private static object GetDynamically(string memberName, object target) - { - var binder = Binder.GetMember(CSharpBinderFlags.None, memberName, null, - new[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) }); - var callsite = CallSite>.Create(binder); - return callsite.Target(callsite, target); + catch (RuntimeBinderException) + { + continue; + } + var destinationMemberValue = context.MapMember(member, sourceMemberValue, destination); + member.SetMemberValue(destination, destinationMemberValue); } - public bool IsMatch(TypePair context) => context.SourceType.IsDynamic() && !context.DestinationType.IsDynamic(); - public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, - MemberMap memberMap, Expression sourceExpression, Expression destExpression) => - Call(MapMethodInfo, sourceExpression, destExpression.ToObject(), Constant(destExpression.Type), ContextParameter, Constant(profileMap)); + return destination; + } + private static object GetDynamically(string memberName, object target) + { + var binder = Binder.GetMember(CSharpBinderFlags.None, memberName, null, + new[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) }); + var callsite = CallSite>.Create(binder); + return callsite.Target(callsite, target); } + public bool IsMatch(TypePair context) => context.SourceType.IsDynamic() && !context.DestinationType.IsDynamic(); + public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, + MemberMap memberMap, Expression sourceExpression, Expression destExpression) => + Call(MapMethodInfo, sourceExpression, destExpression.ToObject(), Constant(destExpression.Type), ContextParameter, Constant(profileMap)); } \ No newline at end of file diff --git a/src/AutoMapper/Mappers/FromStringDictionaryMapper.cs b/src/AutoMapper/Mappers/FromStringDictionaryMapper.cs index d86a26e476..03ee47b68e 100644 --- a/src/AutoMapper/Mappers/FromStringDictionaryMapper.cs +++ b/src/AutoMapper/Mappers/FromStringDictionaryMapper.cs @@ -4,89 +4,88 @@ using System.Reflection; using AutoMapper.Execution; using StringDictionary = System.Collections.Generic.IDictionary; -namespace AutoMapper.Internal.Mappers +namespace AutoMapper.Internal.Mappers; + +using static Expression; +using static ExpressionBuilder; +public class FromStringDictionaryMapper : IObjectMapper { - using static Expression; - using static ExpressionBuilder; - public class FromStringDictionaryMapper : IObjectMapper + private static readonly MethodInfo MapDynamicMethod = typeof(FromStringDictionaryMapper).GetStaticMethod(nameof(MapDynamic)); + public bool IsMatch(TypePair context) => typeof(StringDictionary).IsAssignableFrom(context.SourceType); + public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, MemberMap memberMap, + Expression sourceExpression, Expression destExpression) => + Call(MapDynamicMethod, sourceExpression, destExpression.ToObject(), Constant(destExpression.Type), ContextParameter, Constant(profileMap)); + private static object MapDynamic(StringDictionary source, object boxedDestination, Type destinationType, ResolutionContext context, ProfileMap profileMap) { - private static readonly MethodInfo MapDynamicMethod = typeof(FromStringDictionaryMapper).GetStaticMethod(nameof(MapDynamic)); - public bool IsMatch(TypePair context) => typeof(StringDictionary).IsAssignableFrom(context.SourceType); - public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, MemberMap memberMap, - Expression sourceExpression, Expression destExpression) => - Call(MapDynamicMethod, sourceExpression, destExpression.ToObject(), Constant(destExpression.Type), ContextParameter, Constant(profileMap)); - private static object MapDynamic(StringDictionary source, object boxedDestination, Type destinationType, ResolutionContext context, ProfileMap profileMap) + boxedDestination ??= ObjectFactory.CreateInstance(destinationType); + int matchedCount = 0; + foreach (var member in profileMap.CreateTypeDetails(destinationType).WriteAccessors) { - boxedDestination ??= ObjectFactory.CreateInstance(destinationType); - int matchedCount = 0; - foreach (var member in profileMap.CreateTypeDetails(destinationType).WriteAccessors) + var (value, count) = MatchSource(member.Name); + if (count == 0) { - var (value, count) = MatchSource(member.Name); - if (count == 0) - { - continue; - } - if (count > 1) - { - throw new AutoMapperMappingException($"Multiple matching keys were found in the source dictionary for destination member {member}.", null, new TypePair(typeof(StringDictionary), destinationType)); - } - var mappedValue = context.MapMember(member, value, boxedDestination); - member.SetMemberValue(boxedDestination, mappedValue); - matchedCount++; + continue; } - if (matchedCount < source.Count) + if (count > 1) { - MapInnerProperties(); + throw new AutoMapperMappingException($"Multiple matching keys were found in the source dictionary for destination member {member}.", null, new TypePair(typeof(StringDictionary), destinationType)); } - return boxedDestination; - (object Value, int Count) MatchSource(string name) + var mappedValue = context.MapMember(member, value, boxedDestination); + member.SetMemberValue(boxedDestination, mappedValue); + matchedCount++; + } + if (matchedCount < source.Count) + { + MapInnerProperties(); + } + return boxedDestination; + (object Value, int Count) MatchSource(string name) + { + if (source.TryGetValue(name, out var value)) { - if (source.TryGetValue(name, out var value)) - { - return (value, 1); - } - var matches = source.Where(s => s.Key.Trim() == name).Select(s=>s.Value).ToArray(); - if (matches.Length == 1) - { - return (matches[0], 1); - } - return (null, matches.Length); + return (value, 1); + } + var matches = source.Where(s => s.Key.Trim() == name).Select(s=>s.Value).ToArray(); + if (matches.Length == 1) + { + return (matches[0], 1); } - void MapInnerProperties() + return (null, matches.Length); + } + void MapInnerProperties() + { + MemberInfo[] innerMembers; + foreach (var memberPath in source.Keys.Where(k => k.Contains('.'))) { - MemberInfo[] innerMembers; - foreach (var memberPath in source.Keys.Where(k => k.Contains('.'))) + innerMembers = ReflectionHelper.GetMemberPath(destinationType, memberPath); + var innerDestination = GetInnerDestination(); + if (innerDestination == null) { - innerMembers = ReflectionHelper.GetMemberPath(destinationType, memberPath); - var innerDestination = GetInnerDestination(); - if (innerDestination == null) - { - continue; - } - var lastMember = innerMembers[innerMembers.Length - 1]; - var value = context.MapMember(lastMember, source[memberPath], innerDestination); - lastMember.SetMemberValue(innerDestination, value); + continue; } - return; - object GetInnerDestination() + var lastMember = innerMembers[innerMembers.Length - 1]; + var value = context.MapMember(lastMember, source[memberPath], innerDestination); + lastMember.SetMemberValue(innerDestination, value); + } + return; + object GetInnerDestination() + { + var currentDestination = boxedDestination; + foreach (var member in innerMembers.Take(innerMembers.Length - 1)) { - var currentDestination = boxedDestination; - foreach (var member in innerMembers.Take(innerMembers.Length - 1)) + var newDestination = member.GetMemberValue(currentDestination); + if (newDestination == null) { - var newDestination = member.GetMemberValue(currentDestination); - if (newDestination == null) + if (!member.CanBeSet()) { - if (!member.CanBeSet()) - { - return null; - } - newDestination = ObjectFactory.CreateInstance(member.GetMemberType()); - member.SetMemberValue(currentDestination, newDestination); + return null; } - currentDestination = newDestination; + newDestination = ObjectFactory.CreateInstance(member.GetMemberType()); + member.SetMemberValue(currentDestination, newDestination); } - return currentDestination; + currentDestination = newDestination; } + return currentDestination; } } } diff --git a/src/AutoMapper/Mappers/IObjectMapper.cs b/src/AutoMapper/Mappers/IObjectMapper.cs index af3004a45a..4fbad3cf55 100644 --- a/src/AutoMapper/Mappers/IObjectMapper.cs +++ b/src/AutoMapper/Mappers/IObjectMapper.cs @@ -1,73 +1,72 @@ using System; using System.Linq.Expressions; using System.Reflection; -namespace AutoMapper.Internal.Mappers +namespace AutoMapper.Internal.Mappers; + +using static Expression; +using static Execution.ExpressionBuilder; +/// +/// Mapping execution strategy, as a chain of responsibility +/// +public interface IObjectMapper { - using static Expression; - using static Execution.ExpressionBuilder; /// - /// Mapping execution strategy, as a chain of responsibility + /// When true, the mapping engine will use this mapper as the strategy /// - public interface IObjectMapper - { - /// - /// When true, the mapping engine will use this mapper as the strategy - /// - /// Resolution context - /// Is match - bool IsMatch(TypePair context); + /// Resolution context + /// Is match + bool IsMatch(TypePair context); - /// - /// Builds a mapping expression equivalent to the base Map method - /// - /// - /// - /// - /// Source parameter - /// Destination parameter - /// - /// Map expression - Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, - MemberMap memberMap, Expression sourceExpression, Expression destExpression); - TypePair? GetAssociatedTypes(TypePair initialTypes) => null; - } /// - /// Base class for simple object mappers that don't want to use expressions. + /// Builds a mapping expression equivalent to the base Map method /// - /// type of the source - /// type of the destination - public abstract class ObjectMapper : IObjectMapper - { - private static readonly MethodInfo MapMethod = typeof(ObjectMapper).GetMethod("Map"); + /// + /// + /// + /// Source parameter + /// Destination parameter + /// + /// Map expression + Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, + MemberMap memberMap, Expression sourceExpression, Expression destExpression); + TypePair? GetAssociatedTypes(TypePair initialTypes) => null; +} +/// +/// Base class for simple object mappers that don't want to use expressions. +/// +/// type of the source +/// type of the destination +public abstract class ObjectMapper : IObjectMapper +{ + private static readonly MethodInfo MapMethod = typeof(ObjectMapper).GetMethod("Map"); - /// - /// When true, the mapping engine will use this mapper as the strategy - /// - /// Resolution context - /// Is match - public virtual bool IsMatch(TypePair context) => - typeof(TSource).IsAssignableFrom(context.SourceType) && typeof(TDestination).IsAssignableFrom(context.DestinationType); + /// + /// When true, the mapping engine will use this mapper as the strategy + /// + /// Resolution context + /// Is match + public virtual bool IsMatch(TypePair context) => + typeof(TSource).IsAssignableFrom(context.SourceType) && typeof(TDestination).IsAssignableFrom(context.DestinationType); - /// - /// Performs conversion from source to destination type - /// - /// Source object - /// Destination object - /// The compile time type of the source object - /// The compile time type of the destination object - /// Resolution context - /// Destination object - public abstract TDestination Map(TSource source, TDestination destination, Type sourceType, Type destinationType, ResolutionContext context); + /// + /// Performs conversion from source to destination type + /// + /// Source object + /// Destination object + /// The compile time type of the source object + /// The compile time type of the destination object + /// Resolution context + /// Destination object + public abstract TDestination Map(TSource source, TDestination destination, Type sourceType, Type destinationType, ResolutionContext context); - public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, - MemberMap memberMap, Expression sourceExpression, Expression destExpression) => - Call( - Constant(this), - MapMethod, - ToType(sourceExpression, typeof(TSource)), - ToType(destExpression, typeof(TDestination)), - Constant(sourceExpression.Type), - Constant(destExpression.Type), - ContextParameter); - } + public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, + MemberMap memberMap, Expression sourceExpression, Expression destExpression) => + Call( + Constant(this), + MapMethod, + ToType(sourceExpression, typeof(TSource)), + ToType(destExpression, typeof(TDestination)), + Constant(sourceExpression.Type), + Constant(destExpression.Type), + ContextParameter); } \ No newline at end of file diff --git a/src/AutoMapper/Mappers/KeyValueMapper.cs b/src/AutoMapper/Mappers/KeyValueMapper.cs index 3a76883283..e7c2379e4c 100644 --- a/src/AutoMapper/Mappers/KeyValueMapper.cs +++ b/src/AutoMapper/Mappers/KeyValueMapper.cs @@ -1,23 +1,22 @@ using System; using System.Collections.Generic; using System.Linq.Expressions; -namespace AutoMapper.Internal.Mappers +namespace AutoMapper.Internal.Mappers; + +using Execution; +public class KeyValueMapper : IObjectMapper { - using Execution; - public class KeyValueMapper : IObjectMapper + public bool IsMatch(TypePair context) => IsKeyValue(context.SourceType) && IsKeyValue(context.DestinationType); + public static bool IsKeyValue(Type type) => type.IsGenericType(typeof(KeyValuePair<,>)); + public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) { - public bool IsMatch(TypePair context) => IsKeyValue(context.SourceType) && IsKeyValue(context.DestinationType); - public static bool IsKeyValue(Type type) => type.IsGenericType(typeof(KeyValuePair<,>)); - public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) - { - var sourceArguments = sourceExpression.Type.GenericTypeArguments; - var destinationType = destExpression.Type; - var destinationArguments = destinationType.GenericTypeArguments; - var keys = new TypePair(sourceArguments[0], destinationArguments[0]); - var values = new TypePair(sourceArguments[1], destinationArguments[1]); - var mapKeys = configuration.MapExpression(profileMap, keys, ExpressionBuilder.Property(sourceExpression, "Key")); - var mapValues = configuration.MapExpression(profileMap, values, ExpressionBuilder.Property(sourceExpression, "Value")); - return Expression.New(destinationType.GetConstructor(destinationArguments), mapKeys, mapValues); - } + var sourceArguments = sourceExpression.Type.GenericTypeArguments; + var destinationType = destExpression.Type; + var destinationArguments = destinationType.GenericTypeArguments; + var keys = new TypePair(sourceArguments[0], destinationArguments[0]); + var values = new TypePair(sourceArguments[1], destinationArguments[1]); + var mapKeys = configuration.MapExpression(profileMap, keys, ExpressionBuilder.Property(sourceExpression, "Key")); + var mapValues = configuration.MapExpression(profileMap, values, ExpressionBuilder.Property(sourceExpression, "Value")); + return Expression.New(destinationType.GetConstructor(destinationArguments), mapKeys, mapValues); } } \ No newline at end of file diff --git a/src/AutoMapper/Mappers/MapperRegistry.cs b/src/AutoMapper/Mappers/MapperRegistry.cs index b7c5bb57f0..c2637b65e3 100644 --- a/src/AutoMapper/Mappers/MapperRegistry.cs +++ b/src/AutoMapper/Mappers/MapperRegistry.cs @@ -1,28 +1,27 @@ using System.Collections.Generic; -namespace AutoMapper.Internal.Mappers +namespace AutoMapper.Internal.Mappers; + +internal static class MapperRegistry { - internal static class MapperRegistry + public static List Mappers() => new(capacity: 18) { - public static List Mappers() => new(capacity: 18) - { - new CollectionMapper(),// matches IEnumerable, requires a setter, ICollection<> or IList - new AssignableMapper(),// except collections, which are copied; most likely match - new NullableSourceMapper(),// map from the underlying type - new ToStringMapper(),// object.ToString, no boxing, special case enums - new NullableDestinationMapper(),// map to the underlying type - new ConvertMapper(),// the Convert class, mostly primitives - new StringToEnumMapper(),// special case enums - new EnumToEnumMapper(),// map by string value or by numeric value - new ParseStringMapper(),// Parse(string), no boxing, Guid, TimeSpan, DateTimeOffset - new UnderlyingTypeEnumMapper(),// enum numeric value - new KeyValueMapper(),// KeyValuePair, for dictionaries - new ConstructorMapper(),// new Destination(source) - new ConversionOperatorMapper("op_Implicit"),// implicit operator Destination or implicit operator Source - new ConversionOperatorMapper("op_Explicit"),// explicit operator Destination or explicit operator Source - new FromStringDictionaryMapper(),// property values to typed object - new ToStringDictionaryMapper(),// typed object to property values - new FromDynamicMapper(),// dynamic to typed object - new ToDynamicMapper(),// typed object to dynamic - }; - } + new CollectionMapper(),// matches IEnumerable, requires a setter, ICollection<> or IList + new AssignableMapper(),// except collections, which are copied; most likely match + new NullableSourceMapper(),// map from the underlying type + new ToStringMapper(),// object.ToString, no boxing, special case enums + new NullableDestinationMapper(),// map to the underlying type + new ConvertMapper(),// the Convert class, mostly primitives + new StringToEnumMapper(),// special case enums + new EnumToEnumMapper(),// map by string value or by numeric value + new ParseStringMapper(),// Parse(string), no boxing, Guid, TimeSpan, DateTimeOffset + new UnderlyingTypeEnumMapper(),// enum numeric value + new KeyValueMapper(),// KeyValuePair, for dictionaries + new ConstructorMapper(),// new Destination(source) + new ConversionOperatorMapper("op_Implicit"),// implicit operator Destination or implicit operator Source + new ConversionOperatorMapper("op_Explicit"),// explicit operator Destination or explicit operator Source + new FromStringDictionaryMapper(),// property values to typed object + new ToStringDictionaryMapper(),// typed object to property values + new FromDynamicMapper(),// dynamic to typed object + new ToDynamicMapper(),// typed object to dynamic + }; } \ No newline at end of file diff --git a/src/AutoMapper/Mappers/NullableDestinationMapper.cs b/src/AutoMapper/Mappers/NullableDestinationMapper.cs index 76ef5d237a..fd019ce7bc 100644 --- a/src/AutoMapper/Mappers/NullableDestinationMapper.cs +++ b/src/AutoMapper/Mappers/NullableDestinationMapper.cs @@ -1,14 +1,13 @@ using System; using System.Linq.Expressions; using AutoMapper.Execution; -namespace AutoMapper.Internal.Mappers +namespace AutoMapper.Internal.Mappers; + +public class NullableDestinationMapper : IObjectMapper { - public class NullableDestinationMapper : IObjectMapper - { - public bool IsMatch(TypePair context) => context.DestinationType.IsNullableType(); - public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) => - configuration.MapExpression(profileMap, GetAssociatedTypes(sourceExpression.Type, destExpression.Type), sourceExpression, memberMap); - public TypePair? GetAssociatedTypes(TypePair initialTypes) => GetAssociatedTypes(initialTypes.SourceType, initialTypes.DestinationType); - TypePair GetAssociatedTypes(Type sourceType, Type destinationType) => new(sourceType, Nullable.GetUnderlyingType(destinationType)); - } + public bool IsMatch(TypePair context) => context.DestinationType.IsNullableType(); + public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) => + configuration.MapExpression(profileMap, GetAssociatedTypes(sourceExpression.Type, destExpression.Type), sourceExpression, memberMap); + public TypePair? GetAssociatedTypes(TypePair initialTypes) => GetAssociatedTypes(initialTypes.SourceType, initialTypes.DestinationType); + TypePair GetAssociatedTypes(Type sourceType, Type destinationType) => new(sourceType, Nullable.GetUnderlyingType(destinationType)); } \ No newline at end of file diff --git a/src/AutoMapper/Mappers/NullableSourceMapper.cs b/src/AutoMapper/Mappers/NullableSourceMapper.cs index 9d9a8ce711..469373534f 100644 --- a/src/AutoMapper/Mappers/NullableSourceMapper.cs +++ b/src/AutoMapper/Mappers/NullableSourceMapper.cs @@ -1,15 +1,14 @@ using System; using System.Linq.Expressions; using AutoMapper.Execution; -namespace AutoMapper.Internal.Mappers +namespace AutoMapper.Internal.Mappers; + +public class NullableSourceMapper : IObjectMapper { - public class NullableSourceMapper : IObjectMapper - { - public bool IsMatch(TypePair context) => context.SourceType.IsNullableType(); - public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) => - configuration.MapExpression(profileMap, GetAssociatedTypes(sourceExpression.Type, destExpression.Type), - ExpressionBuilder.Property(sourceExpression, "Value"), memberMap, destExpression); - public TypePair? GetAssociatedTypes(TypePair initialTypes) => GetAssociatedTypes(initialTypes.SourceType, initialTypes.DestinationType); - TypePair GetAssociatedTypes(Type sourceType, Type destinationType) => new(Nullable.GetUnderlyingType(sourceType), destinationType); - } + public bool IsMatch(TypePair context) => context.SourceType.IsNullableType(); + public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) => + configuration.MapExpression(profileMap, GetAssociatedTypes(sourceExpression.Type, destExpression.Type), + ExpressionBuilder.Property(sourceExpression, "Value"), memberMap, destExpression); + public TypePair? GetAssociatedTypes(TypePair initialTypes) => GetAssociatedTypes(initialTypes.SourceType, initialTypes.DestinationType); + TypePair GetAssociatedTypes(Type sourceType, Type destinationType) => new(Nullable.GetUnderlyingType(sourceType), destinationType); } \ No newline at end of file diff --git a/src/AutoMapper/Mappers/ParseStringMapper.cs b/src/AutoMapper/Mappers/ParseStringMapper.cs index 73a064f8db..de4bcef80d 100644 --- a/src/AutoMapper/Mappers/ParseStringMapper.cs +++ b/src/AutoMapper/Mappers/ParseStringMapper.cs @@ -1,12 +1,11 @@ using System; using System.Linq.Expressions; -namespace AutoMapper.Internal.Mappers +namespace AutoMapper.Internal.Mappers; + +public class ParseStringMapper : IObjectMapper { - public class ParseStringMapper : IObjectMapper - { - public bool IsMatch(TypePair context) => context.SourceType == typeof(string) && HasParse(context.DestinationType); - static bool HasParse(Type type) => type == typeof(Guid) || type == typeof(TimeSpan) || type == typeof(DateTimeOffset); - public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) => - Expression.Call(destExpression.Type.GetMethod("Parse", new[] { typeof(string) }), sourceExpression); - } + public bool IsMatch(TypePair context) => context.SourceType == typeof(string) && HasParse(context.DestinationType); + static bool HasParse(Type type) => type == typeof(Guid) || type == typeof(TimeSpan) || type == typeof(DateTimeOffset); + public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) => + Expression.Call(destExpression.Type.GetMethod("Parse", new[] { typeof(string) }), sourceExpression); } \ No newline at end of file diff --git a/src/AutoMapper/Mappers/StringToEnumMapper.cs b/src/AutoMapper/Mappers/StringToEnumMapper.cs index 9e2832160d..1ef176718c 100644 --- a/src/AutoMapper/Mappers/StringToEnumMapper.cs +++ b/src/AutoMapper/Mappers/StringToEnumMapper.cs @@ -3,43 +3,42 @@ using System.Linq.Expressions; using System.Reflection; using System.Runtime.Serialization; -namespace AutoMapper.Internal.Mappers +namespace AutoMapper.Internal.Mappers; + +using static Execution.ExpressionBuilder; +using static Expression; +public class StringToEnumMapper : IObjectMapper { - using static Execution.ExpressionBuilder; - using static Expression; - public class StringToEnumMapper : IObjectMapper + private static readonly MethodInfo EqualsMethod = typeof(StringToEnumMapper).GetMethod(nameof(StringCompareOrdinalIgnoreCase)); + private static readonly MethodInfo ParseMethod = typeof(Enum).StaticGenericMethod("Parse", parametersCount: 2); + private static readonly PropertyInfo Length = typeof(string).GetProperty("Length"); + public bool IsMatch(TypePair context) => context.SourceType == typeof(string) && context.DestinationType.IsEnum; + public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, + MemberMap memberMap, Expression sourceExpression, Expression destExpression) { - private static readonly MethodInfo EqualsMethod = typeof(StringToEnumMapper).GetMethod(nameof(StringCompareOrdinalIgnoreCase)); - private static readonly MethodInfo ParseMethod = typeof(Enum).StaticGenericMethod("Parse", parametersCount: 2); - private static readonly PropertyInfo Length = typeof(string).GetProperty("Length"); - public bool IsMatch(TypePair context) => context.SourceType == typeof(string) && context.DestinationType.IsEnum; - public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, - MemberMap memberMap, Expression sourceExpression, Expression destExpression) - { - var destinationType = destExpression.Type; - var ignoreCase = True; - var enumParse = Call(ParseMethod.MakeGenericMethod(destinationType), sourceExpression, ignoreCase); - var enumMember = CheckEnumMember(sourceExpression, destinationType, enumParse, EqualsMethod); - return Condition(Equal(Property(sourceExpression, Length), Zero), configuration.Default(destinationType), enumMember); - } - internal static Expression CheckEnumMember(Expression sourceExpression, Type enumType, Expression defaultExpression, MethodInfo comparison = null) + var destinationType = destExpression.Type; + var ignoreCase = True; + var enumParse = Call(ParseMethod.MakeGenericMethod(destinationType), sourceExpression, ignoreCase); + var enumMember = CheckEnumMember(sourceExpression, destinationType, enumParse, EqualsMethod); + return Condition(Equal(Property(sourceExpression, Length), Zero), configuration.Default(destinationType), enumMember); + } + internal static Expression CheckEnumMember(Expression sourceExpression, Type enumType, Expression defaultExpression, MethodInfo comparison = null) + { + List switchCases = null; + foreach (var memberInfo in enumType.GetFields(TypeExtensions.StaticFlags)) { - List switchCases = null; - foreach (var memberInfo in enumType.GetFields(TypeExtensions.StaticFlags)) + var attributeValue = memberInfo.GetCustomAttribute()?.Value; + if (attributeValue == null) { - var attributeValue = memberInfo.GetCustomAttribute()?.Value; - if (attributeValue == null) - { - continue; - } - var enumToObject = Constant(Enum.ToObject(enumType, memberInfo.GetValue(null))); - var attributeConstant = Constant(attributeValue); - var (body, testValue) = comparison == null ? (attributeConstant, enumToObject) : (ToType(enumToObject, enumType), attributeConstant); - switchCases ??= new(); - switchCases.Add(SwitchCase(body, testValue)); + continue; } - return switchCases == null ? defaultExpression : Switch(sourceExpression, defaultExpression, comparison, switchCases); + var enumToObject = Constant(Enum.ToObject(enumType, memberInfo.GetValue(null))); + var attributeConstant = Constant(attributeValue); + var (body, testValue) = comparison == null ? (attributeConstant, enumToObject) : (ToType(enumToObject, enumType), attributeConstant); + switchCases ??= new(); + switchCases.Add(SwitchCase(body, testValue)); } - public static bool StringCompareOrdinalIgnoreCase(string x, string y) => StringComparer.OrdinalIgnoreCase.Equals(x, y); + return switchCases == null ? defaultExpression : Switch(sourceExpression, defaultExpression, comparison, switchCases); } + public static bool StringCompareOrdinalIgnoreCase(string x, string y) => StringComparer.OrdinalIgnoreCase.Equals(x, y); } \ No newline at end of file diff --git a/src/AutoMapper/Mappers/ToDynamicMapper.cs b/src/AutoMapper/Mappers/ToDynamicMapper.cs index fdef4e014b..7cad4dec81 100644 --- a/src/AutoMapper/Mappers/ToDynamicMapper.cs +++ b/src/AutoMapper/Mappers/ToDynamicMapper.cs @@ -5,46 +5,45 @@ using AutoMapper.Execution; using Microsoft.CSharp.RuntimeBinder; using Binder = Microsoft.CSharp.RuntimeBinder.Binder; -namespace AutoMapper.Internal.Mappers +namespace AutoMapper.Internal.Mappers; + +using static Expression; +using static ExpressionBuilder; +public class ToDynamicMapper : IObjectMapper { - using static Expression; - using static ExpressionBuilder; - public class ToDynamicMapper : IObjectMapper + private static readonly MethodInfo MapMethodInfo = typeof(ToDynamicMapper).GetStaticMethod(nameof(Map)); + private static object Map(object source, object destination, Type destinationType, ResolutionContext context, ProfileMap profileMap) { - private static readonly MethodInfo MapMethodInfo = typeof(ToDynamicMapper).GetStaticMethod(nameof(Map)); - private static object Map(object source, object destination, Type destinationType, ResolutionContext context, ProfileMap profileMap) + destination ??= ObjectFactory.CreateInstance(destinationType); + var sourceTypeDetails = profileMap.CreateTypeDetails(source.GetType()); + foreach (var member in sourceTypeDetails.ReadAccessors) { - destination ??= ObjectFactory.CreateInstance(destinationType); - var sourceTypeDetails = profileMap.CreateTypeDetails(source.GetType()); - foreach (var member in sourceTypeDetails.ReadAccessors) + object sourceMemberValue; + try { - object sourceMemberValue; - try - { - sourceMemberValue = member.GetMemberValue(source); - } - catch (RuntimeBinderException) - { - continue; - } - var destinationMemberValue = context.MapMember(member, sourceMemberValue); - SetDynamically(member.Name, destination, destinationMemberValue); + sourceMemberValue = member.GetMemberValue(source); } - return destination; - } - private static void SetDynamically(string memberName, object target, object value) - { - var binder = Binder.SetMember(CSharpBinderFlags.None, memberName, null, - new[]{ - CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null), - CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) - }); - var callsite = CallSite>.Create(binder); - callsite.Target(callsite, target, value); + catch (RuntimeBinderException) + { + continue; + } + var destinationMemberValue = context.MapMember(member, sourceMemberValue); + SetDynamically(member.Name, destination, destinationMemberValue); } - public bool IsMatch(TypePair context) => context.DestinationType.IsDynamic() && !context.SourceType.IsDynamic(); - public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, - MemberMap memberMap, Expression sourceExpression, Expression destExpression) => - Call(MapMethodInfo, sourceExpression.ToObject(), destExpression, Constant(destExpression.Type), ContextParameter, Constant(profileMap)); + return destination; + } + private static void SetDynamically(string memberName, object target, object value) + { + var binder = Binder.SetMember(CSharpBinderFlags.None, memberName, null, + new[]{ + CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null), + CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) + }); + var callsite = CallSite>.Create(binder); + callsite.Target(callsite, target, value); } + public bool IsMatch(TypePair context) => context.DestinationType.IsDynamic() && !context.SourceType.IsDynamic(); + public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, + MemberMap memberMap, Expression sourceExpression, Expression destExpression) => + Call(MapMethodInfo, sourceExpression.ToObject(), destExpression, Constant(destExpression.Type), ContextParameter, Constant(profileMap)); } \ No newline at end of file diff --git a/src/AutoMapper/Mappers/ToStringDictionaryMapper.cs b/src/AutoMapper/Mappers/ToStringDictionaryMapper.cs index 5a17dd2f4a..2ba980dc4f 100644 --- a/src/AutoMapper/Mappers/ToStringDictionaryMapper.cs +++ b/src/AutoMapper/Mappers/ToStringDictionaryMapper.cs @@ -3,16 +3,15 @@ using System.Linq; using System.Linq.Expressions; using System.Reflection; -namespace AutoMapper.Internal.Mappers +namespace AutoMapper.Internal.Mappers; + +using static Expression; +public class ToStringDictionaryMapper : IObjectMapper { - using static Expression; - public class ToStringDictionaryMapper : IObjectMapper - { - private static readonly MethodInfo MembersDictionaryMethodInfo = typeof(ToStringDictionaryMapper).GetStaticMethod(nameof(MembersDictionary)); - public bool IsMatch(TypePair context) => typeof(IDictionary).IsAssignableFrom(context.DestinationType); - public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) => - Call(MembersDictionaryMethodInfo, sourceExpression.ToObject(), Constant(profileMap)); - private static Dictionary MembersDictionary(object source, ProfileMap profileMap) => - profileMap.CreateTypeDetails(source.GetType()).ReadAccessors.ToDictionary(p => p.Name, p => p.GetMemberValue(source)); - } + private static readonly MethodInfo MembersDictionaryMethodInfo = typeof(ToStringDictionaryMapper).GetStaticMethod(nameof(MembersDictionary)); + public bool IsMatch(TypePair context) => typeof(IDictionary).IsAssignableFrom(context.DestinationType); + public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) => + Call(MembersDictionaryMethodInfo, sourceExpression.ToObject(), Constant(profileMap)); + private static Dictionary MembersDictionary(object source, ProfileMap profileMap) => + profileMap.CreateTypeDetails(source.GetType()).ReadAccessors.ToDictionary(p => p.Name, p => p.GetMemberValue(source)); } \ No newline at end of file diff --git a/src/AutoMapper/Mappers/ToStringMapper.cs b/src/AutoMapper/Mappers/ToStringMapper.cs index df430d3c23..1fe28e4750 100644 --- a/src/AutoMapper/Mappers/ToStringMapper.cs +++ b/src/AutoMapper/Mappers/ToStringMapper.cs @@ -1,16 +1,15 @@ using AutoMapper.Execution; using System.Linq.Expressions; -namespace AutoMapper.Internal.Mappers +namespace AutoMapper.Internal.Mappers; + +using static Expression; +public class ToStringMapper : IObjectMapper { - using static Expression; - public class ToStringMapper : IObjectMapper + public bool IsMatch(TypePair context) => context.DestinationType == typeof(string); + public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) { - public bool IsMatch(TypePair context) => context.DestinationType == typeof(string); - public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) - { - var sourceType = sourceExpression.Type; - var toStringCall = Call(sourceExpression, ExpressionBuilder.ObjectToString); - return sourceType.IsEnum ? StringToEnumMapper.CheckEnumMember(sourceExpression, sourceType, toStringCall) : toStringCall; - } + var sourceType = sourceExpression.Type; + var toStringCall = Call(sourceExpression, ExpressionBuilder.ObjectToString); + return sourceType.IsEnum ? StringToEnumMapper.CheckEnumMember(sourceExpression, sourceType, toStringCall) : toStringCall; } } \ No newline at end of file diff --git a/src/AutoMapper/Mappers/UnderlyingEnumTypeMapper.cs b/src/AutoMapper/Mappers/UnderlyingEnumTypeMapper.cs index 3f4c97b09d..e2981f3eab 100644 --- a/src/AutoMapper/Mappers/UnderlyingEnumTypeMapper.cs +++ b/src/AutoMapper/Mappers/UnderlyingEnumTypeMapper.cs @@ -1,10 +1,9 @@ using System.Linq.Expressions; -namespace AutoMapper.Internal.Mappers +namespace AutoMapper.Internal.Mappers; + +public class UnderlyingTypeEnumMapper : IObjectMapper { - public class UnderlyingTypeEnumMapper : IObjectMapper - { - public bool IsMatch(TypePair context) => context.IsEnumToUnderlyingType() || context.IsUnderlyingTypeToEnum(); - public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, - MemberMap memberMap, Expression sourceExpression, Expression destExpression) => sourceExpression; - } + public bool IsMatch(TypePair context) => context.IsEnumToUnderlyingType() || context.IsUnderlyingTypeToEnum(); + public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, + MemberMap memberMap, Expression sourceExpression, Expression destExpression) => sourceExpression; } \ No newline at end of file diff --git a/src/AutoMapper/MemberMap.cs b/src/AutoMapper/MemberMap.cs index c21ef0e1f3..09bc37690f 100644 --- a/src/AutoMapper/MemberMap.cs +++ b/src/AutoMapper/MemberMap.cs @@ -3,92 +3,91 @@ using System.ComponentModel; using System.Linq.Expressions; using System.Reflection; -namespace AutoMapper -{ - using static Expression; - using Execution; - using Internal; - using System.Diagnostics; +namespace AutoMapper; - /// - /// The base class for member maps (property, constructor and path maps). - /// - [EditorBrowsable(EditorBrowsableState.Never)] - public class MemberMap : IValueResolver +using static Expression; +using Execution; +using Internal; +using System.Diagnostics; + +/// +/// The base class for member maps (property, constructor and path maps). +/// +[EditorBrowsable(EditorBrowsableState.Never)] +public class MemberMap : IValueResolver +{ + protected MemberMap(TypeMap typeMap = null) => TypeMap = typeMap; + internal static readonly MemberMap Instance = new(); + public TypeMap TypeMap { get; protected set; } + public LambdaExpression CustomMapExpression => Resolver?.ProjectToExpression; + public bool IsResolveConfigured => Resolver != null && Resolver != this; + public void SetResolver(LambdaExpression lambda) => Resolver = new ExpressionResolver(lambda); + public virtual Type SourceType => default; + public virtual MemberInfo[] SourceMembers { get => Array.Empty(); set { } } + public virtual IncludedMember IncludedMember => null; + public virtual string DestinationName => default; + public virtual Type DestinationType { get => default; protected set { } } + public virtual TypePair Types() => new(SourceType, DestinationType); + public bool CanResolveValue => !Ignored && Resolver != null; + public bool IsMapped => Ignored || CanResolveValue; + public virtual bool Ignored { get => default; set { } } + public virtual bool Inline { get; set; } = true; + public virtual bool? AllowNull { get => null; set { } } + public virtual bool CanBeSet => true; + public virtual bool? UseDestinationValue { get => default; set { } } + public virtual object NullSubstitute { get => default; set { } } + public virtual LambdaExpression PreCondition { get => default; set { } } + public virtual LambdaExpression Condition { get => default; set { } } + public IValueResolver Resolver { get; set; } + public virtual IReadOnlyCollection ValueTransformers => Array.Empty(); + public MemberInfo SourceMember => Resolver?.GetSourceMember(this); + public string GetSourceMemberName() => Resolver?.SourceMemberName ?? SourceMember?.Name; + public bool MustUseDestination => UseDestinationValue is true || !CanBeSet; + public void MapFrom(LambdaExpression sourceMember) { - protected MemberMap(TypeMap typeMap = null) => TypeMap = typeMap; - internal static readonly MemberMap Instance = new(); - public TypeMap TypeMap { get; protected set; } - public LambdaExpression CustomMapExpression => Resolver?.ProjectToExpression; - public bool IsResolveConfigured => Resolver != null && Resolver != this; - public void SetResolver(LambdaExpression lambda) => Resolver = new ExpressionResolver(lambda); - public virtual Type SourceType => default; - public virtual MemberInfo[] SourceMembers { get => Array.Empty(); set { } } - public virtual IncludedMember IncludedMember => null; - public virtual string DestinationName => default; - public virtual Type DestinationType { get => default; protected set { } } - public virtual TypePair Types() => new(SourceType, DestinationType); - public bool CanResolveValue => !Ignored && Resolver != null; - public bool IsMapped => Ignored || CanResolveValue; - public virtual bool Ignored { get => default; set { } } - public virtual bool Inline { get; set; } = true; - public virtual bool? AllowNull { get => null; set { } } - public virtual bool CanBeSet => true; - public virtual bool? UseDestinationValue { get => default; set { } } - public virtual object NullSubstitute { get => default; set { } } - public virtual LambdaExpression PreCondition { get => default; set { } } - public virtual LambdaExpression Condition { get => default; set { } } - public IValueResolver Resolver { get; set; } - public virtual IReadOnlyCollection ValueTransformers => Array.Empty(); - public MemberInfo SourceMember => Resolver?.GetSourceMember(this); - public string GetSourceMemberName() => Resolver?.SourceMemberName ?? SourceMember?.Name; - public bool MustUseDestination => UseDestinationValue is true || !CanBeSet; - public void MapFrom(LambdaExpression sourceMember) - { - SetResolver(sourceMember); - Ignored = false; - } - public void MapFrom(string sourceMembersPath, MemberInfo[] members) - { - var sourceType = TypeMap.SourceType; - var sourceMembers = sourceType.ContainsGenericParameters ? null :// just a placeholder so the member is mapped - members[0].DeclaringType.ContainsGenericParameters ? ReflectionHelper.GetMemberPath(sourceType, sourceMembersPath, TypeMap) : members; - Resolver = new MemberPathResolver(sourceMembers); - } - public override string ToString() => DestinationName; - public Expression ChainSourceMembers(Expression source) => SourceMembers.Chain(source); - public Expression ChainSourceMembers(IGlobalConfiguration configuration, Expression source, Expression defaultValue) - { - var expression = ChainSourceMembers(source); - return IncludedMember == null && SourceMembers.Length < 2 ? expression : expression.NullCheck(configuration, this, defaultValue); - } - public bool AllowsNullDestinationValues => Profile?.AllowsNullDestinationValuesFor(this) ?? true; - public ProfileMap Profile => TypeMap?.Profile; - protected Type GetSourceType() => Resolver?.ResolvedType ?? DestinationType; - public void MapByConvention(MemberInfo[] sourceMembers) - { - Debug.Assert(sourceMembers.Length > 0); - SourceMembers = sourceMembers; - Resolver = this; - } - Expression IValueResolver.GetExpression(IGlobalConfiguration configuration, MemberMap memberMap, Expression source, Expression destination, Expression destinationMember) => - ChainSourceMembers(configuration, source, destinationMember); - MemberInfo IValueResolver.GetSourceMember(MemberMap memberMap) => SourceMembers[0]; - Type IValueResolver.ResolvedType => SourceMembers[^1].GetMemberType(); + SetResolver(sourceMember); + Ignored = false; } - public readonly record struct ValueTransformerConfiguration(Type ValueType, LambdaExpression TransformerExpression) + public void MapFrom(string sourceMembersPath, MemberInfo[] members) { - public bool IsMatch(MemberMap memberMap) => ValueType.IsAssignableFrom(memberMap.SourceType) && memberMap.DestinationType.IsAssignableFrom(ValueType); + var sourceType = TypeMap.SourceType; + var sourceMembers = sourceType.ContainsGenericParameters ? null :// just a placeholder so the member is mapped + members[0].DeclaringType.ContainsGenericParameters ? ReflectionHelper.GetMemberPath(sourceType, sourceMembersPath, TypeMap) : members; + Resolver = new MemberPathResolver(sourceMembers); } - public static class ValueTransformerConfigurationExtensions + public override string ToString() => DestinationName; + public Expression ChainSourceMembers(Expression source) => SourceMembers.Chain(source); + public Expression ChainSourceMembers(IGlobalConfiguration configuration, Expression source, Expression defaultValue) { - /// - /// Apply a transformation function after any resolved destination member value with the given type - /// - /// Value type to match and transform - /// Value transformer list - /// Transformation expression - public static void Add(this List valueTransformers, Expression> transformer) => - valueTransformers.Add(new ValueTransformerConfiguration(typeof(TValue), transformer)); + var expression = ChainSourceMembers(source); + return IncludedMember == null && SourceMembers.Length < 2 ? expression : expression.NullCheck(configuration, this, defaultValue); } + public bool AllowsNullDestinationValues => Profile?.AllowsNullDestinationValuesFor(this) ?? true; + public ProfileMap Profile => TypeMap?.Profile; + protected Type GetSourceType() => Resolver?.ResolvedType ?? DestinationType; + public void MapByConvention(MemberInfo[] sourceMembers) + { + Debug.Assert(sourceMembers.Length > 0); + SourceMembers = sourceMembers; + Resolver = this; + } + Expression IValueResolver.GetExpression(IGlobalConfiguration configuration, MemberMap memberMap, Expression source, Expression destination, Expression destinationMember) => + ChainSourceMembers(configuration, source, destinationMember); + MemberInfo IValueResolver.GetSourceMember(MemberMap memberMap) => SourceMembers[0]; + Type IValueResolver.ResolvedType => SourceMembers[^1].GetMemberType(); +} +public readonly record struct ValueTransformerConfiguration(Type ValueType, LambdaExpression TransformerExpression) +{ + public bool IsMatch(MemberMap memberMap) => ValueType.IsAssignableFrom(memberMap.SourceType) && memberMap.DestinationType.IsAssignableFrom(ValueType); +} +public static class ValueTransformerConfigurationExtensions +{ + /// + /// Apply a transformation function after any resolved destination member value with the given type + /// + /// Value type to match and transform + /// Value transformer list + /// Transformation expression + public static void Add(this List valueTransformers, Expression> transformer) => + valueTransformers.Add(new ValueTransformerConfiguration(typeof(TValue), transformer)); } \ No newline at end of file diff --git a/src/AutoMapper/PathMap.cs b/src/AutoMapper/PathMap.cs index 3e49a27868..67eaf9d5b9 100644 --- a/src/AutoMapper/PathMap.cs +++ b/src/AutoMapper/PathMap.cs @@ -2,35 +2,34 @@ using System.Diagnostics; using System.Linq.Expressions; -namespace AutoMapper -{ - using Internal; - using System.ComponentModel; +namespace AutoMapper; + +using Internal; +using System.ComponentModel; - [DebuggerDisplay("{DestinationExpression}")] - [EditorBrowsable(EditorBrowsableState.Never)] - public class PathMap : MemberMap +[DebuggerDisplay("{DestinationExpression}")] +[EditorBrowsable(EditorBrowsableState.Never)] +public class PathMap : MemberMap +{ + public PathMap(PathMap pathMap, TypeMap typeMap, IncludedMember includedMember) : this(pathMap.DestinationExpression, pathMap.MemberPath, typeMap) + { + IncludedMember = includedMember.Chain(pathMap.IncludedMember); + Resolver = pathMap.Resolver; + Condition = pathMap.Condition; + Ignored = pathMap.Ignored; + } + public PathMap(LambdaExpression destinationExpression, MemberPath memberPath, TypeMap typeMap) : base(typeMap) { - public PathMap(PathMap pathMap, TypeMap typeMap, IncludedMember includedMember) : this(pathMap.DestinationExpression, pathMap.MemberPath, typeMap) - { - IncludedMember = includedMember.Chain(pathMap.IncludedMember); - Resolver = pathMap.Resolver; - Condition = pathMap.Condition; - Ignored = pathMap.Ignored; - } - public PathMap(LambdaExpression destinationExpression, MemberPath memberPath, TypeMap typeMap) : base(typeMap) - { - MemberPath = memberPath; - DestinationExpression = destinationExpression; - } - public override Type SourceType => Resolver.ResolvedType; - public LambdaExpression DestinationExpression { get; } - public MemberPath MemberPath { get; } - public override Type DestinationType => MemberPath.Last.GetMemberType(); - public override string DestinationName => MemberPath.ToString(); - public override bool CanBeSet => ReflectionHelper.CanBeSet(MemberPath.Last); - public override bool Ignored { get; set; } - public override IncludedMember IncludedMember { get; } - public override LambdaExpression Condition { get; set; } + MemberPath = memberPath; + DestinationExpression = destinationExpression; } + public override Type SourceType => Resolver.ResolvedType; + public LambdaExpression DestinationExpression { get; } + public MemberPath MemberPath { get; } + public override Type DestinationType => MemberPath.Last.GetMemberType(); + public override string DestinationName => MemberPath.ToString(); + public override bool CanBeSet => ReflectionHelper.CanBeSet(MemberPath.Last); + public override bool Ignored { get; set; } + public override IncludedMember IncludedMember { get; } + public override LambdaExpression Condition { get; set; } } \ No newline at end of file diff --git a/src/AutoMapper/ProfileMap.cs b/src/AutoMapper/ProfileMap.cs index 6e63c8f54c..38c06009fc 100644 --- a/src/AutoMapper/ProfileMap.cs +++ b/src/AutoMapper/ProfileMap.cs @@ -10,285 +10,284 @@ using AutoMapper.Execution; using AutoMapper.Internal; -namespace AutoMapper +namespace AutoMapper; + +using static Expression; +[DebuggerDisplay("{Name}")] +[EditorBrowsable(EditorBrowsableState.Never)] +public class ProfileMap { - using static Expression; - [DebuggerDisplay("{Name}")] - [EditorBrowsable(EditorBrowsableState.Never)] - public class ProfileMap - { - private static readonly HashSet EmptyHashSet = new(); - private TypeMapConfiguration[] _typeMapConfigs; - private Dictionary _openTypeMapConfigs; - private Dictionary _typeDetails; - private ConcurrentDictionaryWrapper _runtimeTypeDetails; - public ProfileMap(IProfileConfiguration profile, IGlobalConfigurationExpression configuration = null) - { - var globalProfile = (IProfileConfiguration)configuration; - Name = profile.ProfileName; - AllowNullCollections = profile.AllowNullCollections ?? configuration?.AllowNullCollections ?? false; - AllowNullDestinationValues = profile.AllowNullDestinationValues ?? configuration?.AllowNullDestinationValues ?? true; - EnableNullPropagationForQueryMapping = profile.EnableNullPropagationForQueryMapping ?? configuration?.EnableNullPropagationForQueryMapping ?? false; - ConstructorMappingEnabled = profile.ConstructorMappingEnabled ?? globalProfile?.ConstructorMappingEnabled ?? true; - MethodMappingEnabled = profile.MethodMappingEnabled ?? globalProfile?.MethodMappingEnabled ?? true; - FieldMappingEnabled = profile.FieldMappingEnabled ?? globalProfile?.FieldMappingEnabled ?? true; - ShouldMapField = profile.ShouldMapField ?? configuration?.ShouldMapField ?? (p => p.IsPublic); - ShouldMapProperty = profile.ShouldMapProperty ?? configuration?.ShouldMapProperty ?? (p => p.IsPublic()); - ShouldMapMethod = profile.ShouldMapMethod ?? configuration?.ShouldMapMethod ?? (p => !p.IsSpecialName); - ShouldUseConstructor = profile.ShouldUseConstructor ?? configuration?.ShouldUseConstructor ?? (c => true); - ValueTransformers = profile.ValueTransformers.Concat(configuration?.ValueTransformers).ToArray(); - var profileInternal = (IProfileExpressionInternal)profile; - MemberConfiguration = profileInternal.MemberConfiguration; - MemberConfiguration.Merge(configuration.Internal()?.MemberConfiguration); - var globalIgnores = profile.GlobalIgnores.Concat(globalProfile?.GlobalIgnores); - GlobalIgnores = globalIgnores == Array.Empty() ? EmptyHashSet : new HashSet(globalIgnores); - SourceExtensionMethods = profile.SourceExtensionMethods.Concat(globalProfile?.SourceExtensionMethods).ToArray(); - AllPropertyMapActions = profile.AllPropertyMapActions.Concat(globalProfile?.AllPropertyMapActions).ToArray(); - AllTypeMapActions = profile.AllTypeMapActions.Concat(globalProfile?.AllTypeMapActions).ToArray(); - profileInternal.MemberConfiguration.Seal(); - Prefixes = new(profileInternal.Prefixes.Concat(configuration?.Prefixes)); - Postfixes = new(profileInternal.Postfixes.Concat(configuration?.Postfixes)); - TypeMapConfigs(); - OpenTypeMapConfigs(); - _typeDetails = new(2 * _typeMapConfigs.Length); - return; - void TypeMapConfigs() + private static readonly HashSet EmptyHashSet = new(); + private TypeMapConfiguration[] _typeMapConfigs; + private Dictionary _openTypeMapConfigs; + private Dictionary _typeDetails; + private ConcurrentDictionaryWrapper _runtimeTypeDetails; + public ProfileMap(IProfileConfiguration profile, IGlobalConfigurationExpression configuration = null) + { + var globalProfile = (IProfileConfiguration)configuration; + Name = profile.ProfileName; + AllowNullCollections = profile.AllowNullCollections ?? configuration?.AllowNullCollections ?? false; + AllowNullDestinationValues = profile.AllowNullDestinationValues ?? configuration?.AllowNullDestinationValues ?? true; + EnableNullPropagationForQueryMapping = profile.EnableNullPropagationForQueryMapping ?? configuration?.EnableNullPropagationForQueryMapping ?? false; + ConstructorMappingEnabled = profile.ConstructorMappingEnabled ?? globalProfile?.ConstructorMappingEnabled ?? true; + MethodMappingEnabled = profile.MethodMappingEnabled ?? globalProfile?.MethodMappingEnabled ?? true; + FieldMappingEnabled = profile.FieldMappingEnabled ?? globalProfile?.FieldMappingEnabled ?? true; + ShouldMapField = profile.ShouldMapField ?? configuration?.ShouldMapField ?? (p => p.IsPublic); + ShouldMapProperty = profile.ShouldMapProperty ?? configuration?.ShouldMapProperty ?? (p => p.IsPublic()); + ShouldMapMethod = profile.ShouldMapMethod ?? configuration?.ShouldMapMethod ?? (p => !p.IsSpecialName); + ShouldUseConstructor = profile.ShouldUseConstructor ?? configuration?.ShouldUseConstructor ?? (c => true); + ValueTransformers = profile.ValueTransformers.Concat(configuration?.ValueTransformers).ToArray(); + var profileInternal = (IProfileExpressionInternal)profile; + MemberConfiguration = profileInternal.MemberConfiguration; + MemberConfiguration.Merge(configuration.Internal()?.MemberConfiguration); + var globalIgnores = profile.GlobalIgnores.Concat(globalProfile?.GlobalIgnores); + GlobalIgnores = globalIgnores == Array.Empty() ? EmptyHashSet : new HashSet(globalIgnores); + SourceExtensionMethods = profile.SourceExtensionMethods.Concat(globalProfile?.SourceExtensionMethods).ToArray(); + AllPropertyMapActions = profile.AllPropertyMapActions.Concat(globalProfile?.AllPropertyMapActions).ToArray(); + AllTypeMapActions = profile.AllTypeMapActions.Concat(globalProfile?.AllTypeMapActions).ToArray(); + profileInternal.MemberConfiguration.Seal(); + Prefixes = new(profileInternal.Prefixes.Concat(configuration?.Prefixes)); + Postfixes = new(profileInternal.Postfixes.Concat(configuration?.Postfixes)); + TypeMapConfigs(); + OpenTypeMapConfigs(); + _typeDetails = new(2 * _typeMapConfigs.Length); + return; + void TypeMapConfigs() + { + _typeMapConfigs = new TypeMapConfiguration[profile.TypeMapConfigs.Count]; + var index = 0; + var reverseMapsCount = 0; + foreach (var typeMapConfig in profile.TypeMapConfigs) { - _typeMapConfigs = new TypeMapConfiguration[profile.TypeMapConfigs.Count]; - var index = 0; - var reverseMapsCount = 0; - foreach (var typeMapConfig in profile.TypeMapConfigs) + _typeMapConfigs[index++] = typeMapConfig; + if (typeMapConfig.ReverseTypeMap != null) { - _typeMapConfigs[index++] = typeMapConfig; - if (typeMapConfig.ReverseTypeMap != null) - { - reverseMapsCount++; - } + reverseMapsCount++; } - TypeMapsCount = index + reverseMapsCount; } - void OpenTypeMapConfigs() + TypeMapsCount = index + reverseMapsCount; + } + void OpenTypeMapConfigs() + { + _openTypeMapConfigs = new(profile.OpenTypeMapConfigs.Count); + foreach (var openTypeMapConfig in profile.OpenTypeMapConfigs) { - _openTypeMapConfigs = new(profile.OpenTypeMapConfigs.Count); - foreach (var openTypeMapConfig in profile.OpenTypeMapConfigs) + _openTypeMapConfigs.Add(openTypeMapConfig.Types, openTypeMapConfig); + var reverseMap = openTypeMapConfig.ReverseTypeMap; + if (reverseMap != null) { - _openTypeMapConfigs.Add(openTypeMapConfig.Types, openTypeMapConfig); - var reverseMap = openTypeMapConfig.ReverseTypeMap; - if (reverseMap != null) - { - _openTypeMapConfigs.Add(reverseMap.Types, reverseMap); - } + _openTypeMapConfigs.Add(reverseMap.Types, reverseMap); } } } - public int OpenTypeMapsCount => _openTypeMapConfigs.Count; - public int TypeMapsCount { get; private set; } - internal void Clear() + } + public int OpenTypeMapsCount => _openTypeMapConfigs.Count; + public int TypeMapsCount { get; private set; } + internal void Clear() + { + _typeDetails = null; + _typeMapConfigs = null; + _runtimeTypeDetails = new(TypeDetailsFactory, 2 * _openTypeMapConfigs.Count); + } + public bool AllowNullCollections { get; } + public bool AllowNullDestinationValues { get; } + public bool ConstructorMappingEnabled { get; } + public bool EnableNullPropagationForQueryMapping { get; } + public bool MethodMappingEnabled { get; } + public bool FieldMappingEnabled { get; } + public string Name { get; } + public Func ShouldMapField { get; } + public Func ShouldMapProperty { get; } + public Func ShouldMapMethod { get; } + public Func ShouldUseConstructor { get; } + public IEnumerable> AllPropertyMapActions { get; } + public IEnumerable> AllTypeMapActions { get; } + public HashSet GlobalIgnores { get; } + public MemberConfiguration MemberConfiguration { get; } + public IEnumerable SourceExtensionMethods { get; } + public HashSet Prefixes { get; } + public HashSet Postfixes { get; } + public IReadOnlyCollection ValueTransformers { get; } + public TypeDetails CreateTypeDetails(Type type) + { + if (_typeDetails == null) { - _typeDetails = null; - _typeMapConfigs = null; - _runtimeTypeDetails = new(TypeDetailsFactory, 2 * _openTypeMapConfigs.Count); + return _runtimeTypeDetails.GetOrAdd(type); } - public bool AllowNullCollections { get; } - public bool AllowNullDestinationValues { get; } - public bool ConstructorMappingEnabled { get; } - public bool EnableNullPropagationForQueryMapping { get; } - public bool MethodMappingEnabled { get; } - public bool FieldMappingEnabled { get; } - public string Name { get; } - public Func ShouldMapField { get; } - public Func ShouldMapProperty { get; } - public Func ShouldMapMethod { get; } - public Func ShouldUseConstructor { get; } - public IEnumerable> AllPropertyMapActions { get; } - public IEnumerable> AllTypeMapActions { get; } - public HashSet GlobalIgnores { get; } - public MemberConfiguration MemberConfiguration { get; } - public IEnumerable SourceExtensionMethods { get; } - public HashSet Prefixes { get; } - public HashSet Postfixes { get; } - public IReadOnlyCollection ValueTransformers { get; } - public TypeDetails CreateTypeDetails(Type type) + if (_typeDetails.TryGetValue(type, out var typeDetails)) { - if (_typeDetails == null) - { - return _runtimeTypeDetails.GetOrAdd(type); - } - if (_typeDetails.TryGetValue(type, out var typeDetails)) - { - return typeDetails; - } - typeDetails = TypeDetailsFactory(type); - _typeDetails.Add(type, typeDetails); return typeDetails; - } - private TypeDetails TypeDetailsFactory(Type type) => new(type, this); - public void Register(IGlobalConfiguration configuration) + } + typeDetails = TypeDetailsFactory(type); + _typeDetails.Add(type, typeDetails); + return typeDetails; + } + private TypeDetails TypeDetailsFactory(Type type) => new(type, this); + public void Register(IGlobalConfiguration configuration) + { + foreach (var config in _typeMapConfigs) { - foreach (var config in _typeMapConfigs) - { - if (config.DestinationTypeOverride == null) + if (config.DestinationTypeOverride == null) + { + BuildTypeMap(configuration, config); + if (config.ReverseTypeMap != null) { - BuildTypeMap(configuration, config); - if (config.ReverseTypeMap != null) - { - BuildTypeMap(configuration, config.ReverseTypeMap); - } + BuildTypeMap(configuration, config.ReverseTypeMap); } } } - private void BuildTypeMap(IGlobalConfiguration configuration, TypeMapConfiguration config) - { - var sourceMembers = configuration.SourceMembers; - var typeMap = new TypeMap(config.SourceType, config.DestinationType, this, config, sourceMembers); - config.Configure(typeMap, sourceMembers); - configuration.RegisterTypeMap(typeMap); - } - public void Configure(IGlobalConfiguration configuration) + } + private void BuildTypeMap(IGlobalConfiguration configuration, TypeMapConfiguration config) + { + var sourceMembers = configuration.SourceMembers; + var typeMap = new TypeMap(config.SourceType, config.DestinationType, this, config, sourceMembers); + config.Configure(typeMap, sourceMembers); + configuration.RegisterTypeMap(typeMap); + } + public void Configure(IGlobalConfiguration configuration) + { + foreach (var typeMapConfiguration in _typeMapConfigs) { - foreach (var typeMapConfiguration in _typeMapConfigs) + if (typeMapConfiguration.DestinationTypeOverride == null) { - if (typeMapConfiguration.DestinationTypeOverride == null) + Configure(typeMapConfiguration, configuration); + if (typeMapConfiguration.ReverseTypeMap != null) { - Configure(typeMapConfiguration, configuration); - if (typeMapConfiguration.ReverseTypeMap != null) - { - Configure(typeMapConfiguration.ReverseTypeMap, configuration); - } - } - else - { - configuration.RegisterAsMap(typeMapConfiguration); + Configure(typeMapConfiguration.ReverseTypeMap, configuration); } } - } - private void Configure(TypeMapConfiguration typeMapConfiguration, IGlobalConfiguration configuration) - { - var typeMap = typeMapConfiguration.TypeMap; - if (typeMap.IncludeAllDerivedTypes) + else { - IncludeAllDerived(configuration, typeMap); + configuration.RegisterAsMap(typeMapConfiguration); } - Configure(typeMap, configuration); - } - private static void IncludeAllDerived(IGlobalConfiguration configuration, TypeMap typeMap) + } + } + private void Configure(TypeMapConfiguration typeMapConfiguration, IGlobalConfiguration configuration) + { + var typeMap = typeMapConfiguration.TypeMap; + if (typeMap.IncludeAllDerivedTypes) { - foreach (var derivedMap in configuration.GetAllTypeMaps().Where(tm => - typeMap != tm && - typeMap.SourceType.IsAssignableFrom(tm.SourceType) && - typeMap.DestinationType.IsAssignableFrom(tm.DestinationType))) - { - typeMap.IncludeDerivedTypes(derivedMap.Types); - } + IncludeAllDerived(configuration, typeMap); + } + Configure(typeMap, configuration); + } + private static void IncludeAllDerived(IGlobalConfiguration configuration, TypeMap typeMap) + { + foreach (var derivedMap in configuration.GetAllTypeMaps().Where(tm => + typeMap != tm && + typeMap.SourceType.IsAssignableFrom(tm.SourceType) && + typeMap.DestinationType.IsAssignableFrom(tm.DestinationType))) + { + typeMap.IncludeDerivedTypes(derivedMap.Types); } - private void Configure(TypeMap typeMap, IGlobalConfiguration configuration) + } + private void Configure(TypeMap typeMap, IGlobalConfiguration configuration) + { + foreach (var action in AllTypeMapActions) { - foreach (var action in AllTypeMapActions) - { - var expression = new MappingExpression(typeMap.Types, typeMap.ConfiguredMemberList); - action(typeMap, expression); - expression.Configure(typeMap, configuration.SourceMembers); - } - foreach (var action in AllPropertyMapActions) - { - foreach (var propertyMap in typeMap.PropertyMaps) - { - var memberExpression = new MappingExpression.MemberConfigurationExpression(propertyMap.DestinationMember, typeMap.SourceType); - action(propertyMap, memberExpression); - memberExpression.Configure(typeMap); - } - } - ApplyBaseMaps(typeMap, typeMap, configuration); - ApplyDerivedMaps(typeMap, typeMap, configuration); - ApplyMemberMaps(typeMap, configuration); + var expression = new MappingExpression(typeMap.Types, typeMap.ConfiguredMemberList); + action(typeMap, expression); + expression.Configure(typeMap, configuration.SourceMembers); } - public TypeMap CreateClosedGenericTypeMap(TypeMapConfiguration openMapConfig, TypePair closedTypes, IGlobalConfiguration configuration) + foreach (var action in AllPropertyMapActions) { - TypeMap closedMap; - lock (configuration) - { - closedMap = new TypeMap(closedTypes.SourceType, closedTypes.DestinationType, this, openMapConfig); + foreach (var propertyMap in typeMap.PropertyMaps) + { + var memberExpression = new MappingExpression.MemberConfigurationExpression(propertyMap.DestinationMember, typeMap.SourceType); + action(propertyMap, memberExpression); + memberExpression.Configure(typeMap); } - openMapConfig.Configure(closedMap, configuration.SourceMembers); - Configure(closedMap, configuration); - closedMap.CloseGenerics(openMapConfig, closedTypes); - return closedMap; } - public TypeMapConfiguration GetGenericMap(TypePair genericPair) => _openTypeMapConfigs.GetValueOrDefault(genericPair); - private void ApplyBaseMaps(TypeMap derivedMap, TypeMap currentMap, IGlobalConfiguration configuration) + ApplyBaseMaps(typeMap, typeMap, configuration); + ApplyDerivedMaps(typeMap, typeMap, configuration); + ApplyMemberMaps(typeMap, configuration); + } + public TypeMap CreateClosedGenericTypeMap(TypeMapConfiguration openMapConfig, TypePair closedTypes, IGlobalConfiguration configuration) + { + TypeMap closedMap; + lock (configuration) + { + closedMap = new TypeMap(closedTypes.SourceType, closedTypes.DestinationType, this, openMapConfig); + } + openMapConfig.Configure(closedMap, configuration.SourceMembers); + Configure(closedMap, configuration); + closedMap.CloseGenerics(openMapConfig, closedTypes); + return closedMap; + } + public TypeMapConfiguration GetGenericMap(TypePair genericPair) => _openTypeMapConfigs.GetValueOrDefault(genericPair); + private void ApplyBaseMaps(TypeMap derivedMap, TypeMap currentMap, IGlobalConfiguration configuration) + { + foreach (var baseMap in configuration.GetIncludedTypeMaps(currentMap.IncludedBaseTypes)) { - foreach (var baseMap in configuration.GetIncludedTypeMaps(currentMap.IncludedBaseTypes)) - { - baseMap.IncludeDerivedTypes(currentMap.Types); - derivedMap.AddInheritedMap(baseMap); - ApplyBaseMaps(derivedMap, baseMap, configuration); - } + baseMap.IncludeDerivedTypes(currentMap.Types); + derivedMap.AddInheritedMap(baseMap); + ApplyBaseMaps(derivedMap, baseMap, configuration); } - private void ApplyMemberMaps(TypeMap currentMap, IGlobalConfiguration configuration) + } + private void ApplyMemberMaps(TypeMap currentMap, IGlobalConfiguration configuration) + { + if (!currentMap.HasIncludedMembers) { - if (!currentMap.HasIncludedMembers) - { - return; - } - foreach (var includedMemberExpression in currentMap.GetAllIncludedMembers()) + return; + } + foreach (var includedMemberExpression in currentMap.GetAllIncludedMembers()) + { + var includedMap = configuration.GetIncludedTypeMap(includedMemberExpression.Body.Type, currentMap.DestinationType); + var includedMember = new IncludedMember(includedMap, includedMemberExpression); + if (currentMap.AddMemberMap(includedMember)) { - var includedMap = configuration.GetIncludedTypeMap(includedMemberExpression.Body.Type, currentMap.DestinationType); - var includedMember = new IncludedMember(includedMap, includedMemberExpression); - if (currentMap.AddMemberMap(includedMember)) + ApplyMemberMaps(includedMap, configuration); + foreach (var inheritedIncludedMember in includedMap.IncludedMembersTypeMaps) { - ApplyMemberMaps(includedMap, configuration); - foreach (var inheritedIncludedMember in includedMap.IncludedMembersTypeMaps) - { - currentMap.AddMemberMap(includedMember.Chain(inheritedIncludedMember)); - } + currentMap.AddMemberMap(includedMember.Chain(inheritedIncludedMember)); } - } + } } - private void ApplyDerivedMaps(TypeMap baseMap, TypeMap typeMap, IGlobalConfiguration configuration) + } + private void ApplyDerivedMaps(TypeMap baseMap, TypeMap typeMap, IGlobalConfiguration configuration) + { + foreach (var derivedMap in configuration.GetIncludedTypeMaps(typeMap)) { - foreach (var derivedMap in configuration.GetIncludedTypeMaps(typeMap)) - { - derivedMap.IncludeBaseTypes(typeMap.Types); - derivedMap.AddInheritedMap(baseMap); - ApplyDerivedMaps(baseMap, derivedMap, configuration); - } + derivedMap.IncludeBaseTypes(typeMap.Types); + derivedMap.AddInheritedMap(baseMap); + ApplyDerivedMaps(baseMap, derivedMap, configuration); } - public bool MapDestinationPropertyToSource(TypeDetails sourceTypeDetails, Type destType, Type destMemberType, string destMemberName, List members, bool reverseNamingConventions) => - MemberConfiguration.IsMatch(this, sourceTypeDetails, destType, destMemberType, destMemberName, members, reverseNamingConventions); - public bool AllowsNullDestinationValuesFor(MemberMap memberMap = null) => memberMap?.AllowNull ?? AllowNullDestinationValues; - public bool AllowsNullCollectionsFor(MemberMap memberMap = null) => memberMap?.AllowNull ?? AllowNullCollections; + } + public bool MapDestinationPropertyToSource(TypeDetails sourceTypeDetails, Type destType, Type destMemberType, string destMemberName, List members, bool reverseNamingConventions) => + MemberConfiguration.IsMatch(this, sourceTypeDetails, destType, destMemberType, destMemberName, members, reverseNamingConventions); + public bool AllowsNullDestinationValuesFor(MemberMap memberMap = null) => memberMap?.AllowNull ?? AllowNullDestinationValues; + public bool AllowsNullCollectionsFor(MemberMap memberMap = null) => memberMap?.AllowNull ?? AllowNullCollections; +} +[EditorBrowsable(EditorBrowsableState.Never)] +[DebuggerDisplay("{MemberExpression}, {TypeMap}")] +public class IncludedMember : IEquatable +{ + public IncludedMember(TypeMap typeMap, LambdaExpression memberExpression) : this(typeMap, memberExpression, + Variable(memberExpression.Body.Type, string.Join("", memberExpression.GetMembersChain().Select(m => m.Name))), memberExpression) + { } - [EditorBrowsable(EditorBrowsableState.Never)] - [DebuggerDisplay("{MemberExpression}, {TypeMap}")] - public class IncludedMember : IEquatable + private IncludedMember(TypeMap typeMap, LambdaExpression memberExpression, ParameterExpression variable, LambdaExpression projectToCustomSource) { - public IncludedMember(TypeMap typeMap, LambdaExpression memberExpression) : this(typeMap, memberExpression, - Variable(memberExpression.Body.Type, string.Join("", memberExpression.GetMembersChain().Select(m => m.Name))), memberExpression) - { - } - private IncludedMember(TypeMap typeMap, LambdaExpression memberExpression, ParameterExpression variable, LambdaExpression projectToCustomSource) + TypeMap = typeMap; + MemberExpression = memberExpression; + Variable = variable; + ProjectToCustomSource = projectToCustomSource; + } + public IncludedMember Chain(IncludedMember other) + { + if (other == null) { - TypeMap = typeMap; - MemberExpression = memberExpression; - Variable = variable; - ProjectToCustomSource = projectToCustomSource; + return this; } - public IncludedMember Chain(IncludedMember other) - { - if (other == null) - { - return this; - } - return new(other.TypeMap, Chain(other.MemberExpression), other.Variable, Chain(MemberExpression, other.MemberExpression)); - } - public static LambdaExpression Chain(LambdaExpression customSource, LambdaExpression lambda) => - Lambda(lambda.ReplaceParameters(customSource.Body), customSource.Parameters); - public TypeMap TypeMap { get; } - public LambdaExpression MemberExpression { get; } - public ParameterExpression Variable { get; } - public LambdaExpression ProjectToCustomSource { get; } - public LambdaExpression Chain(LambdaExpression lambda) => Lambda(lambda.ReplaceParameters(Variable), lambda.Parameters); - public bool Equals(IncludedMember other) => TypeMap == other?.TypeMap; - public override int GetHashCode() => TypeMap.GetHashCode(); - } + return new(other.TypeMap, Chain(other.MemberExpression), other.Variable, Chain(MemberExpression, other.MemberExpression)); + } + public static LambdaExpression Chain(LambdaExpression customSource, LambdaExpression lambda) => + Lambda(lambda.ReplaceParameters(customSource.Body), customSource.Parameters); + public TypeMap TypeMap { get; } + public LambdaExpression MemberExpression { get; } + public ParameterExpression Variable { get; } + public LambdaExpression ProjectToCustomSource { get; } + public LambdaExpression Chain(LambdaExpression lambda) => Lambda(lambda.ReplaceParameters(Variable), lambda.Parameters); + public bool Equals(IncludedMember other) => TypeMap == other?.TypeMap; + public override int GetHashCode() => TypeMap.GetHashCode(); } \ No newline at end of file diff --git a/src/AutoMapper/PropertyMap.cs b/src/AutoMapper/PropertyMap.cs index 5f417ec923..e65e5ad9d3 100644 --- a/src/AutoMapper/PropertyMap.cs +++ b/src/AutoMapper/PropertyMap.cs @@ -5,101 +5,100 @@ using System.Linq.Expressions; using System.Reflection; using AutoMapper.Internal; -namespace AutoMapper +namespace AutoMapper; + +[DebuggerDisplay("{DestinationMember.Name}")] +[EditorBrowsable(EditorBrowsableState.Never)] +public class PropertyMap : MemberMap { - [DebuggerDisplay("{DestinationMember.Name}")] - [EditorBrowsable(EditorBrowsableState.Never)] - public class PropertyMap : MemberMap + private MemberMapDetails _details; + private Type _sourceType; + public PropertyMap(MemberInfo destinationMember, Type destinationMemberType, TypeMap typeMap) : base(typeMap) { - private MemberMapDetails _details; - private Type _sourceType; - public PropertyMap(MemberInfo destinationMember, Type destinationMemberType, TypeMap typeMap) : base(typeMap) + DestinationMember = destinationMember; + DestinationType = destinationMemberType; + } + public PropertyMap(PropertyMap inheritedMappedProperty, TypeMap typeMap) + : this(inheritedMappedProperty.DestinationMember, inheritedMappedProperty.DestinationType, typeMap) => ApplyInheritedPropertyMap(inheritedMappedProperty); + public PropertyMap(PropertyMap includedMemberMap, TypeMap typeMap, IncludedMember includedMember) + : this(includedMemberMap, typeMap) => Details.IncludedMember = includedMember.Chain(includedMemberMap.IncludedMember); + private MemberMapDetails Details => _details ??= new(); + public MemberInfo DestinationMember { get; } + public override string DestinationName => DestinationMember?.Name; + public override Type DestinationType { get; protected set; } + public override MemberInfo[] SourceMembers { get; set; } = Array.Empty(); + public override bool CanBeSet => ReflectionHelper.CanBeSet(DestinationMember); + public override bool Ignored { get; set; } + public override Type SourceType => _sourceType ??= GetSourceType(); + public void ApplyInheritedPropertyMap(PropertyMap inheritedMappedProperty) + { + if (Ignored) { - DestinationMember = destinationMember; - DestinationType = destinationMemberType; + return; } - public PropertyMap(PropertyMap inheritedMappedProperty, TypeMap typeMap) - : this(inheritedMappedProperty.DestinationMember, inheritedMappedProperty.DestinationType, typeMap) => ApplyInheritedPropertyMap(inheritedMappedProperty); - public PropertyMap(PropertyMap includedMemberMap, TypeMap typeMap, IncludedMember includedMember) - : this(includedMemberMap, typeMap) => Details.IncludedMember = includedMember.Chain(includedMemberMap.IncludedMember); - private MemberMapDetails Details => _details ??= new(); - public MemberInfo DestinationMember { get; } - public override string DestinationName => DestinationMember?.Name; - public override Type DestinationType { get; protected set; } - public override MemberInfo[] SourceMembers { get; set; } = Array.Empty(); - public override bool CanBeSet => ReflectionHelper.CanBeSet(DestinationMember); - public override bool Ignored { get; set; } - public override Type SourceType => _sourceType ??= GetSourceType(); - public void ApplyInheritedPropertyMap(PropertyMap inheritedMappedProperty) + if (!IsResolveConfigured) { - if (Ignored) + if (inheritedMappedProperty.Ignored) { + Ignored = true; return; } - if (!IsResolveConfigured) + if (inheritedMappedProperty.IsResolveConfigured) { - if (inheritedMappedProperty.Ignored) - { - Ignored = true; - return; - } - if (inheritedMappedProperty.IsResolveConfigured) - { - _sourceType = inheritedMappedProperty._sourceType; - Resolver = inheritedMappedProperty.Resolver; - } - else if (Resolver == null) - { - _sourceType = inheritedMappedProperty._sourceType; - MapByConvention(inheritedMappedProperty.SourceMembers); - } + _sourceType = inheritedMappedProperty._sourceType; + Resolver = inheritedMappedProperty.Resolver; } - if (inheritedMappedProperty._details != null) + else if (Resolver == null) { - Details.ApplyInheritedPropertyMap(inheritedMappedProperty._details); + _sourceType = inheritedMappedProperty._sourceType; + MapByConvention(inheritedMappedProperty.SourceMembers); } } - public override IncludedMember IncludedMember => _details?.IncludedMember; - public override bool? AllowNull { get => _details?.AllowNull; set => Details.AllowNull = value; } - public int? MappingOrder { get => _details?.MappingOrder; set => Details.MappingOrder = value; } - public bool? ExplicitExpansion { get => _details?.ExplicitExpansion; set => Details.ExplicitExpansion = value; } - public override bool? UseDestinationValue { get => _details?.UseDestinationValue; set => Details.UseDestinationValue = value; } - public override object NullSubstitute { get => _details?.NullSubstitute; set => Details.NullSubstitute = value; } - public override LambdaExpression PreCondition { get => _details?.PreCondition; set => Details.PreCondition = value; } - public override LambdaExpression Condition { get => _details?.Condition; set => Details.Condition = value; } - public void AddValueTransformation(ValueTransformerConfiguration config) => Details.AddValueTransformation(config); - public override IReadOnlyCollection ValueTransformers => (_details?.ValueTransformers).NullCheck(); - class MemberMapDetails + if (inheritedMappedProperty._details != null) { - public List ValueTransformers { get; private set; } - public bool? AllowNull; - public int? MappingOrder; - public bool? ExplicitExpansion; - public bool? UseDestinationValue; - public object NullSubstitute; - public LambdaExpression PreCondition; - public LambdaExpression Condition; - public IncludedMember IncludedMember; - public void ApplyInheritedPropertyMap(MemberMapDetails inheritedMappedProperty) - { - AllowNull ??= inheritedMappedProperty.AllowNull; - Condition ??= inheritedMappedProperty.Condition; - PreCondition ??= inheritedMappedProperty.PreCondition; - NullSubstitute ??= inheritedMappedProperty.NullSubstitute; - MappingOrder ??= inheritedMappedProperty.MappingOrder; - UseDestinationValue ??= inheritedMappedProperty.UseDestinationValue; - ExplicitExpansion ??= inheritedMappedProperty.ExplicitExpansion; - if (inheritedMappedProperty.ValueTransformers != null) - { - ValueTransformers ??= new(); - ValueTransformers.InsertRange(0, inheritedMappedProperty.ValueTransformers); - } - } - public void AddValueTransformation(ValueTransformerConfiguration valueTransformerConfiguration) + Details.ApplyInheritedPropertyMap(inheritedMappedProperty._details); + } + } + public override IncludedMember IncludedMember => _details?.IncludedMember; + public override bool? AllowNull { get => _details?.AllowNull; set => Details.AllowNull = value; } + public int? MappingOrder { get => _details?.MappingOrder; set => Details.MappingOrder = value; } + public bool? ExplicitExpansion { get => _details?.ExplicitExpansion; set => Details.ExplicitExpansion = value; } + public override bool? UseDestinationValue { get => _details?.UseDestinationValue; set => Details.UseDestinationValue = value; } + public override object NullSubstitute { get => _details?.NullSubstitute; set => Details.NullSubstitute = value; } + public override LambdaExpression PreCondition { get => _details?.PreCondition; set => Details.PreCondition = value; } + public override LambdaExpression Condition { get => _details?.Condition; set => Details.Condition = value; } + public void AddValueTransformation(ValueTransformerConfiguration config) => Details.AddValueTransformation(config); + public override IReadOnlyCollection ValueTransformers => (_details?.ValueTransformers).NullCheck(); + class MemberMapDetails + { + public List ValueTransformers { get; private set; } + public bool? AllowNull; + public int? MappingOrder; + public bool? ExplicitExpansion; + public bool? UseDestinationValue; + public object NullSubstitute; + public LambdaExpression PreCondition; + public LambdaExpression Condition; + public IncludedMember IncludedMember; + public void ApplyInheritedPropertyMap(MemberMapDetails inheritedMappedProperty) + { + AllowNull ??= inheritedMappedProperty.AllowNull; + Condition ??= inheritedMappedProperty.Condition; + PreCondition ??= inheritedMappedProperty.PreCondition; + NullSubstitute ??= inheritedMappedProperty.NullSubstitute; + MappingOrder ??= inheritedMappedProperty.MappingOrder; + UseDestinationValue ??= inheritedMappedProperty.UseDestinationValue; + ExplicitExpansion ??= inheritedMappedProperty.ExplicitExpansion; + if (inheritedMappedProperty.ValueTransformers != null) { ValueTransformers ??= new(); - ValueTransformers.Add(valueTransformerConfiguration); + ValueTransformers.InsertRange(0, inheritedMappedProperty.ValueTransformers); } } + public void AddValueTransformation(ValueTransformerConfiguration valueTransformerConfiguration) + { + ValueTransformers ??= new(); + ValueTransformers.Add(valueTransformerConfiguration); + } } } \ No newline at end of file diff --git a/src/AutoMapper/QueryableExtensions/Extensions.cs b/src/AutoMapper/QueryableExtensions/Extensions.cs index 04aea3022d..94488e7aee 100644 --- a/src/AutoMapper/QueryableExtensions/Extensions.cs +++ b/src/AutoMapper/QueryableExtensions/Extensions.cs @@ -5,93 +5,92 @@ using System.Reflection; using AutoMapper.Execution; using AutoMapper.Internal; -namespace AutoMapper.QueryableExtensions +namespace AutoMapper.QueryableExtensions; + +using MemberPaths = IEnumerable; +using ParameterBag = IDictionary; +/// +/// Queryable extensions for AutoMapper +/// +public static class Extensions { - using MemberPaths = IEnumerable; - using ParameterBag = IDictionary; + static readonly MethodInfo SelectMethod = typeof(Queryable).StaticGenericMethod("Select", parametersCount: 2); + static IQueryable Select(IQueryable source, LambdaExpression lambda) => source.Provider.CreateQuery( + Expression.Call(SelectMethod.MakeGenericMethod(source.ElementType, lambda.ReturnType), source.Expression, Expression.Quote(lambda))); /// - /// Queryable extensions for AutoMapper + /// Extension method to project from a queryable using the provided mapping engine /// - public static class Extensions + /// Projections are only calculated once and cached + /// Destination type + /// Queryable source + /// Mapper configuration + /// Optional parameter object for parameterized mapping expressions + /// Explicit members to expand + /// Expression to project into + public static IQueryable ProjectTo(this IQueryable source, IConfigurationProvider configuration, object parameters, params Expression>[] membersToExpand) => + source.ToCore(configuration, parameters, membersToExpand.Select(MemberVisitor.GetMemberPath)); + /// + /// Extension method to project from a queryable using the provided mapping engine + /// + /// Projections are only calculated once and cached + /// Destination type + /// Queryable source + /// Mapper configuration + /// Explicit members to expand + /// Expression to project into + public static IQueryable ProjectTo(this IQueryable source, IConfigurationProvider configuration, + params Expression>[] membersToExpand) => + source.ProjectTo(configuration, null, membersToExpand); + /// + /// Projects the source type to the destination type given the mapping configuration + /// + /// Destination type to map to + /// Queryable source + /// Mapper configuration + /// Optional parameter object for parameterized mapping expressions + /// Explicit members to expand + /// Queryable result, use queryable extension methods to project and execute result + public static IQueryable ProjectTo(this IQueryable source, IConfigurationProvider configuration, ParameterBag parameters, params string[] membersToExpand) => + source.ToCore(configuration, parameters, membersToExpand.Select(memberName => ReflectionHelper.GetMemberPath(typeof(TDestination), memberName))); + /// + /// Extension method to project from a queryable using the provided mapping engine + /// + /// Projections are only calculated once and cached + /// Queryable source + /// Destination type + /// Mapper configuration + /// Expression to project into + public static IQueryable ProjectTo(this IQueryable source, Type destinationType, IConfigurationProvider configuration) => + source.ProjectTo(destinationType, configuration, null); + /// + /// Projects the source type to the destination type given the mapping configuration + /// + /// Queryable source + /// Destination type to map to + /// Mapper configuration + /// Optional parameter object for parameterized mapping expressions + /// Explicit members to expand + /// Queryable result, use queryable extension methods to project and execute result + public static IQueryable ProjectTo(this IQueryable source, Type destinationType, IConfigurationProvider configuration, ParameterBag parameters, params string[] membersToExpand) => + source.ToCore(destinationType, configuration, parameters, membersToExpand.Select(memberName => ReflectionHelper.GetMemberPath(destinationType, memberName))); + static IQueryable ToCore(this IQueryable source, IConfigurationProvider configuration, object parameters, MemberPaths memberPathsToExpand) => + (IQueryable)source.ToCore(typeof(TResult), configuration, parameters, memberPathsToExpand); + static IQueryable ToCore(this IQueryable source, Type destinationType, IConfigurationProvider configuration, object parameters, MemberPaths memberPathsToExpand) => + configuration.Internal().ProjectionBuilder.GetProjection(source.ElementType, destinationType, parameters, memberPathsToExpand.Select(m => new MemberPath(m)).ToArray()) + .Chain(source, Select); +} +public class MemberVisitor : ExpressionVisitor +{ + private readonly List _members = new(); + public static MemberInfo[] GetMemberPath(Expression expression) { - static readonly MethodInfo SelectMethod = typeof(Queryable).StaticGenericMethod("Select", parametersCount: 2); - static IQueryable Select(IQueryable source, LambdaExpression lambda) => source.Provider.CreateQuery( - Expression.Call(SelectMethod.MakeGenericMethod(source.ElementType, lambda.ReturnType), source.Expression, Expression.Quote(lambda))); - /// - /// Extension method to project from a queryable using the provided mapping engine - /// - /// Projections are only calculated once and cached - /// Destination type - /// Queryable source - /// Mapper configuration - /// Optional parameter object for parameterized mapping expressions - /// Explicit members to expand - /// Expression to project into - public static IQueryable ProjectTo(this IQueryable source, IConfigurationProvider configuration, object parameters, params Expression>[] membersToExpand) => - source.ToCore(configuration, parameters, membersToExpand.Select(MemberVisitor.GetMemberPath)); - /// - /// Extension method to project from a queryable using the provided mapping engine - /// - /// Projections are only calculated once and cached - /// Destination type - /// Queryable source - /// Mapper configuration - /// Explicit members to expand - /// Expression to project into - public static IQueryable ProjectTo(this IQueryable source, IConfigurationProvider configuration, - params Expression>[] membersToExpand) => - source.ProjectTo(configuration, null, membersToExpand); - /// - /// Projects the source type to the destination type given the mapping configuration - /// - /// Destination type to map to - /// Queryable source - /// Mapper configuration - /// Optional parameter object for parameterized mapping expressions - /// Explicit members to expand - /// Queryable result, use queryable extension methods to project and execute result - public static IQueryable ProjectTo(this IQueryable source, IConfigurationProvider configuration, ParameterBag parameters, params string[] membersToExpand) => - source.ToCore(configuration, parameters, membersToExpand.Select(memberName => ReflectionHelper.GetMemberPath(typeof(TDestination), memberName))); - /// - /// Extension method to project from a queryable using the provided mapping engine - /// - /// Projections are only calculated once and cached - /// Queryable source - /// Destination type - /// Mapper configuration - /// Expression to project into - public static IQueryable ProjectTo(this IQueryable source, Type destinationType, IConfigurationProvider configuration) => - source.ProjectTo(destinationType, configuration, null); - /// - /// Projects the source type to the destination type given the mapping configuration - /// - /// Queryable source - /// Destination type to map to - /// Mapper configuration - /// Optional parameter object for parameterized mapping expressions - /// Explicit members to expand - /// Queryable result, use queryable extension methods to project and execute result - public static IQueryable ProjectTo(this IQueryable source, Type destinationType, IConfigurationProvider configuration, ParameterBag parameters, params string[] membersToExpand) => - source.ToCore(destinationType, configuration, parameters, membersToExpand.Select(memberName => ReflectionHelper.GetMemberPath(destinationType, memberName))); - static IQueryable ToCore(this IQueryable source, IConfigurationProvider configuration, object parameters, MemberPaths memberPathsToExpand) => - (IQueryable)source.ToCore(typeof(TResult), configuration, parameters, memberPathsToExpand); - static IQueryable ToCore(this IQueryable source, Type destinationType, IConfigurationProvider configuration, object parameters, MemberPaths memberPathsToExpand) => - configuration.Internal().ProjectionBuilder.GetProjection(source.ElementType, destinationType, parameters, memberPathsToExpand.Select(m => new MemberPath(m)).ToArray()) - .Chain(source, Select); + var memberVisitor = new MemberVisitor(); + memberVisitor.Visit(expression); + return memberVisitor._members.ToArray(); } - public class MemberVisitor : ExpressionVisitor + protected override Expression VisitMember(MemberExpression node) { - private readonly List _members = new(); - public static MemberInfo[] GetMemberPath(Expression expression) - { - var memberVisitor = new MemberVisitor(); - memberVisitor.Visit(expression); - return memberVisitor._members.ToArray(); - } - protected override Expression VisitMember(MemberExpression node) - { - _members.AddRange(node.GetMemberExpressions().Select(e => e.Member)); - return node; - } + _members.AddRange(node.GetMemberExpressions().Select(e => e.Member)); + return node; } } \ No newline at end of file diff --git a/src/AutoMapper/QueryableExtensions/NullsafeQueryRewriter.cs b/src/AutoMapper/QueryableExtensions/NullsafeQueryRewriter.cs index 54ca7f125e..f86d314c40 100644 --- a/src/AutoMapper/QueryableExtensions/NullsafeQueryRewriter.cs +++ b/src/AutoMapper/QueryableExtensions/NullsafeQueryRewriter.cs @@ -28,139 +28,138 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. using System.Reflection; using System.Runtime.CompilerServices; -namespace AutoMapper.QueryableExtensions +namespace AutoMapper.QueryableExtensions; + +/// +/// Expression visitor for making member access null-safe. +/// +/// +/// NullSafeQueryRewriter is copied from the NeinLinq project, licensed under the MIT license. +/// Copyright (c) 2014-2018 Axel Heer. +/// See https://github.com/axelheer/nein-linq/blob/master/src/NeinLinq/NullsafeQueryRewriter.cs +/// +internal class NullsafeQueryRewriter : ExpressionVisitor { - /// - /// Expression visitor for making member access null-safe. - /// - /// - /// NullSafeQueryRewriter is copied from the NeinLinq project, licensed under the MIT license. - /// Copyright (c) 2014-2018 Axel Heer. - /// See https://github.com/axelheer/nein-linq/blob/master/src/NeinLinq/NullsafeQueryRewriter.cs - /// - internal class NullsafeQueryRewriter : ExpressionVisitor + static readonly LockingConcurrentDictionary Cache = new(Fallback); + + public static Expression NullCheck(Expression expression) => new NullsafeQueryRewriter().Visit(expression); + + /// + protected override Expression VisitMember(MemberExpression node) { - static readonly LockingConcurrentDictionary Cache = new(Fallback); + if (node == null) + throw new ArgumentNullException(nameof(node)); - public static Expression NullCheck(Expression expression) => new NullsafeQueryRewriter().Visit(expression); + var target = Visit(node.Expression); - /// - protected override Expression VisitMember(MemberExpression node) + if (!IsSafe(target)) { - if (node == null) - throw new ArgumentNullException(nameof(node)); + // insert null-check before accessing property or field + return BeSafe(target, node, node.Update); + } - var target = Visit(node.Expression); + return node.Update(target); + } - if (!IsSafe(target)) - { - // insert null-check before accessing property or field - return BeSafe(target, node, node.Update); - } + /// + protected override Expression VisitMethodCall(MethodCallExpression node) + { + if (node == null) + throw new ArgumentNullException(nameof(node)); - return node.Update(target); - } + var target = Visit(node.Object); - /// - protected override Expression VisitMethodCall(MethodCallExpression node) + if (!IsSafe(target)) { - if (node == null) - throw new ArgumentNullException(nameof(node)); + // insert null-check before invoking instance method + return BeSafe(target, node, fallback => node.Update(fallback, node.Arguments)); + } - var target = Visit(node.Object); + var arguments = Visit(node.Arguments); - if (!IsSafe(target)) + if (IsExtensionMethod(node.Method) && !IsSafe(arguments[0])) + { + // insert null-check before invoking extension method + return BeSafe(arguments[0], node.Update(null, arguments), fallback => { - // insert null-check before invoking instance method - return BeSafe(target, node, fallback => node.Update(fallback, node.Arguments)); - } - - var arguments = Visit(node.Arguments); + var args = new Expression[arguments.Count]; + arguments.CopyTo(args, 0); + args[0] = fallback; - if (IsExtensionMethod(node.Method) && !IsSafe(arguments[0])) - { - // insert null-check before invoking extension method - return BeSafe(arguments[0], node.Update(null, arguments), fallback => - { - var args = new Expression[arguments.Count]; - arguments.CopyTo(args, 0); - args[0] = fallback; - - return node.Update(null, args); - }); - } - - return node.Update(target, arguments); + return node.Update(null, args); + }); } - static Expression BeSafe(Expression target, Expression expression, Func update) + return node.Update(target, arguments); + } + + static Expression BeSafe(Expression target, Expression expression, Func update) + { + var fallback = Cache.GetOrAdd(target.Type); + + if (fallback != null) { - var fallback = Cache.GetOrAdd(target.Type); + // coalesce instead, a bit intrusive but fast... + return update(Expression.Coalesce(target, fallback)); + } - if (fallback != null) - { - // coalesce instead, a bit intrusive but fast... - return update(Expression.Coalesce(target, fallback)); - } + // target can be null, which is why we are actually here... + var targetFallback = Expression.Constant(null, target.Type); - // target can be null, which is why we are actually here... - var targetFallback = Expression.Constant(null, target.Type); + // expression can be default or null, which is basically the same... + var expressionFallback = !IsNullableOrReferenceType(expression.Type) + ? (Expression)Expression.Default(expression.Type) : Expression.Constant(null, expression.Type); - // expression can be default or null, which is basically the same... - var expressionFallback = !IsNullableOrReferenceType(expression.Type) - ? (Expression)Expression.Default(expression.Type) : Expression.Constant(null, expression.Type); + return Expression.Condition(Expression.Equal(target, targetFallback), expressionFallback, expression); + } - return Expression.Condition(Expression.Equal(target, targetFallback), expressionFallback, expression); - } + static bool IsSafe(Expression expression) + { + // in method call results and constant values we trust to avoid too much conditions... + return expression == null + || expression.NodeType == ExpressionType.Call + || expression.NodeType == ExpressionType.Constant + || !IsNullableOrReferenceType(expression.Type); + } - static bool IsSafe(Expression expression) + static Expression Fallback(Type type) + { + // default values for generic collections + if (type.IsConstructedGenericType && type.GenericTypeArguments.Length == 1) { - // in method call results and constant values we trust to avoid too much conditions... - return expression == null - || expression.NodeType == ExpressionType.Call - || expression.NodeType == ExpressionType.Constant - || !IsNullableOrReferenceType(expression.Type); + return CollectionFallback(typeof(List<>), type) + ?? CollectionFallback(typeof(HashSet<>), type); } - static Expression Fallback(Type type) + // default value for arrays + if (type.IsArray) { - // default values for generic collections - if (type.IsConstructedGenericType && type.GenericTypeArguments.Length == 1) - { - return CollectionFallback(typeof(List<>), type) - ?? CollectionFallback(typeof(HashSet<>), type); - } - - // default value for arrays - if (type.IsArray) - { - return Expression.NewArrayInit(type.GetElementType()); - } - - return null; + return Expression.NewArrayInit(type.GetElementType()); } - static Expression CollectionFallback(Type definition, Type type) - { - var collection = definition.MakeGenericType(type.GetTypeInfo().GenericTypeArguments); - - // try if an instance of this collection would suffice - if (type.GetTypeInfo().IsAssignableFrom(collection.GetTypeInfo())) - { - return Expression.Convert(Expression.New(collection), type); - } + return null; + } - return null; - } + static Expression CollectionFallback(Type definition, Type type) + { + var collection = definition.MakeGenericType(type.GetTypeInfo().GenericTypeArguments); - static bool IsExtensionMethod(MethodInfo element) + // try if an instance of this collection would suffice + if (type.GetTypeInfo().IsAssignableFrom(collection.GetTypeInfo())) { - return element.IsDefined(typeof(ExtensionAttribute), false); + return Expression.Convert(Expression.New(collection), type); } - static bool IsNullableOrReferenceType(Type type) - { - return !type.GetTypeInfo().IsValueType || Nullable.GetUnderlyingType(type) != null; - } + return null; + } + + static bool IsExtensionMethod(MethodInfo element) + { + return element.IsDefined(typeof(ExtensionAttribute), false); + } + + static bool IsNullableOrReferenceType(Type type) + { + return !type.GetTypeInfo().IsValueType || Nullable.GetUnderlyingType(type) != null; } } \ No newline at end of file diff --git a/src/AutoMapper/QueryableExtensions/ProjectionBuilder.cs b/src/AutoMapper/QueryableExtensions/ProjectionBuilder.cs index 88c013f676..d593fe054f 100644 --- a/src/AutoMapper/QueryableExtensions/ProjectionBuilder.cs +++ b/src/AutoMapper/QueryableExtensions/ProjectionBuilder.cs @@ -8,451 +8,450 @@ using System.Runtime.CompilerServices; using AutoMapper.Execution; using AutoMapper.Internal; -namespace AutoMapper.QueryableExtensions.Impl +namespace AutoMapper.QueryableExtensions.Impl; + +using static Expression; +using static ExpressionBuilder; +using ParameterBag = IDictionary; +using TypePairCount = Dictionary; +[EditorBrowsable(EditorBrowsableState.Never)] +public interface IProjectionBuilder { - using static Expression; - using static ExpressionBuilder; - using ParameterBag = IDictionary; - using TypePairCount = Dictionary; - [EditorBrowsable(EditorBrowsableState.Never)] - public interface IProjectionBuilder + QueryExpressions GetProjection(Type sourceType, Type destinationType, object parameters, MemberPath[] membersToExpand); + QueryExpressions CreateProjection(in ProjectionRequest request, LetPropertyMaps letPropertyMaps); +} +[EditorBrowsable(EditorBrowsableState.Never)] +public interface IProjectionMapper +{ + bool IsMatch(TypePair context); + Expression Project(IGlobalConfiguration configuration, in ProjectionRequest request, Expression resolvedSource, LetPropertyMaps letPropertyMaps); +} +[EditorBrowsable(EditorBrowsableState.Never)] +public class ProjectionBuilder : IProjectionBuilder +{ + internal static List DefaultProjectionMappers() => + new(capacity: 5) + { + new AssignableProjectionMapper(), + new EnumerableProjectionMapper(), + new NullableSourceProjectionMapper(), + new StringProjectionMapper(), + new EnumProjectionMapper(), + }; + private readonly LockingConcurrentDictionary _projectionCache; + private readonly IGlobalConfiguration _configuration; + private readonly IProjectionMapper[] _projectionMappers; + public ProjectionBuilder(IGlobalConfiguration configuration, IProjectionMapper[] projectionMappers) { - QueryExpressions GetProjection(Type sourceType, Type destinationType, object parameters, MemberPath[] membersToExpand); - QueryExpressions CreateProjection(in ProjectionRequest request, LetPropertyMaps letPropertyMaps); + _configuration = configuration; + _projectionMappers = projectionMappers; + _projectionCache = new(CreateProjection); } - [EditorBrowsable(EditorBrowsableState.Never)] - public interface IProjectionMapper + public QueryExpressions GetProjection(Type sourceType, Type destinationType, object parameters, MemberPath[] membersToExpand) + { + var projectionRequest = new ProjectionRequest(sourceType, destinationType, membersToExpand, Array.Empty()); + var cachedExpressions = _projectionCache.GetOrAdd(projectionRequest); + if (parameters == null && !_configuration.EnableNullPropagationForQueryMapping) + { + return cachedExpressions; + } + return cachedExpressions.Prepare(_configuration.EnableNullPropagationForQueryMapping, parameters); + } + private QueryExpressions CreateProjection(ProjectionRequest request) => + CreateProjection(request, new FirstPassLetPropertyMaps(_configuration, MemberPath.Empty, new())); + public QueryExpressions CreateProjection(in ProjectionRequest request, LetPropertyMaps letPropertyMaps) { - bool IsMatch(TypePair context); - Expression Project(IGlobalConfiguration configuration, in ProjectionRequest request, Expression resolvedSource, LetPropertyMaps letPropertyMaps); + var instanceParameter = Parameter(request.SourceType, "dto"+ request.SourceType.Name); + var typeMap = _configuration.ResolveTypeMap(request.SourceType, request.DestinationType) ?? throw TypeMap.MissingMapException(request.SourceType, request.DestinationType); + var projection = CreateProjectionCore(request, instanceParameter, typeMap, letPropertyMaps); + return letPropertyMaps.Count > 0 ? + letPropertyMaps.GetSubQueryExpression(this, projection, typeMap, request, instanceParameter) : + new(projection, instanceParameter); } - [EditorBrowsable(EditorBrowsableState.Never)] - public class ProjectionBuilder : IProjectionBuilder + private Expression CreateProjectionCore(ProjectionRequest request, Expression instanceParameter, TypeMap typeMap, LetPropertyMaps letPropertyMaps) { - internal static List DefaultProjectionMappers() => - new(capacity: 5) - { - new AssignableProjectionMapper(), - new EnumerableProjectionMapper(), - new NullableSourceProjectionMapper(), - new StringProjectionMapper(), - new EnumProjectionMapper(), - }; - private readonly LockingConcurrentDictionary _projectionCache; - private readonly IGlobalConfiguration _configuration; - private readonly IProjectionMapper[] _projectionMappers; - public ProjectionBuilder(IGlobalConfiguration configuration, IProjectionMapper[] projectionMappers) + var customProjection = typeMap.CustomMapExpression?.ReplaceParameters(instanceParameter); + if (customProjection != null) { - _configuration = configuration; - _projectionMappers = projectionMappers; - _projectionCache = new(CreateProjection); + return customProjection; } - public QueryExpressions GetProjection(Type sourceType, Type destinationType, object parameters, MemberPath[] membersToExpand) + var propertiesProjections = new List(); + int depth; + if (OverMaxDepth()) { - var projectionRequest = new ProjectionRequest(sourceType, destinationType, membersToExpand, Array.Empty()); - var cachedExpressions = _projectionCache.GetOrAdd(projectionRequest); - if (parameters == null && !_configuration.EnableNullPropagationForQueryMapping) + if (typeMap.Profile.AllowNullDestinationValues) { - return cachedExpressions; + return null; } - return cachedExpressions.Prepare(_configuration.EnableNullPropagationForQueryMapping, parameters); } - private QueryExpressions CreateProjection(ProjectionRequest request) => - CreateProjection(request, new FirstPassLetPropertyMaps(_configuration, MemberPath.Empty, new())); - public QueryExpressions CreateProjection(in ProjectionRequest request, LetPropertyMaps letPropertyMaps) + else { - var instanceParameter = Parameter(request.SourceType, "dto"+ request.SourceType.Name); - var typeMap = _configuration.ResolveTypeMap(request.SourceType, request.DestinationType) ?? throw TypeMap.MissingMapException(request.SourceType, request.DestinationType); - var projection = CreateProjectionCore(request, instanceParameter, typeMap, letPropertyMaps); - return letPropertyMaps.Count > 0 ? - letPropertyMaps.GetSubQueryExpression(this, projection, typeMap, request, instanceParameter) : - new(projection, instanceParameter); + ProjectProperties(); } - private Expression CreateProjectionCore(ProjectionRequest request, Expression instanceParameter, TypeMap typeMap, LetPropertyMaps letPropertyMaps) + var constructorExpression = CreateDestination(); + var expression = MemberInit(constructorExpression, propertiesProjections); + return expression; + bool OverMaxDepth() { - var customProjection = typeMap.CustomMapExpression?.ReplaceParameters(instanceParameter); - if (customProjection != null) + depth = letPropertyMaps.IncrementDepth(request); + return typeMap.MaxDepth > 0 && depth >= typeMap.MaxDepth; + } + void ProjectProperties() + { + foreach (var propertyMap in typeMap.PropertyMaps.Where(pm => + pm.CanResolveValue && pm.DestinationMember.CanBeSet() && !typeMap.ConstructorParameterMatches(pm.DestinationName)) + .OrderBy(pm => pm.DestinationMember.MetadataToken)) { - return customProjection; + var propertyProjection = TryProjectMember(propertyMap, propertyMap.ExplicitExpansion); + if (propertyProjection != null) + { + propertiesProjections.Add(Bind(propertyMap.DestinationMember, propertyProjection)); + } } - var propertiesProjections = new List(); - int depth; - if (OverMaxDepth()) + } + Expression TryProjectMember(MemberMap memberMap, bool? explicitExpansion = null, Expression defaultSource = null) + { + var memberProjection = new MemberProjection(memberMap); + letPropertyMaps.Push(memberProjection); + var memberExpression = ShouldExpand() ? ProjectMemberCore() : null; + letPropertyMaps.Pop(); + return memberExpression; + bool ShouldExpand() => explicitExpansion != true || request.ShouldExpand(letPropertyMaps.GetCurrentPath()); + Expression ProjectMemberCore() { - if (typeMap.Profile.AllowNullDestinationValues) + var memberTypeMap = _configuration.ResolveTypeMap(memberMap.SourceType, memberMap.DestinationType); + var resolvedSource = ResolveSource(); + memberProjection.Expression ??= resolvedSource; + var memberRequest = request.InnerRequest(resolvedSource.Type, memberMap.DestinationType); + if (memberRequest.AlreadyExists && depth >= _configuration.RecursiveQueriesMaxDepth) { return null; } - } - else - { - ProjectProperties(); - } - var constructorExpression = CreateDestination(); - var expression = MemberInit(constructorExpression, propertiesProjections); - return expression; - bool OverMaxDepth() - { - depth = letPropertyMaps.IncrementDepth(request); - return typeMap.MaxDepth > 0 && depth >= typeMap.MaxDepth; - } - void ProjectProperties() - { - foreach (var propertyMap in typeMap.PropertyMaps.Where(pm => - pm.CanResolveValue && pm.DestinationMember.CanBeSet() && !typeMap.ConstructorParameterMatches(pm.DestinationName)) - .OrderBy(pm => pm.DestinationMember.MetadataToken)) + Expression mappedExpression; + if (memberTypeMap != null) { - var propertyProjection = TryProjectMember(propertyMap, propertyMap.ExplicitExpansion); - if (propertyProjection != null) + mappedExpression = CreateProjectionCore(memberRequest, resolvedSource, memberTypeMap, letPropertyMaps); + if (mappedExpression != null && memberTypeMap.CustomMapExpression == null && memberMap.AllowsNullDestinationValues && + resolvedSource is not ParameterExpression && !resolvedSource.Type.IsCollection()) { - propertiesProjections.Add(Bind(propertyMap.DestinationMember, propertyProjection)); + // Handles null source property so it will not create an object with possible non-nullable properties which would result in an exception. + mappedExpression = resolvedSource.IfNullElse(Constant(null, mappedExpression.Type), mappedExpression); } } - } - Expression TryProjectMember(MemberMap memberMap, bool? explicitExpansion = null, Expression defaultSource = null) - { - var memberProjection = new MemberProjection(memberMap); - letPropertyMaps.Push(memberProjection); - var memberExpression = ShouldExpand() ? ProjectMemberCore() : null; - letPropertyMaps.Pop(); - return memberExpression; - bool ShouldExpand() => explicitExpansion != true || request.ShouldExpand(letPropertyMaps.GetCurrentPath()); - Expression ProjectMemberCore() + else { - var memberTypeMap = _configuration.ResolveTypeMap(memberMap.SourceType, memberMap.DestinationType); - var resolvedSource = ResolveSource(); - memberProjection.Expression ??= resolvedSource; - var memberRequest = request.InnerRequest(resolvedSource.Type, memberMap.DestinationType); - if (memberRequest.AlreadyExists && depth >= _configuration.RecursiveQueriesMaxDepth) - { - return null; - } - Expression mappedExpression; - if (memberTypeMap != null) + var projectionMapper = GetProjectionMapper(); + mappedExpression = projectionMapper.Project(_configuration, memberRequest, resolvedSource, letPropertyMaps); + } + return mappedExpression == null ? null : memberMap.ApplyTransformers(mappedExpression, _configuration); + Expression ResolveSource() + { + var customSource = memberMap.IncludedMember?.ProjectToCustomSource; + var resolvedSource = memberMap switch { - mappedExpression = CreateProjectionCore(memberRequest, resolvedSource, memberTypeMap, letPropertyMaps); - if (mappedExpression != null && memberTypeMap.CustomMapExpression == null && memberMap.AllowsNullDestinationValues && - resolvedSource is not ParameterExpression && !resolvedSource.Type.IsCollection()) - { - // Handles null source property so it will not create an object with possible non-nullable properties which would result in an exception. - mappedExpression = resolvedSource.IfNullElse(Constant(null, mappedExpression.Type), mappedExpression); - } - } - else + { CustomMapExpression: LambdaExpression mapFrom } => MapFromExpression(mapFrom), + { SourceMembers.Length: > 0 } => memberMap.ChainSourceMembers(CheckCustomSource()), + _ => defaultSource ?? throw CannotMap(memberMap, request.SourceType) + }; + if (NullSubstitute()) { - var projectionMapper = GetProjectionMapper(); - mappedExpression = projectionMapper.Project(_configuration, memberRequest, resolvedSource, letPropertyMaps); + return memberMap.NullSubstitute(resolvedSource); } - return mappedExpression == null ? null : memberMap.ApplyTransformers(mappedExpression, _configuration); - Expression ResolveSource() + return resolvedSource; + Expression MapFromExpression(LambdaExpression mapFrom) { - var customSource = memberMap.IncludedMember?.ProjectToCustomSource; - var resolvedSource = memberMap switch - { - { CustomMapExpression: LambdaExpression mapFrom } => MapFromExpression(mapFrom), - { SourceMembers.Length: > 0 } => memberMap.ChainSourceMembers(CheckCustomSource()), - _ => defaultSource ?? throw CannotMap(memberMap, request.SourceType) - }; - if (NullSubstitute()) + if (memberTypeMap == null || mapFrom.IsMemberPath(out _) || mapFrom.Body is ParameterExpression) { - return memberMap.NullSubstitute(resolvedSource); + return mapFrom.ReplaceParameters(CheckCustomSource()); } - return resolvedSource; - Expression MapFromExpression(LambdaExpression mapFrom) + if (customSource == null) { - if (memberTypeMap == null || mapFrom.IsMemberPath(out _) || mapFrom.Body is ParameterExpression) - { - return mapFrom.ReplaceParameters(CheckCustomSource()); - } - if (customSource == null) - { - memberProjection.Expression = mapFrom; - return letPropertyMaps.GetSubQueryMarker(mapFrom); - } - var newMapFrom = IncludedMember.Chain(customSource, mapFrom); - memberProjection.Expression = newMapFrom; - return letPropertyMaps.GetSubQueryMarker(newMapFrom); + memberProjection.Expression = mapFrom; + return letPropertyMaps.GetSubQueryMarker(mapFrom); } - bool NullSubstitute() => memberMap.NullSubstitute != null && resolvedSource is MemberExpression && (resolvedSource.Type.IsNullableType() || resolvedSource.Type == typeof(string)); - Expression CheckCustomSource() + var newMapFrom = IncludedMember.Chain(customSource, mapFrom); + memberProjection.Expression = newMapFrom; + return letPropertyMaps.GetSubQueryMarker(newMapFrom); + } + bool NullSubstitute() => memberMap.NullSubstitute != null && resolvedSource is MemberExpression && (resolvedSource.Type.IsNullableType() || resolvedSource.Type == typeof(string)); + Expression CheckCustomSource() + { + if (customSource == null) { - if (customSource == null) - { - return instanceParameter; - } - return customSource.IsMemberPath(out _) ? customSource.ReplaceParameters(instanceParameter) : letPropertyMaps.GetSubQueryMarker(customSource); + return instanceParameter; } + return customSource.IsMemberPath(out _) ? customSource.ReplaceParameters(instanceParameter) : letPropertyMaps.GetSubQueryMarker(customSource); } - IProjectionMapper GetProjectionMapper() + } + IProjectionMapper GetProjectionMapper() + { + var context = memberMap.Types(); + foreach (var mapper in _projectionMappers) { - var context = memberMap.Types(); - foreach (var mapper in _projectionMappers) + if (mapper.IsMatch(context)) { - if (mapper.IsMatch(context)) - { - return mapper; - } + return mapper; } - throw CannotMap(memberMap, resolvedSource.Type); } + throw CannotMap(memberMap, resolvedSource.Type); } } - NewExpression CreateDestination() => typeMap switch + } + NewExpression CreateDestination() => typeMap switch + { + { CustomCtorExpression: LambdaExpression ctorExpression } => (NewExpression)ctorExpression.ReplaceParameters(instanceParameter), + { ConstructorMap: { CanResolve: true } constructorMap } => + New(constructorMap.Ctor, constructorMap.CtorParams.Select(map => TryProjectMember(map, null, map.DefaultValue(null)) ?? Default(map.DestinationType))), + _ => New(typeMap.DestinationType) + }; + } + private static AutoMapperMappingException CannotMap(MemberMap memberMap, Type sourceType) => new( + $"Unable to create a map expression from {memberMap.SourceMember?.DeclaringType?.Name}.{memberMap.SourceMember?.Name} ({sourceType}) to {memberMap.DestinationType.Name}.{memberMap.DestinationName} ({memberMap.DestinationType})", + null, memberMap); + [EditorBrowsable(EditorBrowsableState.Never)] + class FirstPassLetPropertyMaps : LetPropertyMaps + { + readonly Stack _currentPath = new(); + readonly List _savedPaths = new(); + readonly MemberPath _parentPath; + public FirstPassLetPropertyMaps(IGlobalConfiguration configuration, MemberPath parentPath, TypePairCount builtProjections) : base(configuration, builtProjections) + => _parentPath = parentPath; + public override Expression GetSubQueryMarker(LambdaExpression letExpression) + { + var subQueryPath = new SubQueryPath(_currentPath.Reverse().ToArray(), letExpression); + var existingPath = _savedPaths.SingleOrDefault(s => s.IsEquivalentTo(subQueryPath)); + if (existingPath.Marker != null) { - { CustomCtorExpression: LambdaExpression ctorExpression } => (NewExpression)ctorExpression.ReplaceParameters(instanceParameter), - { ConstructorMap: { CanResolve: true } constructorMap } => - New(constructorMap.Ctor, constructorMap.CtorParams.Select(map => TryProjectMember(map, null, map.DefaultValue(null)) ?? Default(map.DestinationType))), - _ => New(typeMap.DestinationType) - }; + return existingPath.Marker; + } + _savedPaths.Add(subQueryPath); + return subQueryPath.Marker; } - private static AutoMapperMappingException CannotMap(MemberMap memberMap, Type sourceType) => new( - $"Unable to create a map expression from {memberMap.SourceMember?.DeclaringType?.Name}.{memberMap.SourceMember?.Name} ({sourceType}) to {memberMap.DestinationType.Name}.{memberMap.DestinationName} ({memberMap.DestinationType})", - null, memberMap); - [EditorBrowsable(EditorBrowsableState.Never)] - class FirstPassLetPropertyMaps : LetPropertyMaps + public override void Push(MemberProjection memberProjection) => _currentPath.Push(memberProjection); + public override MemberPath GetCurrentPath() => _parentPath.Concat( + _currentPath.Reverse().Select(p => (p.MemberMap as PropertyMap)?.DestinationMember).Where(p => p != null)); + public override void Pop() => _currentPath.Pop(); + public override int Count => _savedPaths.Count; + public override LetPropertyMaps New() => new FirstPassLetPropertyMaps(Configuration, GetCurrentPath(), BuiltProjections); + public override QueryExpressions GetSubQueryExpression(ProjectionBuilder builder, Expression projection, TypeMap typeMap, in ProjectionRequest request, ParameterExpression instanceParameter) { - readonly Stack _currentPath = new(); - readonly List _savedPaths = new(); - readonly MemberPath _parentPath; - public FirstPassLetPropertyMaps(IGlobalConfiguration configuration, MemberPath parentPath, TypePairCount builtProjections) : base(configuration, builtProjections) - => _parentPath = parentPath; - public override Expression GetSubQueryMarker(LambdaExpression letExpression) + var letMapInfos = _savedPaths.Select(path => + (path.LetExpression, + MapFromSource : path.GetSourceExpression(instanceParameter), + Property : path.GetPropertyDescription(), + path.Marker)).ToArray(); + var properties = letMapInfos.Select(m => m.Property).Concat(GePropertiesVisitor.Retrieve(projection, instanceParameter)); + var letType = ProxyGenerator.GetSimilarType(typeof(object), properties); + TypeMap letTypeMap; + lock(Configuration) { - var subQueryPath = new SubQueryPath(_currentPath.Reverse().ToArray(), letExpression); - var existingPath = _savedPaths.SingleOrDefault(s => s.IsEquivalentTo(subQueryPath)); - if (existingPath.Marker != null) - { - return existingPath.Marker; - } - _savedPaths.Add(subQueryPath); - return subQueryPath.Marker; + letTypeMap = new(request.SourceType, letType, typeMap.Profile, null); } - public override void Push(MemberProjection memberProjection) => _currentPath.Push(memberProjection); - public override MemberPath GetCurrentPath() => _parentPath.Concat( - _currentPath.Reverse().Select(p => (p.MemberMap as PropertyMap)?.DestinationMember).Where(p => p != null)); - public override void Pop() => _currentPath.Pop(); - public override int Count => _savedPaths.Count; - public override LetPropertyMaps New() => new FirstPassLetPropertyMaps(Configuration, GetCurrentPath(), BuiltProjections); - public override QueryExpressions GetSubQueryExpression(ProjectionBuilder builder, Expression projection, TypeMap typeMap, in ProjectionRequest request, ParameterExpression instanceParameter) + var secondParameter = Parameter(letType, "dtoLet"); + ReplaceSubQueries(); + var letClause = builder.CreateProjectionCore(request, instanceParameter, letTypeMap, base.New()); + return new(Lambda(projection, secondParameter), Lambda(letClause, instanceParameter)); + void ReplaceSubQueries() { - var letMapInfos = _savedPaths.Select(path => - (path.LetExpression, - MapFromSource : path.GetSourceExpression(instanceParameter), - Property : path.GetPropertyDescription(), - path.Marker)).ToArray(); - var properties = letMapInfos.Select(m => m.Property).Concat(GePropertiesVisitor.Retrieve(projection, instanceParameter)); - var letType = ProxyGenerator.GetSimilarType(typeof(object), properties); - TypeMap letTypeMap; - lock(Configuration) - { - letTypeMap = new(request.SourceType, letType, typeMap.Profile, null); - } - var secondParameter = Parameter(letType, "dtoLet"); - ReplaceSubQueries(); - var letClause = builder.CreateProjectionCore(request, instanceParameter, letTypeMap, base.New()); - return new(Lambda(projection, secondParameter), Lambda(letClause, instanceParameter)); - void ReplaceSubQueries() + foreach(var letMapInfo in letMapInfos) { - foreach(var letMapInfo in letMapInfos) - { - var letProperty = letType.GetProperty(letMapInfo.Property.Name); - var letPropertyMap = letTypeMap.FindOrCreatePropertyMapFor(letProperty, letMapInfo.Property.Type); - letPropertyMap.SetResolver(Lambda(letMapInfo.LetExpression.ReplaceParameters(letMapInfo.MapFromSource), secondParameter)); - projection = projection.Replace(letMapInfo.Marker, Property(secondParameter, letProperty)); - } - projection = new ReplaceMemberAccessesVisitor(instanceParameter, secondParameter).Visit(projection); + var letProperty = letType.GetProperty(letMapInfo.Property.Name); + var letPropertyMap = letTypeMap.FindOrCreatePropertyMapFor(letProperty, letMapInfo.Property.Type); + letPropertyMap.SetResolver(Lambda(letMapInfo.LetExpression.ReplaceParameters(letMapInfo.MapFromSource), secondParameter)); + projection = projection.Replace(letMapInfo.Marker, Property(secondParameter, letProperty)); } + projection = new ReplaceMemberAccessesVisitor(instanceParameter, secondParameter).Visit(projection); } - readonly record struct SubQueryPath(MemberProjection[] Members, LambdaExpression LetExpression, Expression Marker) + } + readonly record struct SubQueryPath(MemberProjection[] Members, LambdaExpression LetExpression, Expression Marker) + { + public SubQueryPath(MemberProjection[] members, LambdaExpression letExpression) : this(members, letExpression, Default(letExpression.Body.Type)){ } + public Expression GetSourceExpression(Expression parameter) { - public SubQueryPath(MemberProjection[] members, LambdaExpression letExpression) : this(members, letExpression, Default(letExpression.Body.Type)){ } - public Expression GetSourceExpression(Expression parameter) + Expression sourceExpression = parameter; + for (int index = 0; index < Members.Length - 1; index++) { - Expression sourceExpression = parameter; - for (int index = 0; index < Members.Length - 1; index++) + var sourceMember = Members[index].Expression; + if (sourceMember is LambdaExpression lambda) { - var sourceMember = Members[index].Expression; - if (sourceMember is LambdaExpression lambda) - { - sourceExpression = lambda.ReplaceParameters(sourceExpression); - } - else + sourceExpression = lambda.ReplaceParameters(sourceExpression); + } + else + { + var chain = sourceMember.GetChain(); + if (chain.TryPeek(out var first)) { - var chain = sourceMember.GetChain(); - if (chain.TryPeek(out var first)) - { - sourceExpression = sourceMember.Replace(first.Target, sourceExpression); - } + sourceExpression = sourceMember.Replace(first.Target, sourceExpression); } } - return sourceExpression; } - public PropertyDescription GetPropertyDescription() => new("__" + string.Join("#", Members.Select(p => p.MemberMap.DestinationName)), LetExpression.Body.Type); - internal bool IsEquivalentTo(SubQueryPath other) => LetExpression == other.LetExpression && Members.Length == other.Members.Length && - Members.Take(Members.Length - 1).Zip(other.Members, (left, right) => left.MemberMap == right.MemberMap).All(item => item); + return sourceExpression; } - class GePropertiesVisitor : ExpressionVisitor + public PropertyDescription GetPropertyDescription() => new("__" + string.Join("#", Members.Select(p => p.MemberMap.DestinationName)), LetExpression.Body.Type); + internal bool IsEquivalentTo(SubQueryPath other) => LetExpression == other.LetExpression && Members.Length == other.Members.Length && + Members.Take(Members.Length - 1).Zip(other.Members, (left, right) => left.MemberMap == right.MemberMap).All(item => item); + } + class GePropertiesVisitor : ExpressionVisitor + { + private readonly Expression _target; + public HashSet Members { get; } = new(); + public GePropertiesVisitor(Expression target) => _target = target; + protected override Expression VisitMember(MemberExpression node) { - private readonly Expression _target; - public HashSet Members { get; } = new(); - public GePropertiesVisitor(Expression target) => _target = target; - protected override Expression VisitMember(MemberExpression node) - { - if(node.Expression == _target) - { - Members.Add(node.Member); - } - return base.VisitMember(node); - } - public static IEnumerable Retrieve(Expression expression, Expression target) + if(node.Expression == _target) { - var visitor = new GePropertiesVisitor(target); - visitor.Visit(expression); - return visitor.Members.Select(member => new PropertyDescription(member.Name, member.GetMemberType())); + Members.Add(node.Member); } + return base.VisitMember(node); } - class ReplaceMemberAccessesVisitor : ExpressionVisitor + public static IEnumerable Retrieve(Expression expression, Expression target) { - private readonly Expression _oldObject, _newObject; - public ReplaceMemberAccessesVisitor(Expression oldObject, Expression newObject) - { - _oldObject = oldObject; - _newObject = newObject; - } - protected override Expression VisitMember(MemberExpression node) + var visitor = new GePropertiesVisitor(target); + visitor.Visit(expression); + return visitor.Members.Select(member => new PropertyDescription(member.Name, member.GetMemberType())); + } + } + class ReplaceMemberAccessesVisitor : ExpressionVisitor + { + private readonly Expression _oldObject, _newObject; + public ReplaceMemberAccessesVisitor(Expression oldObject, Expression newObject) + { + _oldObject = oldObject; + _newObject = newObject; + } + protected override Expression VisitMember(MemberExpression node) + { + if(node.Expression != _oldObject) { - if(node.Expression != _oldObject) - { - return base.VisitMember(node); - } - return PropertyOrField(_newObject, node.Member.Name); + return base.VisitMember(node); } + return PropertyOrField(_newObject, node.Member.Name); } } } - [EditorBrowsable(EditorBrowsableState.Never)] - public class LetPropertyMaps +} +[EditorBrowsable(EditorBrowsableState.Never)] +public class LetPropertyMaps +{ + protected LetPropertyMaps(IGlobalConfiguration configuration, TypePairCount builtProjections) { - protected LetPropertyMaps(IGlobalConfiguration configuration, TypePairCount builtProjections) - { - Configuration = configuration; - BuiltProjections = builtProjections; - } - protected TypePairCount BuiltProjections { get; } - public int IncrementDepth(in ProjectionRequest request) + Configuration = configuration; + BuiltProjections = builtProjections; + } + protected TypePairCount BuiltProjections { get; } + public int IncrementDepth(in ProjectionRequest request) + { + if (BuiltProjections.TryGetValue(request, out var depth)) { - if (BuiltProjections.TryGetValue(request, out var depth)) - { - depth++; - } - BuiltProjections[request] = depth; - return depth; + depth++; } - public virtual Expression GetSubQueryMarker(LambdaExpression letExpression) => letExpression.Body; - public virtual void Push(MemberProjection memberProjection) { } - public virtual MemberPath GetCurrentPath() => MemberPath.Empty; - public virtual void Pop() {} - public virtual int Count => 0; - public IGlobalConfiguration Configuration { get; } - public virtual LetPropertyMaps New() => new(Configuration, BuiltProjections); - public virtual QueryExpressions GetSubQueryExpression(ProjectionBuilder builder, Expression projection, TypeMap typeMap, in ProjectionRequest request, ParameterExpression instanceParameter) - => default; + BuiltProjections[request] = depth; + return depth; } - [EditorBrowsable(EditorBrowsableState.Never)] - public readonly record struct QueryExpressions(LambdaExpression Projection, LambdaExpression LetClause = null) + public virtual Expression GetSubQueryMarker(LambdaExpression letExpression) => letExpression.Body; + public virtual void Push(MemberProjection memberProjection) { } + public virtual MemberPath GetCurrentPath() => MemberPath.Empty; + public virtual void Pop() {} + public virtual int Count => 0; + public IGlobalConfiguration Configuration { get; } + public virtual LetPropertyMaps New() => new(Configuration, BuiltProjections); + public virtual QueryExpressions GetSubQueryExpression(ProjectionBuilder builder, Expression projection, TypeMap typeMap, in ProjectionRequest request, ParameterExpression instanceParameter) + => default; +} +[EditorBrowsable(EditorBrowsableState.Never)] +public readonly record struct QueryExpressions(LambdaExpression Projection, LambdaExpression LetClause = null) +{ + public QueryExpressions(Expression projection, ParameterExpression parameter) : this(projection == null ? null : Lambda(projection, parameter)) { } + public bool Empty => Projection == null; + public T Chain(T source, Func select) => LetClause == null ? select(source, Projection) : select(select(source, LetClause), Projection); + internal QueryExpressions Prepare(bool enableNullPropagationForQueryMapping, object parameters) { - public QueryExpressions(Expression projection, ParameterExpression parameter) : this(projection == null ? null : Lambda(projection, parameter)) { } - public bool Empty => Projection == null; - public T Chain(T source, Func select) => LetClause == null ? select(source, Projection) : select(select(source, LetClause), Projection); - internal QueryExpressions Prepare(bool enableNullPropagationForQueryMapping, object parameters) + return new(Prepare(Projection), Prepare(LetClause)); + LambdaExpression Prepare(Expression cachedExpression) { - return new(Prepare(Projection), Prepare(LetClause)); - LambdaExpression Prepare(Expression cachedExpression) - { - var result = parameters == null ? cachedExpression : ParameterExpressionVisitor.SetParameters(parameters, cachedExpression); - return (LambdaExpression)(enableNullPropagationForQueryMapping ? NullsafeQueryRewriter.NullCheck(result) : result); - } + var result = parameters == null ? cachedExpression : ParameterExpressionVisitor.SetParameters(parameters, cachedExpression); + return (LambdaExpression)(enableNullPropagationForQueryMapping ? NullsafeQueryRewriter.NullCheck(result) : result); } } - public class MemberProjection +} +public class MemberProjection +{ + public MemberProjection(MemberMap memberMap) => MemberMap = memberMap; + public Expression Expression { get; set; } + public MemberMap MemberMap { get; } +} +abstract class ParameterExpressionVisitor : ExpressionVisitor +{ + public static Expression SetParameters(object parameters, Expression expression) { - public MemberProjection(MemberMap memberMap) => MemberMap = memberMap; - public Expression Expression { get; set; } - public MemberMap MemberMap { get; } + var visitor = parameters is ParameterBag dictionary ? (ParameterExpressionVisitor)new ConstantExpressionReplacementVisitor(dictionary) : new ObjectParameterExpressionReplacementVisitor(parameters); + return visitor.Visit(expression); } - abstract class ParameterExpressionVisitor : ExpressionVisitor + protected abstract Expression GetValue(string name); + protected override Expression VisitMember(MemberExpression node) { - public static Expression SetParameters(object parameters, Expression expression) + if (!node.Member.DeclaringType.Has()) { - var visitor = parameters is ParameterBag dictionary ? (ParameterExpressionVisitor)new ConstantExpressionReplacementVisitor(dictionary) : new ObjectParameterExpressionReplacementVisitor(parameters); - return visitor.Visit(expression); + return base.VisitMember(node); } - protected abstract Expression GetValue(string name); - protected override Expression VisitMember(MemberExpression node) + var parameterName = node.Member.Name; + var parameterValue = GetValue(parameterName); + if (parameterValue == null) { - if (!node.Member.DeclaringType.Has()) + const string VbPrefix = "$VB$Local_"; + if (!parameterName.StartsWith(VbPrefix, StringComparison.Ordinal) || (parameterValue = GetValue(parameterName.Substring(VbPrefix.Length))) == null) { return base.VisitMember(node); } - var parameterName = node.Member.Name; - var parameterValue = GetValue(parameterName); - if (parameterValue == null) - { - const string VbPrefix = "$VB$Local_"; - if (!parameterName.StartsWith(VbPrefix, StringComparison.Ordinal) || (parameterValue = GetValue(parameterName.Substring(VbPrefix.Length))) == null) - { - return base.VisitMember(node); - } - } - return ToType(parameterValue, node.Member.GetMemberType()); - } - class ObjectParameterExpressionReplacementVisitor : ParameterExpressionVisitor - { - private readonly object _parameters; - public ObjectParameterExpressionReplacementVisitor(object parameters) => _parameters = parameters; - protected override Expression GetValue(string name) - { - var matchingMember = _parameters.GetType().GetProperty(name); - return matchingMember != null ? Property(Constant(_parameters), matchingMember) : null; - } } - class ConstantExpressionReplacementVisitor : ParameterExpressionVisitor + return ToType(parameterValue, node.Member.GetMemberType()); + } + class ObjectParameterExpressionReplacementVisitor : ParameterExpressionVisitor + { + private readonly object _parameters; + public ObjectParameterExpressionReplacementVisitor(object parameters) => _parameters = parameters; + protected override Expression GetValue(string name) { - private readonly ParameterBag _paramValues; - public ConstantExpressionReplacementVisitor(ParameterBag paramValues) => _paramValues = paramValues; - protected override Expression GetValue(string name) => _paramValues.TryGetValue(name, out object parameterValue) ? Constant(parameterValue) : null; + var matchingMember = _parameters.GetType().GetProperty(name); + return matchingMember != null ? Property(Constant(_parameters), matchingMember) : null; } } - [EditorBrowsable(EditorBrowsableState.Never)] - [DebuggerDisplay("{SourceType.Name}, {DestinationType.Name}")] - public readonly record struct ProjectionRequest(Type SourceType, Type DestinationType, MemberPath[] MembersToExpand, ICollection PreviousRequests) + class ConstantExpressionReplacementVisitor : ParameterExpressionVisitor + { + private readonly ParameterBag _paramValues; + public ConstantExpressionReplacementVisitor(ParameterBag paramValues) => _paramValues = paramValues; + protected override Expression GetValue(string name) => _paramValues.TryGetValue(name, out object parameterValue) ? Constant(parameterValue) : null; + } +} +[EditorBrowsable(EditorBrowsableState.Never)] +[DebuggerDisplay("{SourceType.Name}, {DestinationType.Name}")] +public readonly record struct ProjectionRequest(Type SourceType, Type DestinationType, MemberPath[] MembersToExpand, ICollection PreviousRequests) +{ + public ProjectionRequest InnerRequest(Type sourceType, Type destinationType) => + new(sourceType, destinationType, MembersToExpand, new HashSet(PreviousRequests) { this }); + public bool AlreadyExists => PreviousRequests.Contains(this); + public bool Equals(ProjectionRequest other) => SourceType == other.SourceType && DestinationType == other.DestinationType && + MembersToExpand.SequenceEqual(other.MembersToExpand); + public override int GetHashCode() { - public ProjectionRequest InnerRequest(Type sourceType, Type destinationType) => - new(sourceType, destinationType, MembersToExpand, new HashSet(PreviousRequests) { this }); - public bool AlreadyExists => PreviousRequests.Contains(this); - public bool Equals(ProjectionRequest other) => SourceType == other.SourceType && DestinationType == other.DestinationType && - MembersToExpand.SequenceEqual(other.MembersToExpand); - public override int GetHashCode() + var hashCode = new HashCode(); + hashCode.Add(SourceType); + hashCode.Add(DestinationType); + foreach (var member in MembersToExpand) { - var hashCode = new HashCode(); - hashCode.Add(SourceType); - hashCode.Add(DestinationType); - foreach (var member in MembersToExpand) - { - hashCode.Add(member); - } - return hashCode.ToHashCode(); + hashCode.Add(member); } - public bool ShouldExpand(MemberPath currentPath) + return hashCode.ToHashCode(); + } + public bool ShouldExpand(MemberPath currentPath) + { + foreach (var memberToExpand in MembersToExpand) { - foreach (var memberToExpand in MembersToExpand) + if (memberToExpand.StartsWith(currentPath)) { - if (memberToExpand.StartsWith(currentPath)) - { - return true; - } + return true; } - return false; } + return false; } } \ No newline at end of file diff --git a/src/AutoMapper/QueryableExtensions/ProjectionMappers/AssignableProjectionMapper.cs b/src/AutoMapper/QueryableExtensions/ProjectionMappers/AssignableProjectionMapper.cs index 072b2bfa65..9193e1b0d9 100644 --- a/src/AutoMapper/QueryableExtensions/ProjectionMappers/AssignableProjectionMapper.cs +++ b/src/AutoMapper/QueryableExtensions/ProjectionMappers/AssignableProjectionMapper.cs @@ -3,13 +3,12 @@ using System.ComponentModel; using System.Linq.Expressions; -namespace AutoMapper.QueryableExtensions.Impl +namespace AutoMapper.QueryableExtensions.Impl; + +[EditorBrowsable(EditorBrowsableState.Never)] +public class AssignableProjectionMapper : IProjectionMapper { - [EditorBrowsable(EditorBrowsableState.Never)] - public class AssignableProjectionMapper : IProjectionMapper - { - public bool IsMatch(TypePair context) => context.DestinationType.IsAssignableFrom(context.SourceType); - public Expression Project(IGlobalConfiguration configuration, in ProjectionRequest request, Expression resolvedSource, LetPropertyMaps letPropertyMaps) - => ExpressionBuilder.ToType(resolvedSource, request.DestinationType); - } + public bool IsMatch(TypePair context) => context.DestinationType.IsAssignableFrom(context.SourceType); + public Expression Project(IGlobalConfiguration configuration, in ProjectionRequest request, Expression resolvedSource, LetPropertyMaps letPropertyMaps) + => ExpressionBuilder.ToType(resolvedSource, request.DestinationType); } \ No newline at end of file diff --git a/src/AutoMapper/QueryableExtensions/ProjectionMappers/EnumProjectionMapper.cs b/src/AutoMapper/QueryableExtensions/ProjectionMappers/EnumProjectionMapper.cs index b61d779227..a472b0523b 100644 --- a/src/AutoMapper/QueryableExtensions/ProjectionMappers/EnumProjectionMapper.cs +++ b/src/AutoMapper/QueryableExtensions/ProjectionMappers/EnumProjectionMapper.cs @@ -2,14 +2,13 @@ using System.ComponentModel; using System.Linq.Expressions; -namespace AutoMapper.QueryableExtensions.Impl +namespace AutoMapper.QueryableExtensions.Impl; + +using static Expression; +[EditorBrowsable(EditorBrowsableState.Never)] +public class EnumProjectionMapper : IProjectionMapper { - using static Expression; - [EditorBrowsable(EditorBrowsableState.Never)] - public class EnumProjectionMapper : IProjectionMapper - { - public Expression Project(IGlobalConfiguration configuration, in ProjectionRequest request, Expression resolvedSource, LetPropertyMaps letPropertyMaps) - => Convert(resolvedSource, request.DestinationType); - public bool IsMatch(TypePair context) => context.IsEnumToEnum() || context.IsUnderlyingTypeToEnum() || context.IsEnumToUnderlyingType(); - } + public Expression Project(IGlobalConfiguration configuration, in ProjectionRequest request, Expression resolvedSource, LetPropertyMaps letPropertyMaps) + => Convert(resolvedSource, request.DestinationType); + public bool IsMatch(TypePair context) => context.IsEnumToEnum() || context.IsUnderlyingTypeToEnum() || context.IsEnumToUnderlyingType(); } \ No newline at end of file diff --git a/src/AutoMapper/QueryableExtensions/ProjectionMappers/EnumerableProjectionMapper.cs b/src/AutoMapper/QueryableExtensions/ProjectionMappers/EnumerableProjectionMapper.cs index cdd173a7de..b341d02de1 100644 --- a/src/AutoMapper/QueryableExtensions/ProjectionMappers/EnumerableProjectionMapper.cs +++ b/src/AutoMapper/QueryableExtensions/ProjectionMappers/EnumerableProjectionMapper.cs @@ -5,54 +5,53 @@ using System.Reflection; using AutoMapper.Internal; -namespace AutoMapper.QueryableExtensions.Impl +namespace AutoMapper.QueryableExtensions.Impl; + +using static Expression; +using static Execution.ExpressionBuilder; +using static ReflectionHelper; +[EditorBrowsable(EditorBrowsableState.Never)] +public class EnumerableProjectionMapper : IProjectionMapper { - using static Expression; - using static Execution.ExpressionBuilder; - using static ReflectionHelper; - [EditorBrowsable(EditorBrowsableState.Never)] - public class EnumerableProjectionMapper : IProjectionMapper + private static readonly MethodInfo SelectMethod = typeof(Enumerable).StaticGenericMethod("Select", parametersCount: 2); + private static readonly MethodInfo ToArrayMethod = typeof(Enumerable).GetStaticMethod("ToArray"); + private static readonly MethodInfo ToListMethod = typeof(Enumerable).GetStaticMethod("ToList"); + public bool IsMatch(TypePair context) => context.IsCollection(); + public Expression Project(IGlobalConfiguration configuration, in ProjectionRequest request, Expression resolvedSource, LetPropertyMaps letPropertyMaps) { - private static readonly MethodInfo SelectMethod = typeof(Enumerable).StaticGenericMethod("Select", parametersCount: 2); - private static readonly MethodInfo ToArrayMethod = typeof(Enumerable).GetStaticMethod("ToArray"); - private static readonly MethodInfo ToListMethod = typeof(Enumerable).GetStaticMethod("ToList"); - public bool IsMatch(TypePair context) => context.IsCollection(); - public Expression Project(IGlobalConfiguration configuration, in ProjectionRequest request, Expression resolvedSource, LetPropertyMaps letPropertyMaps) + var destinationType = request.DestinationType; + var destinationListType = GetElementType(destinationType); + var sourceListType = GetElementType(request.SourceType); + var sourceExpression = resolvedSource; + if (sourceListType != destinationListType) { - var destinationType = request.DestinationType; - var destinationListType = GetElementType(destinationType); - var sourceListType = GetElementType(request.SourceType); - var sourceExpression = resolvedSource; - if (sourceListType != destinationListType) + var itemRequest = request.InnerRequest(sourceListType, destinationListType); + var transformedExpressions = configuration.ProjectionBuilder.CreateProjection(itemRequest, letPropertyMaps.New()); + if(transformedExpressions.Empty) { - var itemRequest = request.InnerRequest(sourceListType, destinationListType); - var transformedExpressions = configuration.ProjectionBuilder.CreateProjection(itemRequest, letPropertyMaps.New()); - if(transformedExpressions.Empty) - { - return null; - } - sourceExpression = transformedExpressions.Chain(sourceExpression, Select); + return null; } - if (!destinationType.IsAssignableFrom(sourceExpression.Type)) + sourceExpression = transformedExpressions.Chain(sourceExpression, Select); + } + if (!destinationType.IsAssignableFrom(sourceExpression.Type)) + { + var convertFunction = destinationType.IsArray ? ToArrayMethod : ToListMethod; + convertFunction = convertFunction.MakeGenericMethod(destinationListType); + if (destinationType.IsAssignableFrom(convertFunction.ReturnType)) { - var convertFunction = destinationType.IsArray ? ToArrayMethod : ToListMethod; - convertFunction = convertFunction.MakeGenericMethod(destinationListType); - if (destinationType.IsAssignableFrom(convertFunction.ReturnType)) - { - sourceExpression = Call(convertFunction, sourceExpression); - } - else + sourceExpression = Call(convertFunction, sourceExpression); + } + else + { + var ctorInfo = destinationType.GetConstructor(new[] { sourceExpression.Type }); + if (ctorInfo is not null) { - var ctorInfo = destinationType.GetConstructor(new[] { sourceExpression.Type }); - if (ctorInfo is not null) - { - sourceExpression = New(ctorInfo, sourceExpression); - } + sourceExpression = New(ctorInfo, sourceExpression); } } - return sourceExpression; } - private static Expression Select(Expression source, LambdaExpression lambda) => - Call(SelectMethod.MakeGenericMethod(lambda.Parameters[0].Type, lambda.ReturnType), source, lambda); + return sourceExpression; } + private static Expression Select(Expression source, LambdaExpression lambda) => + Call(SelectMethod.MakeGenericMethod(lambda.Parameters[0].Type, lambda.ReturnType), source, lambda); } \ No newline at end of file diff --git a/src/AutoMapper/QueryableExtensions/ProjectionMappers/NullableSourceProjectionMapper.cs b/src/AutoMapper/QueryableExtensions/ProjectionMappers/NullableSourceProjectionMapper.cs index 5405aab9df..0c0030d423 100644 --- a/src/AutoMapper/QueryableExtensions/ProjectionMappers/NullableSourceProjectionMapper.cs +++ b/src/AutoMapper/QueryableExtensions/ProjectionMappers/NullableSourceProjectionMapper.cs @@ -1,13 +1,12 @@ using System.Linq.Expressions; using AutoMapper.Internal; -namespace AutoMapper.QueryableExtensions.Impl +namespace AutoMapper.QueryableExtensions.Impl; + +using static Expression; +internal class NullableSourceProjectionMapper : IProjectionMapper { - using static Expression; - internal class NullableSourceProjectionMapper : IProjectionMapper - { - public Expression Project(IGlobalConfiguration configuration, in ProjectionRequest request, Expression resolvedSource, LetPropertyMaps letPropertyMaps) => - Coalesce(resolvedSource, New(request.DestinationType)); - public bool IsMatch(TypePair context) => - context.DestinationType.IsValueType && !context.DestinationType.IsNullableType() && context.SourceType.IsNullableType(); - } + public Expression Project(IGlobalConfiguration configuration, in ProjectionRequest request, Expression resolvedSource, LetPropertyMaps letPropertyMaps) => + Coalesce(resolvedSource, New(request.DestinationType)); + public bool IsMatch(TypePair context) => + context.DestinationType.IsValueType && !context.DestinationType.IsNullableType() && context.SourceType.IsNullableType(); } \ No newline at end of file diff --git a/src/AutoMapper/QueryableExtensions/ProjectionMappers/StringProjectionMapper.cs b/src/AutoMapper/QueryableExtensions/ProjectionMappers/StringProjectionMapper.cs index 546330fae9..754407c354 100644 --- a/src/AutoMapper/QueryableExtensions/ProjectionMappers/StringProjectionMapper.cs +++ b/src/AutoMapper/QueryableExtensions/ProjectionMappers/StringProjectionMapper.cs @@ -2,13 +2,12 @@ using AutoMapper.Internal; using System.ComponentModel; using System.Linq.Expressions; -namespace AutoMapper.QueryableExtensions.Impl +namespace AutoMapper.QueryableExtensions.Impl; + +[EditorBrowsable(EditorBrowsableState.Never)] +public class StringProjectionMapper : IProjectionMapper { - [EditorBrowsable(EditorBrowsableState.Never)] - public class StringProjectionMapper : IProjectionMapper - { - public bool IsMatch(TypePair context) => context.DestinationType == typeof(string); - public Expression Project(IGlobalConfiguration configuration, in ProjectionRequest request, Expression resolvedSource, LetPropertyMaps letPropertyMaps) - => Expression.Call(resolvedSource, ExpressionBuilder.ObjectToString); - } + public bool IsMatch(TypePair context) => context.DestinationType == typeof(string); + public Expression Project(IGlobalConfiguration configuration, in ProjectionRequest request, Expression resolvedSource, LetPropertyMaps letPropertyMaps) + => Expression.Call(resolvedSource, ExpressionBuilder.ObjectToString); } \ No newline at end of file diff --git a/src/AutoMapper/ResolutionContext.cs b/src/AutoMapper/ResolutionContext.cs index c84fb52571..ff4525d72b 100644 --- a/src/AutoMapper/ResolutionContext.cs +++ b/src/AutoMapper/ResolutionContext.cs @@ -1,113 +1,112 @@ using AutoMapper.Internal; using System; using System.Collections.Generic; -namespace AutoMapper +namespace AutoMapper; + +/// +/// Context information regarding resolution of a destination value +/// +public class ResolutionContext : IInternalRuntimeMapper { + private Dictionary _instanceCache; + private Dictionary _typeDepth; + private readonly IInternalRuntimeMapper _mapper; + private readonly IMappingOperationOptions _options; + internal ResolutionContext(IInternalRuntimeMapper mapper, IMappingOperationOptions options = null) + { + _mapper = mapper; + _options = options; + } /// - /// Context information regarding resolution of a destination value + /// The items passed in the options of the Map call. /// - public class ResolutionContext : IInternalRuntimeMapper + public IDictionary Items { - private Dictionary _instanceCache; - private Dictionary _typeDepth; - private readonly IInternalRuntimeMapper _mapper; - private readonly IMappingOperationOptions _options; - internal ResolutionContext(IInternalRuntimeMapper mapper, IMappingOperationOptions options = null) + get { - _mapper = mapper; - _options = options; - } - /// - /// The items passed in the options of the Map call. - /// - public IDictionary Items - { - get + if (_options == null) { - if (_options == null) - { - ThrowInvalidMap(); - } - return _options.Items; + ThrowInvalidMap(); } + return _options.Items; } - /// - /// Current mapper - /// - public IRuntimeMapper Mapper => this; - ResolutionContext IInternalRuntimeMapper.DefaultContext => _mapper.DefaultContext; - /// - /// Instance cache for resolving circular references - /// - public Dictionary InstanceCache + } + /// + /// Current mapper + /// + public IRuntimeMapper Mapper => this; + ResolutionContext IInternalRuntimeMapper.DefaultContext => _mapper.DefaultContext; + /// + /// Instance cache for resolving circular references + /// + public Dictionary InstanceCache + { + get { - get - { - CheckDefault(); - return _instanceCache ??= new(); - } + CheckDefault(); + return _instanceCache ??= new(); } - /// - /// Instance cache for resolving keeping track of depth - /// - private Dictionary TypeDepth + } + /// + /// Instance cache for resolving keeping track of depth + /// + private Dictionary TypeDepth + { + get { - get - { - CheckDefault(); - return _typeDepth ??= new(); - } + CheckDefault(); + return _typeDepth ??= new(); } - TDestination IMapperBase.Map(object source) => ((IMapperBase)this).Map(source, default(TDestination)); - TDestination IMapperBase.Map(TSource source) => _mapper.Map(source, default(TDestination), this); - TDestination IMapperBase.Map(TSource source, TDestination destination) => _mapper.Map(source, destination, this); - object IMapperBase.Map(object source, Type sourceType, Type destinationType) => _mapper.Map(source, (object)null, this, sourceType, destinationType); - object IMapperBase.Map(object source, object destination, Type sourceType, Type destinationType) => _mapper.Map(source, destination, this, sourceType, destinationType); - TDestination IInternalRuntimeMapper.Map(TSource source, TDestination destination, ResolutionContext context, - Type sourceType, Type destinationType, MemberMap memberMap) => _mapper.Map(source, destination, context, sourceType, destinationType, memberMap); - internal object CreateInstance(Type type) => ServiceCtor()(type) ?? throw new AutoMapperMappingException("Cannot create an instance of type " + type); - private Func ServiceCtor() => _options?.ServiceCtor ?? _mapper.ServiceCtor; - internal object GetDestination(object source, Type destinationType) => source == null ? null : InstanceCache.GetValueOrDefault(new(source, destinationType)); - internal void CacheDestination(object source, Type destinationType, object destination) + } + TDestination IMapperBase.Map(object source) => ((IMapperBase)this).Map(source, default(TDestination)); + TDestination IMapperBase.Map(TSource source) => _mapper.Map(source, default(TDestination), this); + TDestination IMapperBase.Map(TSource source, TDestination destination) => _mapper.Map(source, destination, this); + object IMapperBase.Map(object source, Type sourceType, Type destinationType) => _mapper.Map(source, (object)null, this, sourceType, destinationType); + object IMapperBase.Map(object source, object destination, Type sourceType, Type destinationType) => _mapper.Map(source, destination, this, sourceType, destinationType); + TDestination IInternalRuntimeMapper.Map(TSource source, TDestination destination, ResolutionContext context, + Type sourceType, Type destinationType, MemberMap memberMap) => _mapper.Map(source, destination, context, sourceType, destinationType, memberMap); + internal object CreateInstance(Type type) => ServiceCtor()(type) ?? throw new AutoMapperMappingException("Cannot create an instance of type " + type); + private Func ServiceCtor() => _options?.ServiceCtor ?? _mapper.ServiceCtor; + internal object GetDestination(object source, Type destinationType) => source == null ? null : InstanceCache.GetValueOrDefault(new(source, destinationType)); + internal void CacheDestination(object source, Type destinationType, object destination) + { + if (source == null) { - if (source == null) - { - return; - } - InstanceCache[new(source, destinationType)] = destination; + return; } - internal void IncrementTypeDepth(TypeMap typeMap) => TypeDepth[typeMap.Types]++; - internal void DecrementTypeDepth(TypeMap typeMap) => TypeDepth[typeMap.Types]--; - internal bool OverTypeDepth(TypeMap typeMap) + InstanceCache[new(source, destinationType)] = destination; + } + internal void IncrementTypeDepth(TypeMap typeMap) => TypeDepth[typeMap.Types]++; + internal void DecrementTypeDepth(TypeMap typeMap) => TypeDepth[typeMap.Types]--; + internal bool OverTypeDepth(TypeMap typeMap) + { + if (!TypeDepth.TryGetValue(typeMap.Types, out int depth)) { - if (!TypeDepth.TryGetValue(typeMap.Types, out int depth)) - { - TypeDepth[typeMap.Types] = 1; - depth = 1; - } - return depth > typeMap.MaxDepth; + TypeDepth[typeMap.Types] = 1; + depth = 1; } - internal bool IsDefault => this == _mapper.DefaultContext; - Func IInternalRuntimeMapper.ServiceCtor => ServiceCtor(); - internal static void CheckContext(ref ResolutionContext resolutionContext) + return depth > typeMap.MaxDepth; + } + internal bool IsDefault => this == _mapper.DefaultContext; + Func IInternalRuntimeMapper.ServiceCtor => ServiceCtor(); + internal static void CheckContext(ref ResolutionContext resolutionContext) + { + if (resolutionContext.IsDefault) { - if (resolutionContext.IsDefault) - { - resolutionContext = new(resolutionContext._mapper); - } + resolutionContext = new(resolutionContext._mapper); } - internal TDestination MapInternal(TSource source, TDestination destination, MemberMap memberMap) => - _mapper.Map(source, destination, this, memberMap: memberMap); - internal object Map(object source, object destination, Type sourceType, Type destinationType, MemberMap memberMap) => - _mapper.Map(source, destination, this, sourceType, destinationType, memberMap); - private void CheckDefault() + } + internal TDestination MapInternal(TSource source, TDestination destination, MemberMap memberMap) => + _mapper.Map(source, destination, this, memberMap: memberMap); + internal object Map(object source, object destination, Type sourceType, Type destinationType, MemberMap memberMap) => + _mapper.Map(source, destination, this, sourceType, destinationType, memberMap); + private void CheckDefault() + { + if (IsDefault) { - if (IsDefault) - { - ThrowInvalidMap(); - } + ThrowInvalidMap(); } - private static void ThrowInvalidMap() => throw new InvalidOperationException("Context.Items are only available when using a Map overload that takes Action!"); } - public readonly record struct ContextCacheKey(object Source, Type DestinationType); -} \ No newline at end of file + private static void ThrowInvalidMap() => throw new InvalidOperationException("Context.Items are only available when using a Map overload that takes Action!"); +} +public readonly record struct ContextCacheKey(object Source, Type DestinationType); \ No newline at end of file diff --git a/src/AutoMapper/TypeMap.cs b/src/AutoMapper/TypeMap.cs index 81232282f3..b5985682c8 100644 --- a/src/AutoMapper/TypeMap.cs +++ b/src/AutoMapper/TypeMap.cs @@ -5,500 +5,499 @@ using System.Linq.Expressions; using System.Reflection; using System.ComponentModel; -namespace AutoMapper +namespace AutoMapper; + +using Execution; +using static Expression; +using static Execution.ExpressionBuilder; +using Configuration; +using Features; +using Internal; +/// +/// Main configuration object holding all mapping configuration for a source and destination type +/// +[DebuggerDisplay("{SourceType.Name} -> {DestinationType.Name}")] +[EditorBrowsable(EditorBrowsableState.Never)] +public class TypeMap { - using Execution; - using static Expression; - using static Execution.ExpressionBuilder; - using Configuration; - using Features; - using Internal; - /// - /// Main configuration object holding all mapping configuration for a source and destination type - /// - [DebuggerDisplay("{SourceType.Name} -> {DestinationType.Name}")] - [EditorBrowsable(EditorBrowsableState.Never)] - public class TypeMap + private static readonly MethodInfo CreateProxyMethod = typeof(ObjectFactory).GetStaticMethod(nameof(ObjectFactory.CreateInterfaceProxy)); + private TypeMapDetails _details; + private Dictionary _propertyMaps; + private bool _sealed; + public TypeMap(Type sourceType, Type destinationType, ProfileMap profile, TypeMapConfiguration typeMapConfiguration, List sourceMembers = null) { - private static readonly MethodInfo CreateProxyMethod = typeof(ObjectFactory).GetStaticMethod(nameof(ObjectFactory.CreateInterfaceProxy)); - private TypeMapDetails _details; - private Dictionary _propertyMaps; - private bool _sealed; - public TypeMap(Type sourceType, Type destinationType, ProfileMap profile, TypeMapConfiguration typeMapConfiguration, List sourceMembers = null) + Types = new(sourceType, destinationType); + Profile = profile; + if (typeMapConfiguration?.HasTypeConverter is true) + { + return; + } + SourceTypeDetails = profile.CreateTypeDetails(sourceType); + DestinationTypeDetails = profile.CreateTypeDetails(destinationType); + sourceMembers ??= new(); + var isReverseMap = typeMapConfiguration?.IsReverseMap is true; + foreach (var destinationProperty in DestinationTypeDetails.WriteAccessors) { - Types = new(sourceType, destinationType); - Profile = profile; - if (typeMapConfiguration?.HasTypeConverter is true) + var destinationName = destinationProperty.Name; + var memberConfig = typeMapConfiguration?.GetDestinationMemberConfiguration(destinationProperty); + if (memberConfig?.Ignored is true || profile.GlobalIgnores.Contains(destinationName)) { - return; + continue; } - SourceTypeDetails = profile.CreateTypeDetails(sourceType); - DestinationTypeDetails = profile.CreateTypeDetails(destinationType); - sourceMembers ??= new(); - var isReverseMap = typeMapConfiguration?.IsReverseMap is true; - foreach (var destinationProperty in DestinationTypeDetails.WriteAccessors) + sourceMembers.Clear(); + var propertyType = destinationProperty.GetMemberType(); + if (profile.MapDestinationPropertyToSource(SourceTypeDetails, destinationType, propertyType, destinationName, sourceMembers, isReverseMap)) { - var destinationName = destinationProperty.Name; - var memberConfig = typeMapConfiguration?.GetDestinationMemberConfiguration(destinationProperty); - if (memberConfig?.Ignored is true || profile.GlobalIgnores.Contains(destinationName)) - { - continue; - } - sourceMembers.Clear(); - var propertyType = destinationProperty.GetMemberType(); - if (profile.MapDestinationPropertyToSource(SourceTypeDetails, destinationType, propertyType, destinationName, sourceMembers, isReverseMap)) - { - AddPropertyMap(destinationProperty, propertyType, sourceMembers); - } + AddPropertyMap(destinationProperty, propertyType, sourceMembers); } } - public Features Features => Details.Features; - private TypeMapDetails Details => _details ??= new(); - public void CheckProjection() + } + public Features Features => Details.Features; + private TypeMapDetails Details => _details ??= new(); + public void CheckProjection() + { + if (Projection) { - if (Projection) - { - throw new AutoMapperConfigurationException("CreateProjection works with ProjectTo, not with Map.", MissingMapException(Types)); - } + throw new AutoMapperConfigurationException("CreateProjection works with ProjectTo, not with Map.", MissingMapException(Types)); } - public static Exception MissingMapException(TypePair types) => MissingMapException(types.SourceType, types.DestinationType); - public static Exception MissingMapException(Type sourceType, Type destinationType) - => new InvalidOperationException($"Missing map from {sourceType} to {destinationType}. Create using CreateMap<{sourceType.Name}, {destinationType.Name}>."); - public bool Projection { get; set; } - public LambdaExpression MapExpression { get; private set; } - public Expression Invoke(Expression source, Expression destination) => - Expression.Invoke(MapExpression, ToType(source, SourceType), ToType(destination, DestinationType), ContextParameter); - internal bool CanConstructorMap() => Profile.ConstructorMappingEnabled && !DestinationType.IsAbstract && - !CustomConstruction && !HasTypeConverter && DestinationConstructors.Length > 0; - public TypePair Types; - public ConstructorMap ConstructorMap { get; set; } - public TypeDetails SourceTypeDetails { get; private set; } - private TypeDetails DestinationTypeDetails { get; set; } - public Type SourceType => Types.SourceType; - public Type DestinationType => Types.DestinationType; - public ProfileMap Profile { get; } - public LambdaExpression CustomMapExpression => TypeConverter?.ProjectToExpression; - public LambdaExpression CustomCtorFunction { get => _details?.CustomCtorFunction; set => Details.CustomCtorFunction = value; } - public LambdaExpression CustomCtorExpression => CustomCtorFunction?.Parameters.Count == 1 ? CustomCtorFunction : null; - public bool IncludeAllDerivedTypes { get => (_details?.IncludeAllDerivedTypes).GetValueOrDefault(); set => Details.IncludeAllDerivedTypes = value; } - public MemberList ConfiguredMemberList + } + public static Exception MissingMapException(TypePair types) => MissingMapException(types.SourceType, types.DestinationType); + public static Exception MissingMapException(Type sourceType, Type destinationType) + => new InvalidOperationException($"Missing map from {sourceType} to {destinationType}. Create using CreateMap<{sourceType.Name}, {destinationType.Name}>."); + public bool Projection { get; set; } + public LambdaExpression MapExpression { get; private set; } + public Expression Invoke(Expression source, Expression destination) => + Expression.Invoke(MapExpression, ToType(source, SourceType), ToType(destination, DestinationType), ContextParameter); + internal bool CanConstructorMap() => Profile.ConstructorMappingEnabled && !DestinationType.IsAbstract && + !CustomConstruction && !HasTypeConverter && DestinationConstructors.Length > 0; + public TypePair Types; + public ConstructorMap ConstructorMap { get; set; } + public TypeDetails SourceTypeDetails { get; private set; } + private TypeDetails DestinationTypeDetails { get; set; } + public Type SourceType => Types.SourceType; + public Type DestinationType => Types.DestinationType; + public ProfileMap Profile { get; } + public LambdaExpression CustomMapExpression => TypeConverter?.ProjectToExpression; + public LambdaExpression CustomCtorFunction { get => _details?.CustomCtorFunction; set => Details.CustomCtorFunction = value; } + public LambdaExpression CustomCtorExpression => CustomCtorFunction?.Parameters.Count == 1 ? CustomCtorFunction : null; + public bool IncludeAllDerivedTypes { get => (_details?.IncludeAllDerivedTypes).GetValueOrDefault(); set => Details.IncludeAllDerivedTypes = value; } + public MemberList ConfiguredMemberList + { + get => (_details?.ConfiguredMemberList).GetValueOrDefault(); + set { - get => (_details?.ConfiguredMemberList).GetValueOrDefault(); - set + if (value == default) { - if (value == default) - { - return; - } - Details.ConfiguredMemberList = value; + return; } + Details.ConfiguredMemberList = value; } - public IReadOnlyCollection IncludedDerivedTypes => (_details?.IncludedDerivedTypes).NullCheck(); - public IReadOnlyCollection IncludedBaseTypes => (_details?.IncludedBaseTypes).NullCheck(); - public IReadOnlyCollection BeforeMapActions => (_details?.BeforeMapActions).NullCheck(); - public IReadOnlyCollection AfterMapActions => (_details?.AfterMapActions).NullCheck(); - public IReadOnlyCollection ValueTransformers => (_details?.ValueTransformerConfigs).NullCheck(); - public bool PreserveReferences { get => (_details?.PreserveReferences).GetValueOrDefault(); set => Details.PreserveReferences = value; } - public int MaxDepth { get => (_details?.MaxDepth).GetValueOrDefault(); set => Details.MaxDepth = value; } - public bool DisableConstructorValidation { get => (_details?.DisableConstructorValidation).GetValueOrDefault(); set => Details.DisableConstructorValidation = value; } - public IReadOnlyCollection PropertyMaps => (_propertyMaps?.Values).NullCheck(); - public IReadOnlyCollection PathMaps => (_details?.PathMaps?.Values).NullCheck(); - public IEnumerable MemberMaps + } + public IReadOnlyCollection IncludedDerivedTypes => (_details?.IncludedDerivedTypes).NullCheck(); + public IReadOnlyCollection IncludedBaseTypes => (_details?.IncludedBaseTypes).NullCheck(); + public IReadOnlyCollection BeforeMapActions => (_details?.BeforeMapActions).NullCheck(); + public IReadOnlyCollection AfterMapActions => (_details?.AfterMapActions).NullCheck(); + public IReadOnlyCollection ValueTransformers => (_details?.ValueTransformerConfigs).NullCheck(); + public bool PreserveReferences { get => (_details?.PreserveReferences).GetValueOrDefault(); set => Details.PreserveReferences = value; } + public int MaxDepth { get => (_details?.MaxDepth).GetValueOrDefault(); set => Details.MaxDepth = value; } + public bool DisableConstructorValidation { get => (_details?.DisableConstructorValidation).GetValueOrDefault(); set => Details.DisableConstructorValidation = value; } + public IReadOnlyCollection PropertyMaps => (_propertyMaps?.Values).NullCheck(); + public IReadOnlyCollection PathMaps => (_details?.PathMaps?.Values).NullCheck(); + public IEnumerable MemberMaps + { + get { - get + var maps = PropertyMaps.Concat((IReadOnlyCollection)PathMaps); + if (ConstructorMapping) { - var maps = PropertyMaps.Concat((IReadOnlyCollection)PathMaps); - if (ConstructorMapping) - { - maps = maps.Concat(ConstructorMap.CtorParams); - } - return maps; + maps = maps.Concat(ConstructorMap.CtorParams); } + return maps; } - public bool PassesCtorValidation => - DisableConstructorValidation - || CustomConstruction - || ConstructorMapping - || DestinationType.IsAbstract - || DestinationType.IsGenericTypeDefinition - || DestinationType.IsValueType - || TypeDetails.GetConstructors(DestinationType, Profile).Any(c => c.AllParametersOptional()); - public MemberInfo[] DestinationSetters => DestinationTypeDetails.WriteAccessors; - public ConstructorParameters[] DestinationConstructors => DestinationTypeDetails.Constructors; - public bool ConstructorMapping => ConstructorMap is { CanResolve: true }; - public bool CustomConstruction => CustomCtorFunction != null; - public bool HasTypeConverter => TypeConverter != null; - public TypeConverter TypeConverter { get; set; } - public bool ShouldCheckForValid => ConfiguredMemberList != MemberList.None && !HasTypeConverter; - public LambdaExpression[] IncludedMembers { get => _details?.IncludedMembers ?? Array.Empty(); set => Details.IncludedMembers = value; } - public string[] IncludedMembersNames { get => _details?.IncludedMembersNames ?? Array.Empty(); set => Details.IncludedMembersNames = value; } - public IReadOnlyCollection IncludedMembersTypeMaps => (_details?.IncludedMembersTypeMaps).NullCheck(); - public Type MakeGenericType(Type type) => type.IsGenericTypeDefinition ? - type.MakeGenericType(SourceType.GenericTypeArguments.Concat(DestinationType.GenericTypeArguments).Take(type.GenericParametersCount()).ToArray()) : - type; - public bool HasIncludedMembers => IncludedMembers.Length > 0 || IncludedMembersNames.Length > 0; - public IEnumerable GetAllIncludedMembers() => IncludedMembersNames.Length == 0 || SourceType.ContainsGenericParameters ? - IncludedMembers : IncludedMembers.Concat(IncludedMembersNames.Select(name => MemberAccessLambda(SourceType, name, this))); - public bool ConstructorParameterMatches(string destinationPropertyName) => ConstructorMapping && ConstructorMap[destinationPropertyName] != null; - private void AddPropertyMap(MemberInfo destProperty, Type destinationPropertyType, List sourceMembers) + } + public bool PassesCtorValidation => + DisableConstructorValidation + || CustomConstruction + || ConstructorMapping + || DestinationType.IsAbstract + || DestinationType.IsGenericTypeDefinition + || DestinationType.IsValueType + || TypeDetails.GetConstructors(DestinationType, Profile).Any(c => c.AllParametersOptional()); + public MemberInfo[] DestinationSetters => DestinationTypeDetails.WriteAccessors; + public ConstructorParameters[] DestinationConstructors => DestinationTypeDetails.Constructors; + public bool ConstructorMapping => ConstructorMap is { CanResolve: true }; + public bool CustomConstruction => CustomCtorFunction != null; + public bool HasTypeConverter => TypeConverter != null; + public TypeConverter TypeConverter { get; set; } + public bool ShouldCheckForValid => ConfiguredMemberList != MemberList.None && !HasTypeConverter; + public LambdaExpression[] IncludedMembers { get => _details?.IncludedMembers ?? Array.Empty(); set => Details.IncludedMembers = value; } + public string[] IncludedMembersNames { get => _details?.IncludedMembersNames ?? Array.Empty(); set => Details.IncludedMembersNames = value; } + public IReadOnlyCollection IncludedMembersTypeMaps => (_details?.IncludedMembersTypeMaps).NullCheck(); + public Type MakeGenericType(Type type) => type.IsGenericTypeDefinition ? + type.MakeGenericType(SourceType.GenericTypeArguments.Concat(DestinationType.GenericTypeArguments).Take(type.GenericParametersCount()).ToArray()) : + type; + public bool HasIncludedMembers => IncludedMembers.Length > 0 || IncludedMembersNames.Length > 0; + public IEnumerable GetAllIncludedMembers() => IncludedMembersNames.Length == 0 || SourceType.ContainsGenericParameters ? + IncludedMembers : IncludedMembers.Concat(IncludedMembersNames.Select(name => MemberAccessLambda(SourceType, name, this))); + public bool ConstructorParameterMatches(string destinationPropertyName) => ConstructorMapping && ConstructorMap[destinationPropertyName] != null; + private void AddPropertyMap(MemberInfo destProperty, Type destinationPropertyType, List sourceMembers) + { + var propertyMap = new PropertyMap(destProperty, destinationPropertyType, this); + propertyMap.MapByConvention(sourceMembers.ToArray()); + AddPropertyMap(propertyMap); + } + private void AddPropertyMap(PropertyMap propertyMap) + { + _propertyMaps ??= new(); + _propertyMaps.Add(propertyMap.DestinationName, propertyMap); + } + public string[] GetUnmappedPropertyNames() + { + IEnumerable properties; + if (ConfiguredMemberList == MemberList.Destination) { - var propertyMap = new PropertyMap(destProperty, destinationPropertyType, this); - propertyMap.MapByConvention(sourceMembers.ToArray()); - AddPropertyMap(propertyMap); + properties = Profile.CreateTypeDetails(DestinationType).WriteAccessors + .Select(p => p.Name) + .Where(p => !ConstructorParameterMatches(p)) + .Except(MappedMembers().Select(m => m.DestinationName)) + .Except(PathMaps.Select(p => p.MemberPath.First.Name)); } - private void AddPropertyMap(PropertyMap propertyMap) + else { - _propertyMaps ??= new(); - _propertyMaps.Add(propertyMap.DestinationName, propertyMap); + var ignoredSourceMembers = _details?.SourceMemberConfigs?.Values + .Where(smc => smc.IsIgnored()) + .Select(pm => pm.SourceMember.Name); + properties = Profile.CreateTypeDetails(SourceType).ReadAccessors + .Select(p => p.Name) + .Except(MappedMembers().Select(m => m.GetSourceMemberName())) + .Except(IncludedMembersNames) + .Except(IncludedMembers.Select(m => m.GetMember()?.Name)) + .Except(ignoredSourceMembers ?? Array.Empty()); } - public string[] GetUnmappedPropertyNames() + return properties.Where(memberName => !Profile.GlobalIgnores.Any(memberName.StartsWith)).ToArray(); + IEnumerable MappedMembers() => MemberMaps.Where(pm => pm.IsMapped); + } + public PropertyMap FindOrCreatePropertyMapFor(MemberInfo destinationProperty, Type destinationPropertyType) + { + var propertyMap = GetPropertyMap(destinationProperty.Name); + if (propertyMap != null) return propertyMap; + + propertyMap = new(destinationProperty, destinationPropertyType, this); + + AddPropertyMap(propertyMap); + return propertyMap; + } + private void CheckDifferent(TypePair types) + { + if (types == Types) { - IEnumerable properties; - if (ConfiguredMemberList == MemberList.Destination) - { - properties = Profile.CreateTypeDetails(DestinationType).WriteAccessors - .Select(p => p.Name) - .Where(p => !ConstructorParameterMatches(p)) - .Except(MappedMembers().Select(m => m.DestinationName)) - .Except(PathMaps.Select(p => p.MemberPath.First.Name)); - } - else - { - var ignoredSourceMembers = _details?.SourceMemberConfigs?.Values - .Where(smc => smc.IsIgnored()) - .Select(pm => pm.SourceMember.Name); - properties = Profile.CreateTypeDetails(SourceType).ReadAccessors - .Select(p => p.Name) - .Except(MappedMembers().Select(m => m.GetSourceMemberName())) - .Except(IncludedMembersNames) - .Except(IncludedMembers.Select(m => m.GetMember()?.Name)) - .Except(ignoredSourceMembers ?? Array.Empty()); - } - return properties.Where(memberName => !Profile.GlobalIgnores.Any(memberName.StartsWith)).ToArray(); - IEnumerable MappedMembers() => MemberMaps.Where(pm => pm.IsMapped); + throw new InvalidOperationException($"You cannot include a type map into itself.{Environment.NewLine}Source type: {types.SourceType.FullName}{Environment.NewLine}Destination type: {types.DestinationType.FullName}"); } - public PropertyMap FindOrCreatePropertyMapFor(MemberInfo destinationProperty, Type destinationPropertyType) + } + internal void IgnorePaths(MemberInfo destinationMember) + { + foreach (var pathMap in PathMaps.Where(pm => pm.MemberPath.First == destinationMember)) { - var propertyMap = GetPropertyMap(destinationProperty.Name); - if (propertyMap != null) return propertyMap; - - propertyMap = new(destinationProperty, destinationPropertyType, this); - - AddPropertyMap(propertyMap); - return propertyMap; + pathMap.Ignored = true; } - private void CheckDifferent(TypePair types) + } + public bool HasDerivedTypesToInclude => IncludedDerivedTypes.Count > 0; + public void Seal(IGlobalConfiguration configuration) + { + if (_sealed) { - if (types == Types) - { - throw new InvalidOperationException($"You cannot include a type map into itself.{Environment.NewLine}Source type: {types.SourceType.FullName}{Environment.NewLine}Destination type: {types.DestinationType.FullName}"); - } + return; } - internal void IgnorePaths(MemberInfo destinationMember) + _sealed = true; + _details?.Seal(configuration, this); + if (!Projection) { - foreach (var pathMap in PathMaps.Where(pm => pm.MemberPath.First == destinationMember)) - { - pathMap.Ignored = true; - } + MapExpression = CreateMapperLambda(configuration); + } + SourceTypeDetails = null; + DestinationTypeDetails = null; + } + public IEnumerable OrderedPropertyMaps() + { + if (HasMappingOrder()) + { + return PropertyMaps.OrderBy(map => map.MappingOrder); + } + else + { + return PropertyMaps; } - public bool HasDerivedTypesToInclude => IncludedDerivedTypes.Count > 0; - public void Seal(IGlobalConfiguration configuration) + bool HasMappingOrder() { - if (_sealed) + if (_propertyMaps == null) { - return; + return false; } - _sealed = true; - _details?.Seal(configuration, this); - if (!Projection) + foreach (var propertyMap in _propertyMaps.Values) { - MapExpression = CreateMapperLambda(configuration); + if (propertyMap.MappingOrder != null) + { + return true; + } } - SourceTypeDetails = null; - DestinationTypeDetails = null; + return false; } - public IEnumerable OrderedPropertyMaps() + } + public void IncludeDerivedTypes(TypePair derivedTypes) + { + CheckDifferent(derivedTypes); + Details.IncludeDerivedTypes(derivedTypes); + } + public void IncludeBaseTypes(TypePair baseTypes) + { + CheckDifferent(baseTypes); + Details.IncludeBaseTypes(baseTypes); + } + public void AddBeforeMapAction(LambdaExpression beforeMap) => Details.AddBeforeMapAction(beforeMap); + public void AddAfterMapAction(LambdaExpression afterMap) => Details.AddAfterMapAction(afterMap); + public void AddValueTransformation(ValueTransformerConfiguration config) => Details.AddValueTransformation(config); + public void ConstructUsingServiceLocator() => CustomCtorFunction = Lambda(ServiceLocator(DestinationType)); + internal LambdaExpression CreateMapperLambda(IGlobalConfiguration configuration) => + Types.ContainsGenericParameters ? null : new TypeMapPlanBuilder(configuration, this).CreateMapperLambda(); + private PropertyMap GetPropertyMap(string name) => _propertyMaps?.GetValueOrDefault(name); + private PropertyMap GetPropertyMap(PropertyMap propertyMap) => GetPropertyMap(propertyMap.DestinationName); + public void AsProxy() => CustomCtorFunction = Lambda(Call(CreateProxyMethod, Constant(DestinationType))); + internal void CopyInheritedMapsTo(TypeMap typeMap) + { + if (_details?.InheritedTypeMaps == null) { - if (HasMappingOrder()) - { - return PropertyMaps.OrderBy(map => map.MappingOrder); - } - else + return; + } + _details.CopyInheritedMapsTo(typeMap); + } + public void CloseGenerics(TypeMapConfiguration openMapConfig, TypePair closedTypes) => TypeConverter?.CloseGenerics(openMapConfig, closedTypes); + public bool AddMemberMap(IncludedMember includedMember) => Details.AddMemberMap(includedMember); + public PathMap FindOrCreatePathMapFor(LambdaExpression destinationExpression, MemberPath path, TypeMap typeMap) => + Details.FindOrCreatePathMapFor(destinationExpression, path, typeMap); + public bool AddInheritedMap(TypeMap inheritedTypeMap) => Details.AddInheritedMap(inheritedTypeMap); + public SourceMemberConfig FindOrCreateSourceMemberConfigFor(MemberInfo sourceMember) => Details.FindOrCreateSourceMemberConfigFor(sourceMember); + class TypeMapDetails + { + Features _features; + public bool PreserveReferences; + public LambdaExpression[] IncludedMembers; + public string[] IncludedMembersNames; + public bool DisableConstructorValidation; + public int MaxDepth; + public bool IncludeAllDerivedTypes; + public LambdaExpression CustomCtorFunction; + public MemberList ConfiguredMemberList; + public HashSet AfterMapActions { get; private set; } + public HashSet BeforeMapActions { get; private set; } + public HashSet IncludedDerivedTypes { get; private set; } + public HashSet IncludedBaseTypes { get; private set; } + public Dictionary PathMaps { get; private set; } + public Dictionary SourceMemberConfigs { get; private set; } + public HashSet InheritedTypeMaps { get; private set; } + public HashSet IncludedMembersTypeMaps { get; private set; } + public List ValueTransformerConfigs { get; private set; } + public Features Features => _features ??= new(); + public void Seal(IGlobalConfiguration configuration, TypeMap thisMap) + { + if (InheritedTypeMaps != null) { - return PropertyMaps; + foreach (var inheritedTypeMap in InheritedTypeMaps) + { + var includedMaps = inheritedTypeMap?._details?.IncludedMembersTypeMaps; + if (includedMaps != null) + { + IncludedMembersTypeMaps ??= new(); + IncludedMembersTypeMaps.UnionWith(includedMaps); + } + } } - bool HasMappingOrder() + if (IncludedMembersTypeMaps != null) { - if (_propertyMaps == null) + foreach (var includedMemberTypeMap in IncludedMembersTypeMaps) { - return false; + includedMemberTypeMap.TypeMap.Seal(configuration); + ApplyIncludedMemberTypeMap(includedMemberTypeMap, thisMap); } - foreach (var propertyMap in _propertyMaps.Values) + } + if (InheritedTypeMaps != null) + { + foreach (var inheritedTypeMap in InheritedTypeMaps) { - if (propertyMap.MappingOrder != null) - { - return true; - } + ApplyInheritedTypeMap(inheritedTypeMap, thisMap); } - return false; } + _features?.Seal(configuration); } public void IncludeDerivedTypes(TypePair derivedTypes) { - CheckDifferent(derivedTypes); - Details.IncludeDerivedTypes(derivedTypes); + IncludedDerivedTypes ??= new(); + IncludedDerivedTypes.Add(derivedTypes); + } + public void AddBeforeMapAction(LambdaExpression beforeMap) + { + BeforeMapActions ??= new(); + BeforeMapActions.Add(beforeMap); + } + public void AddAfterMapAction(LambdaExpression afterMap) + { + AfterMapActions ??= new(); + AfterMapActions.Add(afterMap); + } + public void AddValueTransformation(ValueTransformerConfiguration valueTransformerConfiguration) + { + ValueTransformerConfigs ??= new(); + ValueTransformerConfigs.Add(valueTransformerConfiguration); + } + public PathMap FindOrCreatePathMapFor(LambdaExpression destinationExpression, MemberPath path, TypeMap typeMap) + { + PathMaps ??= new(); + var pathMap = PathMaps.GetValueOrDefault(path); + if (pathMap == null) + { + pathMap = new(destinationExpression, path, typeMap); + AddPathMap(pathMap); + } + return pathMap; } + private void AddPathMap(PathMap pathMap) => PathMaps.Add(pathMap.MemberPath, pathMap); public void IncludeBaseTypes(TypePair baseTypes) { - CheckDifferent(baseTypes); - Details.IncludeBaseTypes(baseTypes); + IncludedBaseTypes ??= new(); + IncludedBaseTypes.Add(baseTypes); } - public void AddBeforeMapAction(LambdaExpression beforeMap) => Details.AddBeforeMapAction(beforeMap); - public void AddAfterMapAction(LambdaExpression afterMap) => Details.AddAfterMapAction(afterMap); - public void AddValueTransformation(ValueTransformerConfiguration config) => Details.AddValueTransformation(config); - public void ConstructUsingServiceLocator() => CustomCtorFunction = Lambda(ServiceLocator(DestinationType)); - internal LambdaExpression CreateMapperLambda(IGlobalConfiguration configuration) => - Types.ContainsGenericParameters ? null : new TypeMapPlanBuilder(configuration, this).CreateMapperLambda(); - private PropertyMap GetPropertyMap(string name) => _propertyMaps?.GetValueOrDefault(name); - private PropertyMap GetPropertyMap(PropertyMap propertyMap) => GetPropertyMap(propertyMap.DestinationName); - public void AsProxy() => CustomCtorFunction = Lambda(Call(CreateProxyMethod, Constant(DestinationType))); internal void CopyInheritedMapsTo(TypeMap typeMap) { - if (_details?.InheritedTypeMaps == null) + typeMap.Details.InheritedTypeMaps ??= new(); + typeMap._details.InheritedTypeMaps.UnionWith(InheritedTypeMaps); + } + public bool AddMemberMap(IncludedMember includedMember) + { + IncludedMembersTypeMaps ??= new(); + return IncludedMembersTypeMaps.Add(includedMember); + } + public SourceMemberConfig FindOrCreateSourceMemberConfigFor(MemberInfo sourceMember) + { + SourceMemberConfigs ??= new(); + var config = SourceMemberConfigs.GetValueOrDefault(sourceMember); + + if (config != null) return config; + + config = new(sourceMember); + SourceMemberConfigs.Add(config.SourceMember, config); + return config; + } + public bool AddInheritedMap(TypeMap inheritedTypeMap) + { + InheritedTypeMaps ??= new(); + return InheritedTypeMaps.Add(inheritedTypeMap); + } + private void ApplyIncludedMemberTypeMap(IncludedMember includedMember, TypeMap thisMap) + { + var typeMap = includedMember.TypeMap; + var includedMemberMaps = typeMap.PropertyMaps. + Where(m => m.CanResolveValue && thisMap.GetPropertyMap(m) == null) + .Select(p => new PropertyMap(p, thisMap, includedMember)) + .ToArray(); + var notOverridenPathMaps = NotOverridenPathMaps(typeMap); + var appliedConstructorMap = thisMap.ConstructorMap?.ApplyIncludedMember(includedMember); + if (includedMemberMaps.Length == 0 && notOverridenPathMaps.Length == 0 && appliedConstructorMap is not true) { return; } - _details.CopyInheritedMapsTo(typeMap); - } - public void CloseGenerics(TypeMapConfiguration openMapConfig, TypePair closedTypes) => TypeConverter?.CloseGenerics(openMapConfig, closedTypes); - public bool AddMemberMap(IncludedMember includedMember) => Details.AddMemberMap(includedMember); - public PathMap FindOrCreatePathMapFor(LambdaExpression destinationExpression, MemberPath path, TypeMap typeMap) => - Details.FindOrCreatePathMapFor(destinationExpression, path, typeMap); - public bool AddInheritedMap(TypeMap inheritedTypeMap) => Details.AddInheritedMap(inheritedTypeMap); - public SourceMemberConfig FindOrCreateSourceMemberConfigFor(MemberInfo sourceMember) => Details.FindOrCreateSourceMemberConfigFor(sourceMember); - class TypeMapDetails - { - Features _features; - public bool PreserveReferences; - public LambdaExpression[] IncludedMembers; - public string[] IncludedMembersNames; - public bool DisableConstructorValidation; - public int MaxDepth; - public bool IncludeAllDerivedTypes; - public LambdaExpression CustomCtorFunction; - public MemberList ConfiguredMemberList; - public HashSet AfterMapActions { get; private set; } - public HashSet BeforeMapActions { get; private set; } - public HashSet IncludedDerivedTypes { get; private set; } - public HashSet IncludedBaseTypes { get; private set; } - public Dictionary PathMaps { get; private set; } - public Dictionary SourceMemberConfigs { get; private set; } - public HashSet InheritedTypeMaps { get; private set; } - public HashSet IncludedMembersTypeMaps { get; private set; } - public List ValueTransformerConfigs { get; private set; } - public Features Features => _features ??= new(); - public void Seal(IGlobalConfiguration configuration, TypeMap thisMap) + foreach (var includedMemberMap in includedMemberMaps) { - if (InheritedTypeMaps != null) - { - foreach (var inheritedTypeMap in InheritedTypeMaps) - { - var includedMaps = inheritedTypeMap?._details?.IncludedMembersTypeMaps; - if (includedMaps != null) - { - IncludedMembersTypeMaps ??= new(); - IncludedMembersTypeMaps.UnionWith(includedMaps); - } - } - } - if (IncludedMembersTypeMaps != null) + thisMap.AddPropertyMap(includedMemberMap); + foreach (var transformer in typeMap.ValueTransformers) { - foreach (var includedMemberTypeMap in IncludedMembersTypeMaps) - { - includedMemberTypeMap.TypeMap.Seal(configuration); - ApplyIncludedMemberTypeMap(includedMemberTypeMap, thisMap); - } - } - if (InheritedTypeMaps != null) - { - foreach (var inheritedTypeMap in InheritedTypeMaps) - { - ApplyInheritedTypeMap(inheritedTypeMap, thisMap); - } + includedMemberMap.AddValueTransformation(transformer); } - _features?.Seal(configuration); } - public void IncludeDerivedTypes(TypePair derivedTypes) + var details = typeMap._details; + if (details != null) { - IncludedDerivedTypes ??= new(); - IncludedDerivedTypes.Add(derivedTypes); + ApplyInheritedMapActions(details.BeforeMapActions?.Select(includedMember.Chain), details.AfterMapActions?.Select(includedMember.Chain)); } - public void AddBeforeMapAction(LambdaExpression beforeMap) + foreach (var notOverridenPathMap in notOverridenPathMaps) { - BeforeMapActions ??= new(); - BeforeMapActions.Add(beforeMap); + AddPathMap(new(notOverridenPathMap, thisMap, includedMember)); } - public void AddAfterMapAction(LambdaExpression afterMap) - { - AfterMapActions ??= new(); - AfterMapActions.Add(afterMap); - } - public void AddValueTransformation(ValueTransformerConfiguration valueTransformerConfiguration) - { - ValueTransformerConfigs ??= new(); - ValueTransformerConfigs.Add(valueTransformerConfiguration); - } - public PathMap FindOrCreatePathMapFor(LambdaExpression destinationExpression, MemberPath path, TypeMap typeMap) + } + private void ApplyInheritedTypeMap(TypeMap inheritedTypeMap, TypeMap thisMap) + { + if (inheritedTypeMap._propertyMaps != null) { - PathMaps ??= new(); - var pathMap = PathMaps.GetValueOrDefault(path); - if (pathMap == null) - { - pathMap = new(destinationExpression, path, typeMap); - AddPathMap(pathMap); - } - return pathMap; + ApplyInheritedPropertyMaps(inheritedTypeMap, thisMap); } - private void AddPathMap(PathMap pathMap) => PathMaps.Add(pathMap.MemberPath, pathMap); - public void IncludeBaseTypes(TypePair baseTypes) + var inheritedDetails = inheritedTypeMap._details; + if (inheritedDetails == null) { - IncludedBaseTypes ??= new(); - IncludedBaseTypes.Add(baseTypes); + return; } - internal void CopyInheritedMapsTo(TypeMap typeMap) + ApplyInheritedMapActions(inheritedDetails.BeforeMapActions, inheritedDetails.AfterMapActions); + if (inheritedDetails.SourceMemberConfigs != null) { - typeMap.Details.InheritedTypeMaps ??= new(); - typeMap._details.InheritedTypeMaps.UnionWith(InheritedTypeMaps); + ApplyInheritedSourceMembers(inheritedTypeMap._details); } - public bool AddMemberMap(IncludedMember includedMember) + var notOverridenPathMaps = NotOverridenPathMaps(inheritedTypeMap); + foreach (var notOverridenPathMap in notOverridenPathMaps) { - IncludedMembersTypeMaps ??= new(); - return IncludedMembersTypeMaps.Add(includedMember); + AddPathMap(notOverridenPathMap); } - public SourceMemberConfig FindOrCreateSourceMemberConfigFor(MemberInfo sourceMember) + if (inheritedDetails.ValueTransformerConfigs != null) { - SourceMemberConfigs ??= new(); - var config = SourceMemberConfigs.GetValueOrDefault(sourceMember); - - if (config != null) return config; - - config = new(sourceMember); - SourceMemberConfigs.Add(config.SourceMember, config); - return config; - } - public bool AddInheritedMap(TypeMap inheritedTypeMap) - { - InheritedTypeMaps ??= new(); - return InheritedTypeMaps.Add(inheritedTypeMap); + ValueTransformerConfigs ??= new(); + ValueTransformerConfigs.InsertRange(0, inheritedDetails.ValueTransformerConfigs); } - private void ApplyIncludedMemberTypeMap(IncludedMember includedMember, TypeMap thisMap) + return; + void ApplyInheritedPropertyMaps(TypeMap inheritedTypeMap, TypeMap thisMap) { - var typeMap = includedMember.TypeMap; - var includedMemberMaps = typeMap.PropertyMaps. - Where(m => m.CanResolveValue && thisMap.GetPropertyMap(m) == null) - .Select(p => new PropertyMap(p, thisMap, includedMember)) - .ToArray(); - var notOverridenPathMaps = NotOverridenPathMaps(typeMap); - var appliedConstructorMap = thisMap.ConstructorMap?.ApplyIncludedMember(includedMember); - if (includedMemberMaps.Length == 0 && notOverridenPathMaps.Length == 0 && appliedConstructorMap is not true) + foreach (var inheritedMappedProperty in inheritedTypeMap._propertyMaps.Values) { - return; - } - foreach (var includedMemberMap in includedMemberMaps) - { - thisMap.AddPropertyMap(includedMemberMap); - foreach (var transformer in typeMap.ValueTransformers) + if (!inheritedMappedProperty.IsMapped) { - includedMemberMap.AddValueTransformation(transformer); + continue; } - } - var details = typeMap._details; - if (details != null) - { - ApplyInheritedMapActions(details.BeforeMapActions?.Select(includedMember.Chain), details.AfterMapActions?.Select(includedMember.Chain)); - } - foreach (var notOverridenPathMap in notOverridenPathMaps) - { - AddPathMap(new(notOverridenPathMap, thisMap, includedMember)); - } - } - private void ApplyInheritedTypeMap(TypeMap inheritedTypeMap, TypeMap thisMap) - { - if (inheritedTypeMap._propertyMaps != null) - { - ApplyInheritedPropertyMaps(inheritedTypeMap, thisMap); - } - var inheritedDetails = inheritedTypeMap._details; - if (inheritedDetails == null) - { - return; - } - ApplyInheritedMapActions(inheritedDetails.BeforeMapActions, inheritedDetails.AfterMapActions); - if (inheritedDetails.SourceMemberConfigs != null) - { - ApplyInheritedSourceMembers(inheritedTypeMap._details); - } - var notOverridenPathMaps = NotOverridenPathMaps(inheritedTypeMap); - foreach (var notOverridenPathMap in notOverridenPathMaps) - { - AddPathMap(notOverridenPathMap); - } - if (inheritedDetails.ValueTransformerConfigs != null) - { - ValueTransformerConfigs ??= new(); - ValueTransformerConfigs.InsertRange(0, inheritedDetails.ValueTransformerConfigs); - } - return; - void ApplyInheritedPropertyMaps(TypeMap inheritedTypeMap, TypeMap thisMap) - { - foreach (var inheritedMappedProperty in inheritedTypeMap._propertyMaps.Values) + var conventionPropertyMap = thisMap.GetPropertyMap(inheritedMappedProperty); + if (conventionPropertyMap != null) { - if (!inheritedMappedProperty.IsMapped) - { - continue; - } - var conventionPropertyMap = thisMap.GetPropertyMap(inheritedMappedProperty); - if (conventionPropertyMap != null) - { - conventionPropertyMap.ApplyInheritedPropertyMap(inheritedMappedProperty); - } - else - { - thisMap.AddPropertyMap(new(inheritedMappedProperty, thisMap)); - } + conventionPropertyMap.ApplyInheritedPropertyMap(inheritedMappedProperty); } - } - void ApplyInheritedSourceMembers(TypeMapDetails inheritedTypeMap) - { - SourceMemberConfigs ??= new(); - foreach (var inheritedSourceConfig in inheritedTypeMap.SourceMemberConfigs.Values) + else { - SourceMemberConfigs.TryAdd(inheritedSourceConfig.SourceMember, inheritedSourceConfig); + thisMap.AddPropertyMap(new(inheritedMappedProperty, thisMap)); } } } - void ApplyInheritedMapActions(IEnumerable beforeMap, IEnumerable afterMap) + void ApplyInheritedSourceMembers(TypeMapDetails inheritedTypeMap) { - if (beforeMap != null) - { - BeforeMapActions ??= new(); - BeforeMapActions.UnionWith(beforeMap); - } - if (afterMap != null) + SourceMemberConfigs ??= new(); + foreach (var inheritedSourceConfig in inheritedTypeMap.SourceMemberConfigs.Values) { - AfterMapActions ??= new(); - AfterMapActions.UnionWith(afterMap); + SourceMemberConfigs.TryAdd(inheritedSourceConfig.SourceMember, inheritedSourceConfig); } } - private PathMap[] NotOverridenPathMaps(TypeMap inheritedTypeMap) + } + void ApplyInheritedMapActions(IEnumerable beforeMap, IEnumerable afterMap) + { + if (beforeMap != null) + { + BeforeMapActions ??= new(); + BeforeMapActions.UnionWith(beforeMap); + } + if (afterMap != null) { - if (inheritedTypeMap.PathMaps.Count == 0) - { - return Array.Empty(); - } - PathMaps ??= new(); - return inheritedTypeMap.PathMaps.Where(baseConfig => !PathMaps.ContainsKey(baseConfig.MemberPath)).ToArray(); + AfterMapActions ??= new(); + AfterMapActions.UnionWith(afterMap); + } + } + private PathMap[] NotOverridenPathMaps(TypeMap inheritedTypeMap) + { + if (inheritedTypeMap.PathMaps.Count == 0) + { + return Array.Empty(); } + PathMaps ??= new(); + return inheritedTypeMap.PathMaps.Where(baseConfig => !PathMaps.ContainsKey(baseConfig.MemberPath)).ToArray(); } } } \ No newline at end of file diff --git a/src/Benchmark/BenchEngine.cs b/src/Benchmark/BenchEngine.cs index 887f8a137f..bf8d2b49b2 100644 --- a/src/Benchmark/BenchEngine.cs +++ b/src/Benchmark/BenchEngine.cs @@ -1,34 +1,33 @@ using System; using System.Diagnostics; -namespace Benchmark +namespace Benchmark; + +public class BenchEngine { - public class BenchEngine - { - private readonly IObjectToObjectMapper _mapper; - private readonly string _mode; + private readonly IObjectToObjectMapper _mapper; + private readonly string _mode; - public BenchEngine(IObjectToObjectMapper mapper, string mode) - { - _mapper = mapper; - _mode = mode; - } + public BenchEngine(IObjectToObjectMapper mapper, string mode) + { + _mapper = mapper; + _mode = mode; + } - public void Start() - { - _mapper.Initialize(); - //_mapper.Map(); + public void Start() + { + _mapper.Initialize(); + //_mapper.Map(); - //var timer = Stopwatch.StartNew(); + //var timer = Stopwatch.StartNew(); - //for (int i = 0; i < 1_000_000; i++) - //{ - // _mapper.Map(); - //} + //for (int i = 0; i < 1_000_000; i++) + //{ + // _mapper.Map(); + //} - //timer.Stop(); + //timer.Stop(); - //Console.WriteLine("{2:D3} ms {0}: - {1}", _mapper.Name, _mode, (int)timer.Elapsed.TotalMilliseconds); - } + //Console.WriteLine("{2:D3} ms {0}: - {1}", _mapper.Name, _mode, (int)timer.Elapsed.TotalMilliseconds); } } \ No newline at end of file diff --git a/src/Benchmark/FlatteningMapper.cs b/src/Benchmark/FlatteningMapper.cs index 98c9c1d2f0..c940974e19 100644 --- a/src/Benchmark/FlatteningMapper.cs +++ b/src/Benchmark/FlatteningMapper.cs @@ -2,557 +2,555 @@ using AutoMapper; using System.Collections.Generic; using System.Linq; -namespace Benchmark.Flattening +namespace Benchmark.Flattening; + +static class Config { - static class Config + public static readonly IMapper Mapper = CreateMapper(); + class DeepTypeProfile : Profile { - public static readonly IMapper Mapper = CreateMapper(); - class DeepTypeProfile : Profile - { - public DeepTypeProfile() - { - CreateMap(); - CreateMap(); - CreateMap(); - } - } - class ComplexTypesProfile : Profile - { - public ComplexTypesProfile() - { - CreateMap(); - CreateMap(); - } - } - class ConstructorProfile : Profile - { - public ConstructorProfile() => CreateMap(); - } - class FlatteningProfile : Profile - { - public FlatteningProfile() - { - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - } - } - private static IMapper CreateMapper() + public DeepTypeProfile() { - var config = new MapperConfiguration(cfg => - { - cfg.AddProfile(new DeepTypeProfile()); - cfg.AddProfile(new ComplexTypesProfile()); - cfg.AddProfile(new ConstructorProfile()); - cfg.AddProfile(new FlatteningProfile()); - }); - //config.AssertConfigurationIsValid(); - return config.CreateMapper(); + CreateMap(); + CreateMap(); + CreateMap(); } - public static TDestination Map(TSource source) => Mapper.Map(source); } - public class DeepTypeMapper : IObjectToObjectMapper + class ComplexTypesProfile : Profile { - private Customer _customer; - public string Name { get; } = "Deep Types"; - public void Initialize() + public ComplexTypesProfile() { - _customer = new Customer() - { - Address = new Address() { City = "istanbul", Country = "turkey", Id = 1, Street = "istiklal cad." }, - HomeAddress = new Address() { City = "istanbul", Country = "turkey", Id = 2, Street = "istiklal cad." }, - Id = 1, - Name = "Eduardo Najera", - Credit = 234.7m, - WorkAddresses = new List
() - { - new Address() {City = "istanbul", Country = "turkey", Id = 5, Street = "istiklal cad."}, - new Address() {City = "izmir", Country = "turkey", Id = 6, Street = "konak"} - }, - Addresses = new List
() - { - new Address() {City = "istanbul", Country = "turkey", Id = 3, Street = "istiklal cad."}, - new Address() {City = "izmir", Country = "turkey", Id = 4, Street = "konak"} - }.ToArray() - }; + CreateMap(); + CreateMap(); } - public object Map() => Config.Map(_customer); - } - public class Address - { - public int Id { get; set; } - public string Street { get; set; } - public string City { get; set; } - public string Country { get; set; } } - - public class AddressDTO + class ConstructorProfile : Profile { - public int Id { get; set; } - public string City { get; set; } - public string Country { get; set; } + public ConstructorProfile() => CreateMap(); } - - public class Customer + class FlatteningProfile : Profile { - public int Id { get; set; } - public string Name { get; set; } - public decimal? Credit { get; set; } - public Address Address { get; set; } - public Address HomeAddress { get; set; } - public Address[] Addresses { get; set; } - public List
WorkAddresses { get; set; } + public FlatteningProfile() + { + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + } } - - public class CustomerDTO + private static IMapper CreateMapper() { - public int Id { get; set; } - public string Name { get; set; } - public Address Address { get; set; } - public AddressDTO HomeAddress { get; set; } - public AddressDTO[] Addresses { get; set; } - public List WorkAddresses { get; set; } - public string AddressCity { get; set; } - } - public class ManualDeepTypeMapper : IObjectToObjectMapper + var config = new MapperConfiguration(cfg => + { + cfg.AddProfile(new DeepTypeProfile()); + cfg.AddProfile(new ComplexTypesProfile()); + cfg.AddProfile(new ConstructorProfile()); + cfg.AddProfile(new FlatteningProfile()); + }); + //config.AssertConfigurationIsValid(); + return config.CreateMapper(); + } + public static TDestination Map(TSource source) => Mapper.Map(source); +} +public class DeepTypeMapper : IObjectToObjectMapper +{ + private Customer _customer; + public string Name { get; } = "Deep Types"; + public void Initialize() { - private Customer _customer; - public string Name { get; } = "Manual Deep Types"; - public void Initialize() + _customer = new Customer() { - _customer = new Customer() + Address = new Address() { City = "istanbul", Country = "turkey", Id = 1, Street = "istiklal cad." }, + HomeAddress = new Address() { City = "istanbul", Country = "turkey", Id = 2, Street = "istiklal cad." }, + Id = 1, + Name = "Eduardo Najera", + Credit = 234.7m, + WorkAddresses = new List
() { - Address = new Address() { City = "istanbul", Country = "turkey", Id = 1, Street = "istiklal cad." }, - HomeAddress = new Address() { City = "istanbul", Country = "turkey", Id = 2, Street = "istiklal cad." }, - Id = 1, - Name = "Eduardo Najera", - Credit = 234.7m, - WorkAddresses = new List
() - { - new Address() {City = "istanbul", Country = "turkey", Id = 5, Street = "istiklal cad."}, - new Address() {City = "izmir", Country = "turkey", Id = 6, Street = "konak"} - }, - Addresses = new List
() - { - new Address() {City = "istanbul", Country = "turkey", Id = 3, Street = "istiklal cad."}, - new Address() {City = "izmir", Country = "turkey", Id = 4, Street = "konak"} - }.ToArray() - }; - } + new Address() {City = "istanbul", Country = "turkey", Id = 5, Street = "istiklal cad."}, + new Address() {City = "izmir", Country = "turkey", Id = 6, Street = "konak"} + }, + Addresses = new List
() + { + new Address() {City = "istanbul", Country = "turkey", Id = 3, Street = "istiklal cad."}, + new Address() {City = "izmir", Country = "turkey", Id = 4, Street = "konak"} + }.ToArray() + }; + } + public object Map() => Config.Map(_customer); +} +public class Address +{ + public int Id { get; set; } + public string Street { get; set; } + public string City { get; set; } + public string Country { get; set; } +} - public object Map() +public class AddressDTO +{ + public int Id { get; set; } + public string City { get; set; } + public string Country { get; set; } +} + +public class Customer +{ + public int Id { get; set; } + public string Name { get; set; } + public decimal? Credit { get; set; } + public Address Address { get; set; } + public Address HomeAddress { get; set; } + public Address[] Addresses { get; set; } + public List
WorkAddresses { get; set; } +} + +public class CustomerDTO +{ + public int Id { get; set; } + public string Name { get; set; } + public Address Address { get; set; } + public AddressDTO HomeAddress { get; set; } + public AddressDTO[] Addresses { get; set; } + public List WorkAddresses { get; set; } + public string AddressCity { get; set; } +} +public class ManualDeepTypeMapper : IObjectToObjectMapper +{ + private Customer _customer; + public string Name { get; } = "Manual Deep Types"; + public void Initialize() + { + _customer = new Customer() { - var dto = new CustomerDTO(); + Address = new Address() { City = "istanbul", Country = "turkey", Id = 1, Street = "istiklal cad." }, + HomeAddress = new Address() { City = "istanbul", Country = "turkey", Id = 2, Street = "istiklal cad." }, + Id = 1, + Name = "Eduardo Najera", + Credit = 234.7m, + WorkAddresses = new List
() + { + new Address() {City = "istanbul", Country = "turkey", Id = 5, Street = "istiklal cad."}, + new Address() {City = "izmir", Country = "turkey", Id = 6, Street = "konak"} + }, + Addresses = new List
() + { + new Address() {City = "istanbul", Country = "turkey", Id = 3, Street = "istiklal cad."}, + new Address() {City = "izmir", Country = "turkey", Id = 4, Street = "konak"} + }.ToArray() + }; + } - dto.Id = _customer.Id; - dto.Name = _customer.Name; - dto.AddressCity = _customer.Address.City; + public object Map() + { + var dto = new CustomerDTO(); - dto.Address = new Address() { Id = _customer.Address.Id, Street = _customer.Address.Street, Country = _customer.Address.Country, City = _customer.Address.City }; + dto.Id = _customer.Id; + dto.Name = _customer.Name; + dto.AddressCity = _customer.Address.City; - dto.HomeAddress = new AddressDTO() { Id = _customer.HomeAddress.Id, Country = _customer.HomeAddress.Country, City = _customer.HomeAddress.City }; + dto.Address = new Address() { Id = _customer.Address.Id, Street = _customer.Address.Street, Country = _customer.Address.Country, City = _customer.Address.City }; - dto.Addresses = new AddressDTO[_customer.Addresses.Length]; - for (int i = 0; i < _customer.Addresses.Length; i++) - { - dto.Addresses[i] = new AddressDTO() { Id = _customer.Addresses[i].Id, Country = _customer.Addresses[i].Country, City = _customer.Addresses[i].City }; - } + dto.HomeAddress = new AddressDTO() { Id = _customer.HomeAddress.Id, Country = _customer.HomeAddress.Country, City = _customer.HomeAddress.City }; - dto.WorkAddresses = new List(); - foreach (var workAddress in _customer.WorkAddresses) - { - dto.WorkAddresses.Add(new AddressDTO() { Id = workAddress.Id, Country = workAddress.Country, City = workAddress.City }); - } - return dto; - } - } - public class ComplexTypeMapper : IObjectToObjectMapper - { - private Foo _foo; - public string Name { get; } = "Complex Types"; - public void Initialize() + dto.Addresses = new AddressDTO[_customer.Addresses.Length]; + for (int i = 0; i < _customer.Addresses.Length; i++) { - _foo = Foo.New(); + dto.Addresses[i] = new AddressDTO() { Id = _customer.Addresses[i].Id, Country = _customer.Addresses[i].Country, City = _customer.Addresses[i].City }; } - public object Map() + + dto.WorkAddresses = new List(); + foreach (var workAddress in _customer.WorkAddresses) { - var dest = Config.Map(_foo); - return dest; + dto.WorkAddresses.Add(new AddressDTO() { Id = workAddress.Id, Country = workAddress.Country, City = workAddress.City }); } + return dto; } - - public class Foo +} +public class ComplexTypeMapper : IObjectToObjectMapper +{ + private Foo _foo; + public string Name { get; } = "Complex Types"; + public void Initialize() { - public static Foo New() => new Foo - { - Name = "foo", - Int32 = 12, - Int64 = 123123, - NullInt = 16, - DateTime = DateTime.Now, - Doublen = 2312112, - Foo1 = new InnerFoo { Name = "foo one" }, - Foos = new List - { - new InnerFoo {Name = "j1", Int64 = 123, NullInt = 321}, - new InnerFoo {Name = "j2", Int32 = 12345, NullInt = 54321}, - new InnerFoo {Name = "j3", Int32 = 12345, NullInt = 54321}, - }, - FooArr = new[] - { - new InnerFoo {Name = "a1"}, - new InnerFoo {Name = "a2"}, - new InnerFoo {Name = "a3"}, - }, - IntArr = new[] { 1, 2, 3, 4, 5 }, - Ints = new[] { 7, 8, 9 }, - }; + _foo = Foo.New(); + } + public object Map() + { + var dest = Config.Map(_foo); + return dest; + } +} - public string Name { get; set; } +public class Foo +{ + public static Foo New() => new Foo + { + Name = "foo", + Int32 = 12, + Int64 = 123123, + NullInt = 16, + DateTime = DateTime.Now, + Doublen = 2312112, + Foo1 = new InnerFoo { Name = "foo one" }, + Foos = new List + { + new InnerFoo {Name = "j1", Int64 = 123, NullInt = 321}, + new InnerFoo {Name = "j2", Int32 = 12345, NullInt = 54321}, + new InnerFoo {Name = "j3", Int32 = 12345, NullInt = 54321}, + }, + FooArr = new[] + { + new InnerFoo {Name = "a1"}, + new InnerFoo {Name = "a2"}, + new InnerFoo {Name = "a3"}, + }, + IntArr = new[] { 1, 2, 3, 4, 5 }, + Ints = new[] { 7, 8, 9 }, + }; - public int Int32 { get; set; } + public string Name { get; set; } - public long Int64 { set; get; } + public int Int32 { get; set; } - public int? NullInt { get; set; } + public long Int64 { set; get; } - public float Floatn { get; set; } + public int? NullInt { get; set; } - public double Doublen { get; set; } + public float Floatn { get; set; } - public DateTime DateTime { get; set; } + public double Doublen { get; set; } - public InnerFoo Foo1 { get; set; } + public DateTime DateTime { get; set; } - public List Foos { get; set; } + public InnerFoo Foo1 { get; set; } - public InnerFoo[] FooArr { get; set; } + public List Foos { get; set; } - public int[] IntArr { get; set; } + public InnerFoo[] FooArr { get; set; } - public int[] Ints { get; set; } - } + public int[] IntArr { get; set; } - public class InnerFoo - { - public string Name { get; set; } - public int Int32 { get; set; } - public long Int64 { set; get; } - public int? NullInt { get; set; } - } + public int[] Ints { get; set; } +} - public class InnerFooDest - { - public string Name { get; set; } - public int Int32 { get; set; } - public long Int64 { set; get; } - public int? NullInt { get; set; } - } +public class InnerFoo +{ + public string Name { get; set; } + public int Int32 { get; set; } + public long Int64 { set; get; } + public int? NullInt { get; set; } +} - public class FooDest - { - public string Name { get; set; } +public class InnerFooDest +{ + public string Name { get; set; } + public int Int32 { get; set; } + public long Int64 { set; get; } + public int? NullInt { get; set; } +} - public int Int32 { get; set; } +public class FooDest +{ + public string Name { get; set; } - public long Int64 { set; get; } + public int Int32 { get; set; } - public int? NullInt { get; set; } + public long Int64 { set; get; } - public float Floatn { get; set; } + public int? NullInt { get; set; } - public double Doublen { get; set; } + public float Floatn { get; set; } - public DateTime DateTime { get; set; } + public double Doublen { get; set; } - public InnerFooDest Foo1 { get; set; } + public DateTime DateTime { get; set; } - public List Foos { get; set; } + public InnerFooDest Foo1 { get; set; } - public InnerFooDest[] FooArr { get; set; } + public List Foos { get; set; } - public int[] IntArr { get; set; } + public InnerFooDest[] FooArr { get; set; } - public int[] Ints { get; set; } - } + public int[] IntArr { get; set; } + + public int[] Ints { get; set; } +} - public class ManualComplexTypeMapper : IObjectToObjectMapper +public class ManualComplexTypeMapper : IObjectToObjectMapper +{ + private Foo _foo; + public string Name { get; } = "Manual Complex Types"; + + public void Initialize() { - private Foo _foo; - public string Name { get; } = "Manual Complex Types"; + _foo = Foo.New(); + } - public void Initialize() + public object Map() + { + var dest = new FooDest + { + Name = _foo.Name, + Int32 = _foo.Int32, + Int64 = _foo.Int64, + NullInt = _foo.NullInt, + DateTime = _foo.DateTime, + Doublen = _foo.Doublen, + Foo1 = new InnerFooDest { Name = _foo.Foo1.Name }, + Foos = new List(_foo.Foos.Count), + FooArr = new InnerFooDest[_foo.Foos.Count], + IntArr = new int[_foo.IntArr.Length], + Ints = _foo.Ints.ToArray(), + }; + foreach(var foo in _foo.Foos) { - _foo = Foo.New(); + dest.Foos.Add(new InnerFooDest { Name = foo.Name, Int64 = foo.Int64, NullInt = foo.NullInt }); } - - public object Map() + ; + for(int index = 0; index < _foo.Foos.Count; index++) { - var dest = new FooDest - { - Name = _foo.Name, - Int32 = _foo.Int32, - Int64 = _foo.Int64, - NullInt = _foo.NullInt, - DateTime = _foo.DateTime, - Doublen = _foo.Doublen, - Foo1 = new InnerFooDest { Name = _foo.Foo1.Name }, - Foos = new List(_foo.Foos.Count), - FooArr = new InnerFooDest[_foo.Foos.Count], - IntArr = new int[_foo.IntArr.Length], - Ints = _foo.Ints.ToArray(), - }; - foreach(var foo in _foo.Foos) - { - dest.Foos.Add(new InnerFooDest { Name = foo.Name, Int64 = foo.Int64, NullInt = foo.NullInt }); - } - ; - for(int index = 0; index < _foo.Foos.Count; index++) - { - var foo = _foo.Foos[index]; - dest.FooArr[index] = new InnerFooDest { Name = foo.Name, Int64 = foo.Int64, NullInt = foo.NullInt }; - } - Array.Copy(_foo.IntArr, dest.IntArr, _foo.IntArr.Length); - return dest; + var foo = _foo.Foos[index]; + dest.FooArr[index] = new InnerFooDest { Name = foo.Name, Int64 = foo.Int64, NullInt = foo.NullInt }; } + Array.Copy(_foo.IntArr, dest.IntArr, _foo.IntArr.Length); + return dest; } - public class CtorMapper : IObjectToObjectMapper - { - private Model11 _model; - public string Name => "CtorMapper"; - public void Initialize() => _model = new Model11 { Value = 5 }; - public object Map() => Config.Map(_model); - } - public class ManualCtorMapper : IObjectToObjectMapper - { - private Model11 _model; - public string Name => "ManualCtorMapper"; - public void Initialize() => _model = new Model11 { Value = 5 }; - public object Map() => new Dto11(_model.Value); - } - public class FlatteningMapper : IObjectToObjectMapper +} +public class CtorMapper : IObjectToObjectMapper +{ + private Model11 _model; + public string Name => "CtorMapper"; + public void Initialize() => _model = new Model11 { Value = 5 }; + public object Map() => Config.Map(_model); +} +public class ManualCtorMapper : IObjectToObjectMapper +{ + private Model11 _model; + public string Name => "ManualCtorMapper"; + public void Initialize() => _model = new Model11 { Value = 5 }; + public object Map() => new Dto11(_model.Value); +} +public class FlatteningMapper : IObjectToObjectMapper +{ + private ModelObject _source; + public string Name => "AutoMapper"; + public void Initialize() { - private ModelObject _source; - public string Name => "AutoMapper"; - public void Initialize() + _source = new ModelObject { - _source = new ModelObject + BaseDate = new DateTime(2007, 4, 5), + Sub = new ModelSubObject { - BaseDate = new DateTime(2007, 4, 5), - Sub = new ModelSubObject - { - ProperName = "Some name", - SubSub = new ModelSubSubObject - { - IAmACoolProperty = "Cool daddy-o" - } - }, - Sub2 = new ModelSubObject + ProperName = "Some name", + SubSub = new ModelSubSubObject { - ProperName = "Sub 2 name" - }, - SubWithExtraName = new ModelSubObject - { - ProperName = "Some other name" - }, - }; - var mapper = Config.Mapper; - } - public object Map() => Config.Map(_source); + IAmACoolProperty = "Cool daddy-o" + } + }, + Sub2 = new ModelSubObject + { + ProperName = "Sub 2 name" + }, + SubWithExtraName = new ModelSubObject + { + ProperName = "Some other name" + }, + }; + var mapper = Config.Mapper; } - public class ManualMapper : IObjectToObjectMapper + public object Map() => Config.Map(_source); +} +public class ManualMapper : IObjectToObjectMapper +{ + private ModelObject _source; + public string Name => "Manual"; + public void Initialize() { - private ModelObject _source; - public string Name => "Manual"; - public void Initialize() + _source = new ModelObject { - _source = new ModelObject + BaseDate = new DateTime(2007, 4, 5), + Sub = new ModelSubObject { - BaseDate = new DateTime(2007, 4, 5), - Sub = new ModelSubObject - { - ProperName = "Some name", - SubSub = new ModelSubSubObject - { - IAmACoolProperty = "Cool daddy-o" - } - }, - Sub2 = new ModelSubObject - { - ProperName = "Sub 2 name" - }, - SubWithExtraName = new ModelSubObject + ProperName = "Some name", + SubSub = new ModelSubSubObject { - ProperName = "Some other name" - }, - }; - } - public object Map() - { - return new ModelDto + IAmACoolProperty = "Cool daddy-o" + } + }, + Sub2 = new ModelSubObject { - BaseDate = _source.BaseDate, - Sub2ProperName = _source.Sub2.ProperName, - SubProperName = _source.Sub.ProperName, - SubSubSubIAmACoolProperty = _source.Sub.SubSub.IAmACoolProperty, - SubWithExtraNameProperName = _source.SubWithExtraName.ProperName - }; - } + ProperName = "Sub 2 name" + }, + SubWithExtraName = new ModelSubObject + { + ProperName = "Some other name" + }, + }; } - public class Model1 + public object Map() { - public int Value { get; set; } + return new ModelDto + { + BaseDate = _source.BaseDate, + Sub2ProperName = _source.Sub2.ProperName, + SubProperName = _source.Sub.ProperName, + SubSubSubIAmACoolProperty = _source.Sub.SubSub.IAmACoolProperty, + SubWithExtraNameProperName = _source.SubWithExtraName.ProperName + }; } +} +public class Model1 +{ + public int Value { get; set; } +} - public class Model2 - { - public int Value { get; set; } - } +public class Model2 +{ + public int Value { get; set; } +} - public class Model3 - { - public int Value { get; set; } - } +public class Model3 +{ + public int Value { get; set; } +} - public class Model4 - { - public int Value { get; set; } - } +public class Model4 +{ + public int Value { get; set; } +} - public class Model5 - { - public int Value { get; set; } - } +public class Model5 +{ + public int Value { get; set; } +} - public class Model6 - { - public int Value { get; set; } - } +public class Model6 +{ + public int Value { get; set; } +} - public class Model7 - { - public int Value { get; set; } - } +public class Model7 +{ + public int Value { get; set; } +} - public class Model8 - { - public int Value { get; set; } - } +public class Model8 +{ + public int Value { get; set; } +} - public class Model9 - { - public int Value { get; set; } - } +public class Model9 +{ + public int Value { get; set; } +} - public class Model10 - { - public int Value { get; set; } - } +public class Model10 +{ + public int Value { get; set; } +} - public class Model11 - { - public int Value { get; set; } - } +public class Model11 +{ + public int Value { get; set; } +} - public class Dto1 - { - public int Value { get; set; } - } +public class Dto1 +{ + public int Value { get; set; } +} - public class Dto2 - { - public int Value { get; set; } - } +public class Dto2 +{ + public int Value { get; set; } +} - public class Dto3 - { - public int Value { get; set; } - } +public class Dto3 +{ + public int Value { get; set; } +} - public class Dto4 - { - public int Value { get; set; } - } +public class Dto4 +{ + public int Value { get; set; } +} - public class Dto5 - { - public int Value { get; set; } - } +public class Dto5 +{ + public int Value { get; set; } +} - public class Dto6 - { - public int Value { get; set; } - } +public class Dto6 +{ + public int Value { get; set; } +} - public class Dto7 - { - public int Value { get; set; } - } +public class Dto7 +{ + public int Value { get; set; } +} - public class Dto8 - { - public int Value { get; set; } - } +public class Dto8 +{ + public int Value { get; set; } +} - public class Dto9 - { - public int Value { get; set; } - } +public class Dto9 +{ + public int Value { get; set; } +} - public class Dto10 - { - public int Value { get; set; } - } +public class Dto10 +{ + public int Value { get; set; } +} - public class Dto11 +public class Dto11 +{ + public Dto11(int value) { - public Dto11(int value) - { - _value = value; - } - - private readonly int _value; - - public int Value - { - get { return _value; } - } + _value = value; } - public class ModelObject - { - public DateTime BaseDate { get; set; } - public ModelSubObject Sub { get; set; } - public ModelSubObject Sub2 { get; set; } - public ModelSubObject SubWithExtraName { get; set; } - } + private readonly int _value; - public class ModelSubObject + public int Value { - public string ProperName { get; set; } - public ModelSubSubObject SubSub { get; set; } + get { return _value; } } +} - public class ModelSubSubObject - { - public string IAmACoolProperty { get; set; } - } +public class ModelObject +{ + public DateTime BaseDate { get; set; } + public ModelSubObject Sub { get; set; } + public ModelSubObject Sub2 { get; set; } + public ModelSubObject SubWithExtraName { get; set; } +} - public class ModelDto - { - public DateTime BaseDate { get; set; } - public string SubProperName { get; set; } - public string Sub2ProperName { get; set; } - public string SubWithExtraNameProperName { get; set; } - public string SubSubSubIAmACoolProperty { get; set; } - } +public class ModelSubObject +{ + public string ProperName { get; set; } + public ModelSubSubObject SubSub { get; set; } +} +public class ModelSubSubObject +{ + public string IAmACoolProperty { get; set; } +} + +public class ModelDto +{ + public DateTime BaseDate { get; set; } + public string SubProperName { get; set; } + public string Sub2ProperName { get; set; } + public string SubWithExtraNameProperName { get; set; } + public string SubSubSubIAmACoolProperty { get; set; } } \ No newline at end of file diff --git a/src/Benchmark/HiPerfTimer.cs b/src/Benchmark/HiPerfTimer.cs index e179d07b09..976163f732 100644 --- a/src/Benchmark/HiPerfTimer.cs +++ b/src/Benchmark/HiPerfTimer.cs @@ -2,57 +2,56 @@ using System.Runtime.InteropServices; using System.Threading; -namespace Benchmark +namespace Benchmark; + +public class HiPerfTimer { - public class HiPerfTimer - { - [DllImport("Kernel32.dll")] - private static extern bool QueryPerformanceCounter( - out long lpPerformanceCount); + [DllImport("Kernel32.dll")] + private static extern bool QueryPerformanceCounter( + out long lpPerformanceCount); - [DllImport("Kernel32.dll")] - private static extern bool QueryPerformanceFrequency( - out long lpFrequency); + [DllImport("Kernel32.dll")] + private static extern bool QueryPerformanceFrequency( + out long lpFrequency); - private long _startTime, _stopTime; - private long _freq; + private long _startTime, _stopTime; + private long _freq; + + // Constructor + public HiPerfTimer() + { + _startTime = 0; + _stopTime = 0; - // Constructor - public HiPerfTimer() + if (QueryPerformanceFrequency(out _freq) == false) { - _startTime = 0; - _stopTime = 0; - - if (QueryPerformanceFrequency(out _freq) == false) - { - // high-performance counter not supported - throw new Win32Exception(); - } + // high-performance counter not supported + throw new Win32Exception(); } + } - // Start the timer - public void Start() - { - // lets do the waiting threads there work - Thread.Sleep(0); + // Start the timer + public void Start() + { + // lets do the waiting threads there work + Thread.Sleep(0); - QueryPerformanceCounter(out _startTime); - } + QueryPerformanceCounter(out _startTime); + } - // Stop the timer - public void Stop() - { - QueryPerformanceCounter(out _stopTime); - } + // Stop the timer + public void Stop() + { + QueryPerformanceCounter(out _stopTime); + } - // Returns the duration of the timer (in seconds) - public double Duration + // Returns the duration of the timer (in seconds) + public double Duration + { + get { - get - { - double d = (_stopTime - _startTime); - return d / _freq; - } + double d = (_stopTime - _startTime); + return d / _freq; } } } \ No newline at end of file diff --git a/src/Benchmark/IObjectToObjectMapper.cs b/src/Benchmark/IObjectToObjectMapper.cs index e276d52e45..ec6041349c 100644 --- a/src/Benchmark/IObjectToObjectMapper.cs +++ b/src/Benchmark/IObjectToObjectMapper.cs @@ -1,11 +1,10 @@ using System; -namespace Benchmark +namespace Benchmark; + +public interface IObjectToObjectMapper { - public interface IObjectToObjectMapper - { - string Name { get; } - void Initialize(); - object Map(); - } + string Name { get; } + void Initialize(); + object Map(); } \ No newline at end of file diff --git a/src/Benchmark/Program.cs b/src/Benchmark/Program.cs index b5195d2723..df2b635547 100644 --- a/src/Benchmark/Program.cs +++ b/src/Benchmark/Program.cs @@ -2,30 +2,29 @@ using System.Collections.Generic; using Benchmark.Flattening; -namespace Benchmark +namespace Benchmark; + +public class Program { - public class Program + public static void Main(string[] args) { - public static void Main(string[] args) + var mappers = new Dictionary + { + { "Flattening", new IObjectToObjectMapper[] { new FlatteningMapper() , new ManualMapper(), } }, + { "Ctors", new IObjectToObjectMapper[] { new CtorMapper(), new ManualCtorMapper(), } }, + { "Complex", new IObjectToObjectMapper[] { new ComplexTypeMapper(), new ManualComplexTypeMapper() } }, + { "Deep", new IObjectToObjectMapper[] { new DeepTypeMapper(), new ManualDeepTypeMapper() } } + }; + //while (true) { - var mappers = new Dictionary - { - { "Flattening", new IObjectToObjectMapper[] { new FlatteningMapper() , new ManualMapper(), } }, - { "Ctors", new IObjectToObjectMapper[] { new CtorMapper(), new ManualCtorMapper(), } }, - { "Complex", new IObjectToObjectMapper[] { new ComplexTypeMapper(), new ManualComplexTypeMapper() } }, - { "Deep", new IObjectToObjectMapper[] { new DeepTypeMapper(), new ManualDeepTypeMapper() } } - }; - //while (true) + foreach (var pair in mappers) { - foreach (var pair in mappers) + foreach (var mapper in pair.Value) { - foreach (var mapper in pair.Value) - { - new BenchEngine(mapper, pair.Key).Start(); - } + new BenchEngine(mapper, pair.Key).Start(); } - //Console.ReadLine(); } + //Console.ReadLine(); } } } diff --git a/src/UnitTests/AddProfiles.cs b/src/UnitTests/AddProfiles.cs index 0b529858e8..d972c762e9 100644 --- a/src/UnitTests/AddProfiles.cs +++ b/src/UnitTests/AddProfiles.cs @@ -2,22 +2,21 @@ using Shouldly; using Xunit; -namespace AutoMapper.UnitTests +namespace AutoMapper.UnitTests; + +public class AddProfiles : AutoMapperSpecBase { - public class AddProfiles : AutoMapperSpecBase + public class Source { } + public class Dest { } + public class ForwardProfile : Profile + { + public ForwardProfile() => CreateMap(); + } + public class ReverseProfile : Profile { - public class Source { } - public class Dest { } - public class ForwardProfile : Profile - { - public ForwardProfile() => CreateMap(); - } - public class ReverseProfile : Profile - { - public ReverseProfile() => CreateMap(); - } - protected override MapperConfiguration CreateConfiguration() => new(c => c.AddProfiles(new Profile[] { new ForwardProfile(), new ReverseProfile() })); - [Fact] - public void Should_not_throw_when_loading_multiple_profiles() => GetProfiles().Count().ShouldBe(3); // default plus two specifically added + public ReverseProfile() => CreateMap(); } + protected override MapperConfiguration CreateConfiguration() => new(c => c.AddProfiles(new Profile[] { new ForwardProfile(), new ReverseProfile() })); + [Fact] + public void Should_not_throw_when_loading_multiple_profiles() => GetProfiles().Count().ShouldBe(3); // default plus two specifically added } \ No newline at end of file diff --git a/src/UnitTests/ArraysAndLists.cs b/src/UnitTests/ArraysAndLists.cs index b7d7abc8c4..bc7e4c8326 100644 --- a/src/UnitTests/ArraysAndLists.cs +++ b/src/UnitTests/ArraysAndLists.cs @@ -9,904 +9,903 @@ using System.Linq.Expressions; using AutoMapper.Internal; using AutoMapper.Internal.Mappers; -namespace AutoMapper.UnitTests.ArraysAndLists +namespace AutoMapper.UnitTests.ArraysAndLists; + +public class When_mapping_to_Existing_IEnumerable : AutoMapperSpecBase { - public class When_mapping_to_Existing_IEnumerable : AutoMapperSpecBase - { - public class Source - { - public IEnumerable Items { get; set; } = Enumerable.Empty(); - } - public class Destination - { - public IEnumerable Items { get; set; } = Enumerable.Empty(); - } - public class SourceItem - { - public string Value { get; set; } - } - public class DestinationItem - { - public string Value { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(c => - { - c.CreateMap(); - c.CreateMap(); - }); - [Fact] - public void Should_overwrite_the_existing_list() - { - var destination = new Destination(); - var existingList = destination.Items; - Mapper.Map(new Source(), destination); - destination.Items.ShouldNotBeSameAs(existingList); - destination.Items.ShouldBeEmpty(); - } + public class Source + { + public IEnumerable Items { get; set; } = Enumerable.Empty(); } - public class When_mapping_to_an_array_as_ICollection_with_MapAtRuntime : AutoMapperSpecBase + public class Destination { - Destination _destination; - SourceItem[] _sourceItems = new [] { new SourceItem { Value = "1" }, new SourceItem { Value = "2" }, new SourceItem { Value = "3" } }; - - public class Source - { - public ICollection Items { get; set; } - } + public IEnumerable Items { get; set; } = Enumerable.Empty(); + } + public class SourceItem + { + public string Value { get; set; } + } + public class DestinationItem + { + public string Value { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(c => + { + c.CreateMap(); + c.CreateMap(); + }); + [Fact] + public void Should_overwrite_the_existing_list() + { + var destination = new Destination(); + var existingList = destination.Items; + Mapper.Map(new Source(), destination); + destination.Items.ShouldNotBeSameAs(existingList); + destination.Items.ShouldBeEmpty(); + } +} +public class When_mapping_to_an_array_as_ICollection_with_MapAtRuntime : AutoMapperSpecBase +{ + Destination _destination; + SourceItem[] _sourceItems = new [] { new SourceItem { Value = "1" }, new SourceItem { Value = "2" }, new SourceItem { Value = "3" } }; - public class Destination - { - public ICollection Items { get; set; } - } + public class Source + { + public ICollection Items { get; set; } + } - public class SourceItem - { - public string Value { get; set; } - } + public class Destination + { + public ICollection Items { get; set; } + } - public class DestinationItem - { - public string Value { get; set; } - } + public class SourceItem + { + public string Value { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(c => - { - c.CreateMap().ForMember(d=>d.Items, o=>o.MapAtRuntime()); - c.CreateMap(); - }); + public class DestinationItem + { + public string Value { get; set; } + } - protected override void Because_of() - { - var source = new Source { Items = _sourceItems }; - _destination = Mapper.Map(source, new Destination { Items = new[] { new DestinationItem { Value = "4" } } }); - } + protected override MapperConfiguration CreateConfiguration() => new(c => + { + c.CreateMap().ForMember(d=>d.Items, o=>o.MapAtRuntime()); + c.CreateMap(); + }); - [Fact] - public void Should_map_ok() - { - _destination.Items.Select(i => i.Value).SequenceEqual(_sourceItems.Select(i => i.Value)).ShouldBeTrue(); - } + protected override void Because_of() + { + var source = new Source { Items = _sourceItems }; + _destination = Mapper.Map(source, new Destination { Items = new[] { new DestinationItem { Value = "4" } } }); } - public class When_mapping_an_array : AutoMapperSpecBase + [Fact] + public void Should_map_ok() { - decimal[] _source = Enumerable.Range(1, 10).Select(i=>(decimal)i).ToArray(); - decimal[] _destination; + _destination.Items.Select(i => i.Value).SequenceEqual(_sourceItems.Select(i => i.Value)).ShouldBeTrue(); + } +} - protected override MapperConfiguration CreateConfiguration() => new(c =>{}); +public class When_mapping_an_array : AutoMapperSpecBase +{ + decimal[] _source = Enumerable.Range(1, 10).Select(i=>(decimal)i).ToArray(); + decimal[] _destination; - protected override void Because_of() - { - _destination = Mapper.Map(_source); - } + protected override MapperConfiguration CreateConfiguration() => new(c =>{}); - [Fact] - public void Should_return_a_copy() - { - _destination.ShouldNotBeSameAs(_source); - } + protected override void Because_of() + { + _destination = Mapper.Map(_source); } - public class When_mapping_a_primitive_array : AutoMapperSpecBase + [Fact] + public void Should_return_a_copy() { - int[] _source = Enumerable.Range(1, 10).ToArray(); - long[] _destination; + _destination.ShouldNotBeSameAs(_source); + } +} - protected override MapperConfiguration CreateConfiguration() => new(c =>{}); +public class When_mapping_a_primitive_array : AutoMapperSpecBase +{ + int[] _source = Enumerable.Range(1, 10).ToArray(); + long[] _destination; - protected override void Because_of() - { - _destination = Mapper.Map(_source); - } + protected override MapperConfiguration CreateConfiguration() => new(c =>{}); - [Fact] - public void Should_return_a_copy() - { - var source = new int[] {1, 2, 3, 4}; - var dest = new long[4]; - Array.Copy(source, dest, 4); - dest[3].ShouldBe(4L); - - var plan = Configuration.BuildExecutionPlan(typeof(int[]), typeof(long[])); - _destination.ShouldNotBeSameAs(_source); - } + protected override void Because_of() + { + _destination = Mapper.Map(_source); } - public class When_mapping_a_primitive_array_with_custom_mapping_function : AutoMapperSpecBase + [Fact] + public void Should_return_a_copy() { - int[] _source = Enumerable.Range(1, 10).ToArray(); - int[] _destination; + var source = new int[] {1, 2, 3, 4}; + var dest = new long[4]; + Array.Copy(source, dest, 4); + dest[3].ShouldBe(4L); - protected override MapperConfiguration CreateConfiguration() => new(c => c.CreateMap().ConstructUsing(i => i * 1000)); + var plan = Configuration.BuildExecutionPlan(typeof(int[]), typeof(long[])); + _destination.ShouldNotBeSameAs(_source); + } +} - protected override void Because_of() - { - _destination = Mapper.Map(_source); - } +public class When_mapping_a_primitive_array_with_custom_mapping_function : AutoMapperSpecBase +{ + int[] _source = Enumerable.Range(1, 10).ToArray(); + int[] _destination; - [Fact] - public void Should_map_each_item() - { - for (var i = 0; i < _source.Length; i++) - { - _destination[i].ShouldBe((i+1) * 1000); - } - } - } + protected override MapperConfiguration CreateConfiguration() => new(c => c.CreateMap().ConstructUsing(i => i * 1000)); - public class When_mapping_a_primitive_array_with_custom_object_mapper : AutoMapperSpecBase + protected override void Because_of() { - int[] _source = Enumerable.Range(1, 10).ToArray(); - int[] _destination; + _destination = Mapper.Map(_source); + } - private class IntToIntMapper : IObjectMapper + [Fact] + public void Should_map_each_item() + { + for (var i = 0; i < _source.Length; i++) { - public bool IsMatch(TypePair context) - => context.SourceType == typeof(int) && context.DestinationType == typeof(int); + _destination[i].ShouldBe((i+1) * 1000); + } + } +} - public Expression MapExpression(IGlobalConfiguration configurationProvider, ProfileMap profileMap, - MemberMap memberMap, - Expression sourceExpression, Expression destExpression) - => Expression.Multiply(Expression.Convert(sourceExpression, typeof(int)), Expression.Constant(1000)); - } +public class When_mapping_a_primitive_array_with_custom_object_mapper : AutoMapperSpecBase +{ + int[] _source = Enumerable.Range(1, 10).ToArray(); + int[] _destination; - protected override MapperConfiguration CreateConfiguration() => new(c => c.Internal().Mappers.Insert(0, new IntToIntMapper())); + private class IntToIntMapper : IObjectMapper + { + public bool IsMatch(TypePair context) + => context.SourceType == typeof(int) && context.DestinationType == typeof(int); - protected override void Because_of() - { - _destination = Mapper.Map(_source); - } + public Expression MapExpression(IGlobalConfiguration configurationProvider, ProfileMap profileMap, + MemberMap memberMap, + Expression sourceExpression, Expression destExpression) + => Expression.Multiply(Expression.Convert(sourceExpression, typeof(int)), Expression.Constant(1000)); + } - [Fact] - public void Should_not_use_custom_mapper_but_probably_should() - { - for (var i = 0; i < _source.Length; i++) - { - _destination[i].ShouldBe(i + 1); - } - } - } + protected override MapperConfiguration CreateConfiguration() => new(c => c.Internal().Mappers.Insert(0, new IntToIntMapper())); - public class When_mapping_null_list_to_array: AutoMapperSpecBase + protected override void Because_of() { - Destination _destination; + _destination = Mapper.Map(_source); + } - class Source + [Fact] + public void Should_not_use_custom_mapper_but_probably_should() + { + for (var i = 0; i < _source.Length; i++) { - public List Items { get; set; } + _destination[i].ShouldBe(i + 1); } + } +} - class Destination - { - public DestinationItem[] Items { get; set; } - } +public class When_mapping_null_list_to_array: AutoMapperSpecBase +{ + Destination _destination; - class SourceItem - { - public int Value { get; set; } - } + class Source + { + public List Items { get; set; } + } - class DestinationItem - { - public int Value { get; set; } - } + class Destination + { + public DestinationItem[] Items { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - cfg.CreateMap(); - }); + class SourceItem + { + public int Value { get; set; } + } - protected override void Because_of() - { - _destination = Mapper.Map(new Source()); - } + class DestinationItem + { + public int Value { get; set; } + } - [Fact] - public void Should_map_ok() - { - _destination.Items.Length.ShouldBe(0); - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + cfg.CreateMap(); + }); + + protected override void Because_of() + { + _destination = Mapper.Map(new Source()); } - public class When_mapping_null_array_to_list : AutoMapperSpecBase + [Fact] + public void Should_map_ok() { - Destination _destination; + _destination.Items.Length.ShouldBe(0); + } +} - class Source - { - public SourceItem[] Items { get; set; } - } +public class When_mapping_null_array_to_list : AutoMapperSpecBase +{ + Destination _destination; - class Destination - { - public List Items { get; set; } - } + class Source + { + public SourceItem[] Items { get; set; } + } - class SourceItem - { - public int Value { get; set; } - } + class Destination + { + public List Items { get; set; } + } - class DestinationItem - { - public int Value { get; set; } - } + class SourceItem + { + public int Value { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - cfg.CreateMap(); - }); + class DestinationItem + { + public int Value { get; set; } + } - protected override void Because_of() - { - _destination = Mapper.Map(new Source()); - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + cfg.CreateMap(); + }); - [Fact] - public void Should_map_ok() - { - _destination.Items.Count.ShouldBe(0); - } + protected override void Because_of() + { + _destination = Mapper.Map(new Source()); } - public class When_mapping_collections : AutoMapperSpecBase + [Fact] + public void Should_map_ok() { - Author mappedAuthor; + _destination.Items.Count.ShouldBe(0); + } +} - protected override MapperConfiguration CreateConfiguration() => new(delegate{}); +public class When_mapping_collections : AutoMapperSpecBase +{ + Author mappedAuthor; - protected override void Because_of() - { - dynamic authorDynamic = new ExpandoObject(); - authorDynamic.Name = "Charles Dickens"; - dynamic book1 = new ExpandoObject(); - book1.Name = "Great Expectations"; - dynamic book2 = new ExpandoObject(); - book2.Name = "Oliver Twist"; - authorDynamic.Books = new List { book1, book2 }; - mappedAuthor = Mapper.Map((object)authorDynamic); - } + protected override MapperConfiguration CreateConfiguration() => new(delegate{}); - [Fact] - public void Should_map_by_item_type() - { - mappedAuthor.Name.ShouldBe("Charles Dickens"); - mappedAuthor.Books[0].Name.ShouldBe("Great Expectations"); - mappedAuthor.Books[1].Name.ShouldBe("Oliver Twist"); - } + protected override void Because_of() + { + dynamic authorDynamic = new ExpandoObject(); + authorDynamic.Name = "Charles Dickens"; + dynamic book1 = new ExpandoObject(); + book1.Name = "Great Expectations"; + dynamic book2 = new ExpandoObject(); + book2.Name = "Oliver Twist"; + authorDynamic.Books = new List { book1, book2 }; + mappedAuthor = Mapper.Map((object)authorDynamic); + } - public class Author - { - public string Name { get; set; } - public Book[] Books { get; set; } - } + [Fact] + public void Should_map_by_item_type() + { + mappedAuthor.Name.ShouldBe("Charles Dickens"); + mappedAuthor.Books[0].Name.ShouldBe("Great Expectations"); + mappedAuthor.Books[1].Name.ShouldBe("Oliver Twist"); + } - public class Book - { - public string Name { get; set; } - } - } - - public class When_mapping_to_an_existing_HashSet_typed_as_IEnumerable : AutoMapperSpecBase + public class Author { - private Destination _destination = new Destination(); + public string Name { get; set; } + public Book[] Books { get; set; } + } - public class Source - { - public int[] IntCollection { get; set; } = new int[0]; - } + public class Book + { + public string Name { get; set; } + } +} + +public class When_mapping_to_an_existing_HashSet_typed_as_IEnumerable : AutoMapperSpecBase +{ + private Destination _destination = new Destination(); - public class Destination - { - public IEnumerable IntCollection { get; set; } = new HashSet { 1, 2, 3, 4, 5 }; - public string Unmapped { get; } - } + public class Source + { + public int[] IntCollection { get; set; } = new int[0]; + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - }); + public class Destination + { + public IEnumerable IntCollection { get; set; } = new HashSet { 1, 2, 3, 4, 5 }; + public string Unmapped { get; } + } - protected override void Because_of() - { - _destination = Mapper.Map(new Source(), _destination); - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + }); - [Fact] - public void Should_clear_the_destination() - { - _destination.IntCollection.Count().ShouldBe(0); - } + protected override void Because_of() + { + _destination = Mapper.Map(new Source(), _destination); } - public class When_mapping_to_an_existing_array_typed_as_IEnumerable : AutoMapperSpecBase + [Fact] + public void Should_clear_the_destination() { - private Destination _destination = new Destination(); + _destination.IntCollection.Count().ShouldBe(0); + } +} - public class Source - { - public int[] IntCollection { get; set; } = new int[0]; - } +public class When_mapping_to_an_existing_array_typed_as_IEnumerable : AutoMapperSpecBase +{ + private Destination _destination = new Destination(); - public class Destination - { - public IEnumerable IntCollection { get; set; } = new[] { 1, 2, 3, 4, 5 }; - } + public class Source + { + public int[] IntCollection { get; set; } = new int[0]; + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - }); + public class Destination + { + public IEnumerable IntCollection { get; set; } = new[] { 1, 2, 3, 4, 5 }; + } - protected override void Because_of() - { - _destination = Mapper.Map(new Source(), _destination); - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + }); - [Fact] - public void Should_create_destination_array_the_same_size_as_the_source() - { - _destination.IntCollection.Count().ShouldBe(0); - } + protected override void Because_of() + { + _destination = Mapper.Map(new Source(), _destination); } - public class When_mapping_to_a_concrete_non_generic_ienumerable : AutoMapperSpecBase + [Fact] + public void Should_create_destination_array_the_same_size_as_the_source() { - private Destination _destination; + _destination.IntCollection.Count().ShouldBe(0); + } +} - public class Source - { - public int[] Values { get; set; } - public List Values2 { get; set; } - } +public class When_mapping_to_a_concrete_non_generic_ienumerable : AutoMapperSpecBase +{ + private Destination _destination; - public class Destination - { - public IEnumerable Values { get; set; } - public IEnumerable Values2 { get; set; } - } + public class Source + { + public int[] Values { get; set; } + public List Values2 { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - }); + public class Destination + { + public IEnumerable Values { get; set; } + public IEnumerable Values2 { get; set; } + } - protected override void Because_of() - { - _destination = Mapper.Map(new Source { Values = new[] { 1, 2, 3, 4 }, Values2 = new List { 9, 8, 7, 6 } }); - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + }); - [Fact] - public void Should_map_the_list_of_source_items() - { - _destination.Values.ShouldNotBeNull(); - _destination.Values.ShouldContain(1); - _destination.Values.ShouldContain(2); - _destination.Values.ShouldContain(3); - _destination.Values.ShouldContain(4); - } + protected override void Because_of() + { + _destination = Mapper.Map(new Source { Values = new[] { 1, 2, 3, 4 }, Values2 = new List { 9, 8, 7, 6 } }); + } - [Fact] - public void Should_map_from_the_generic_list_of_values() - { - _destination.Values2.ShouldNotBeNull(); - _destination.Values2.ShouldContain(9); - _destination.Values2.ShouldContain(8); - _destination.Values2.ShouldContain(7); - _destination.Values2.ShouldContain(6); - } + [Fact] + public void Should_map_the_list_of_source_items() + { + _destination.Values.ShouldNotBeNull(); + _destination.Values.ShouldContain(1); + _destination.Values.ShouldContain(2); + _destination.Values.ShouldContain(3); + _destination.Values.ShouldContain(4); } - public class When_mapping_to_a_concrete_generic_ienumerable : AutoMapperSpecBase + [Fact] + public void Should_map_from_the_generic_list_of_values() { - private Destination _destination; + _destination.Values2.ShouldNotBeNull(); + _destination.Values2.ShouldContain(9); + _destination.Values2.ShouldContain(8); + _destination.Values2.ShouldContain(7); + _destination.Values2.ShouldContain(6); + } +} - public class Source - { - public int[] Values { get; set; } - public List Values2 { get; set; } - } +public class When_mapping_to_a_concrete_generic_ienumerable : AutoMapperSpecBase +{ + private Destination _destination; - public class Destination - { - public IEnumerable Values { get; set; } - public IEnumerable Values2 { get; set; } - } + public class Source + { + public int[] Values { get; set; } + public List Values2 { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - }); + public class Destination + { + public IEnumerable Values { get; set; } + public IEnumerable Values2 { get; set; } + } - protected override void Because_of() - { - _destination = Mapper.Map(new Source { Values = new[] { 1, 2, 3, 4 }, Values2 = new List { 9, 8, 7, 6 } }); - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + }); - [Fact] - public void Should_map_the_list_of_source_items() - { - _destination.Values.ShouldNotBeNull(); - _destination.Values.ShouldContain(1); - _destination.Values.ShouldContain(2); - _destination.Values.ShouldContain(3); - _destination.Values.ShouldContain(4); - } + protected override void Because_of() + { + _destination = Mapper.Map(new Source { Values = new[] { 1, 2, 3, 4 }, Values2 = new List { 9, 8, 7, 6 } }); + } - [Fact] - public void Should_map_from_the_generic_list_of_values_with_formatting() - { - _destination.Values2.ShouldNotBeNull(); - _destination.Values2.ShouldContain("9"); - _destination.Values2.ShouldContain("8"); - _destination.Values2.ShouldContain("7"); - _destination.Values2.ShouldContain("6"); - } - } + [Fact] + public void Should_map_the_list_of_source_items() + { + _destination.Values.ShouldNotBeNull(); + _destination.Values.ShouldContain(1); + _destination.Values.ShouldContain(2); + _destination.Values.ShouldContain(3); + _destination.Values.ShouldContain(4); + } + + [Fact] + public void Should_map_from_the_generic_list_of_values_with_formatting() + { + _destination.Values2.ShouldNotBeNull(); + _destination.Values2.ShouldContain("9"); + _destination.Values2.ShouldContain("8"); + _destination.Values2.ShouldContain("7"); + _destination.Values2.ShouldContain("6"); + } +} - public class When_mapping_to_a_getter_only_ienumerable : AutoMapperSpecBase +public class When_mapping_to_a_getter_only_ienumerable : AutoMapperSpecBase +{ + private Destination _destination = new Destination(); + public class Source { - private Destination _destination = new Destination(); - public class Source - { - public int[] Values { get; set; } - public List Values2 { get; set; } - } - public class Destination - { - public IEnumerable Values { get; } = new List(); - public IEnumerable Values2 { get; } = new List(); - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - }); - protected override void Because_of() => _destination = Mapper.Map(new Source { Values = new[] { 1, 2, 3, 4 }, Values2 = new List { 9, 8, 7, 6 } }); - [Fact] - public void Should_map_the_list_of_source_items() - { - _destination.Values.ShouldBe(new[] { 1, 2, 3, 4 }); - _destination.Values2.ShouldBe(new[] { "9", "8", "7", "6" }); - } - } + public int[] Values { get; set; } + public List Values2 { get; set; } + } + public class Destination + { + public IEnumerable Values { get; } = new List(); + public IEnumerable Values2 { get; } = new List(); + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + }); + protected override void Because_of() => _destination = Mapper.Map(new Source { Values = new[] { 1, 2, 3, 4 }, Values2 = new List { 9, 8, 7, 6 } }); + [Fact] + public void Should_map_the_list_of_source_items() + { + _destination.Values.ShouldBe(new[] { 1, 2, 3, 4 }); + _destination.Values2.ShouldBe(new[] { "9", "8", "7", "6" }); + } +} - public class When_mapping_to_a_getter_only_existing_ienumerable : AutoMapperSpecBase +public class When_mapping_to_a_getter_only_existing_ienumerable : AutoMapperSpecBase +{ + private Destination _destination = new Destination(); + public class Source { - private Destination _destination = new Destination(); - public class Source - { - public int[] Values { get; set; } - public List Values2 { get; set; } - } - public class Destination - { - public IEnumerable Values { get; } = new List(); - public IEnumerable Values2 { get; } = new List(); - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - }); - protected override void Because_of() => Mapper.Map(new Source { Values = new[] { 1, 2, 3, 4 }, Values2 = new List { 9, 8, 7, 6 } }, _destination); - [Fact] - public void Should_map_the_list_of_source_items() - { - _destination.Values.ShouldBe(new[] { 1, 2, 3, 4 }); - _destination.Values2.ShouldBe(new[]{ "9", "8", "7", "6" }); - } - } - - public class When_mapping_to_a_concrete_non_generic_icollection : AutoMapperSpecBase + public int[] Values { get; set; } + public List Values2 { get; set; } + } + public class Destination + { + public IEnumerable Values { get; } = new List(); + public IEnumerable Values2 { get; } = new List(); + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => { - private Destination _destination; + cfg.CreateMap(); + }); + protected override void Because_of() => Mapper.Map(new Source { Values = new[] { 1, 2, 3, 4 }, Values2 = new List { 9, 8, 7, 6 } }, _destination); + [Fact] + public void Should_map_the_list_of_source_items() + { + _destination.Values.ShouldBe(new[] { 1, 2, 3, 4 }); + _destination.Values2.ShouldBe(new[]{ "9", "8", "7", "6" }); + } +} - public class Source - { - public int[] Values { get; set; } - public List Values2 { get; set; } - } +public class When_mapping_to_a_concrete_non_generic_icollection : AutoMapperSpecBase +{ + private Destination _destination; - public class Destination - { - public ICollection Values { get; set; } - public ICollection Values2 { get; set; } - } + public class Source + { + public int[] Values { get; set; } + public List Values2 { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - }); + public class Destination + { + public ICollection Values { get; set; } + public ICollection Values2 { get; set; } + } - protected override void Because_of() - { - _destination = Mapper.Map(new Source { Values = new[] { 1, 2, 3, 4 }, Values2 = new List { 9, 8, 7, 6 } }); - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + }); - [Fact] - public void Should_map_the_list_of_source_items() - { - _destination.Values.ShouldNotBeNull(); - _destination.Values.ShouldContain(1); - _destination.Values.ShouldContain(2); - _destination.Values.ShouldContain(3); - _destination.Values.ShouldContain(4); - } + protected override void Because_of() + { + _destination = Mapper.Map(new Source { Values = new[] { 1, 2, 3, 4 }, Values2 = new List { 9, 8, 7, 6 } }); + } - [Fact] - public void Should_map_from_a_non_array_source() - { - _destination.Values2.ShouldNotBeNull(); - _destination.Values2.ShouldContain(9); - _destination.Values2.ShouldContain(8); - _destination.Values2.ShouldContain(7); - _destination.Values2.ShouldContain(6); - } + [Fact] + public void Should_map_the_list_of_source_items() + { + _destination.Values.ShouldNotBeNull(); + _destination.Values.ShouldContain(1); + _destination.Values.ShouldContain(2); + _destination.Values.ShouldContain(3); + _destination.Values.ShouldContain(4); } - public class When_mapping_to_a_concrete_generic_icollection : AutoMapperSpecBase + [Fact] + public void Should_map_from_a_non_array_source() { - private Destination _destination; + _destination.Values2.ShouldNotBeNull(); + _destination.Values2.ShouldContain(9); + _destination.Values2.ShouldContain(8); + _destination.Values2.ShouldContain(7); + _destination.Values2.ShouldContain(6); + } +} - public class Source - { - public int[] Values { get; set; } - } +public class When_mapping_to_a_concrete_generic_icollection : AutoMapperSpecBase +{ + private Destination _destination; - public class Destination - { - public ICollection Values { get; set; } - } + public class Source + { + public int[] Values { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - }); + public class Destination + { + public ICollection Values { get; set; } + } - protected override void Because_of() - { - _destination = Mapper.Map(new Source { Values = new[] { 1, 2, 3, 4 } }); - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + }); - [Fact] - public void Should_map_the_list_of_source_items() - { - _destination.Values.ShouldNotBeNull(); - _destination.Values.ShouldContain("1"); - _destination.Values.ShouldContain("2"); - _destination.Values.ShouldContain("3"); - _destination.Values.ShouldContain("4"); - } + protected override void Because_of() + { + _destination = Mapper.Map(new Source { Values = new[] { 1, 2, 3, 4 } }); } - public class When_mapping_to_a_concrete_ilist : AutoMapperSpecBase + [Fact] + public void Should_map_the_list_of_source_items() { - private Destination _destination; + _destination.Values.ShouldNotBeNull(); + _destination.Values.ShouldContain("1"); + _destination.Values.ShouldContain("2"); + _destination.Values.ShouldContain("3"); + _destination.Values.ShouldContain("4"); + } +} - public class Source - { - public int[] Values { get; set; } - } +public class When_mapping_to_a_concrete_ilist : AutoMapperSpecBase +{ + private Destination _destination; - public class Destination - { - public IList Values { get; set; } - } + public class Source + { + public int[] Values { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - }); + public class Destination + { + public IList Values { get; set; } + } - protected override void Because_of() - { - _destination = Mapper.Map(new Source { Values = new[] { 1, 2, 3, 4 } }); - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + }); - [Fact] - public void Should_map_the_list_of_source_items() - { - _destination.Values.ShouldNotBeNull(); - _destination.Values.ShouldContain(1); - _destination.Values.ShouldContain(2); - _destination.Values.ShouldContain(3); - _destination.Values.ShouldContain(4); - } + protected override void Because_of() + { + _destination = Mapper.Map(new Source { Values = new[] { 1, 2, 3, 4 } }); } - public class When_mapping_to_a_concrete_generic_ilist : AutoMapperSpecBase + [Fact] + public void Should_map_the_list_of_source_items() { - private Destination _destination; + _destination.Values.ShouldNotBeNull(); + _destination.Values.ShouldContain(1); + _destination.Values.ShouldContain(2); + _destination.Values.ShouldContain(3); + _destination.Values.ShouldContain(4); + } +} - public class Source - { - public int[] Values { get; set; } - } +public class When_mapping_to_a_concrete_generic_ilist : AutoMapperSpecBase +{ + private Destination _destination; - public class Destination - { - public IList Values { get; set; } - } + public class Source + { + public int[] Values { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - }); + public class Destination + { + public IList Values { get; set; } + } - protected override void Because_of() - { - _destination = Mapper.Map(new Source { Values = new[] { 1, 2, 3, 4 } }); - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + }); - [Fact] - public void Should_map_the_list_of_source_items() - { - _destination.Values.ShouldNotBeNull(); - _destination.Values.ShouldContain("1"); - _destination.Values.ShouldContain("2"); - _destination.Values.ShouldContain("3"); - _destination.Values.ShouldContain("4"); - } + protected override void Because_of() + { + _destination = Mapper.Map(new Source { Values = new[] { 1, 2, 3, 4 } }); } - public class When_mapping_to_a_custom_list_with_the_same_type : AutoMapperSpecBase + [Fact] + public void Should_map_the_list_of_source_items() { - private Destination _destination; - private Source _source; + _destination.Values.ShouldNotBeNull(); + _destination.Values.ShouldContain("1"); + _destination.Values.ShouldContain("2"); + _destination.Values.ShouldContain("3"); + _destination.Values.ShouldContain("4"); + } +} - public class ValueCollection : Collection - { - } +public class When_mapping_to_a_custom_list_with_the_same_type : AutoMapperSpecBase +{ + private Destination _destination; + private Source _source; - public class Source - { - public ValueCollection Values { get; set; } - } + public class ValueCollection : Collection + { + } - public class Destination - { - public ValueCollection Values { get; set; } - } + public class Source + { + public ValueCollection Values { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - }); + public class Destination + { + public ValueCollection Values { get; set; } + } - protected override void Because_of() - { - _source = new Source { Values = new ValueCollection { 1, 2, 3, 4 } }; - _destination = Mapper.Map(_source); - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + }); - [Fact] - public void Should_assign_the_value_directly() - { - _source.Values.ShouldBe(_destination.Values); - } + protected override void Because_of() + { + _source = new Source { Values = new ValueCollection { 1, 2, 3, 4 } }; + _destination = Mapper.Map(_source); } - public class When_mapping_to_a_collection_with_instantiation_managed_by_the_destination : AutoMapperSpecBase + + [Fact] + public void Should_assign_the_value_directly() { - private Destination _destination; - private Source _source; + _source.Values.ShouldBe(_destination.Values); + } +} +public class When_mapping_to_a_collection_with_instantiation_managed_by_the_destination : AutoMapperSpecBase +{ + private Destination _destination; + private Source _source; - public class SourceItem - { - public int Value { get; set; } - } + public class SourceItem + { + public int Value { get; set; } + } - public class DestItem - { - public int Value { get; set; } - } + public class DestItem + { + public int Value { get; set; } + } - public class Source - { - public List Values { get; set; } - } + public class Source + { + public List Values { get; set; } + } - public class Destination - { - private List _values = new List(); + public class Destination + { + private List _values = new List(); - public List Values - { - get { return _values; } - } + public List Values + { + get { return _values; } } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ForMember(dest => dest.Values, opt => opt.UseDestinationValue()); - cfg.CreateMap(); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .ForMember(dest => dest.Values, opt => opt.UseDestinationValue()); + cfg.CreateMap(); + }); - protected override void Because_of() - { - _source = new Source { Values = new List { new SourceItem { Value = 5 }, new SourceItem { Value = 10 } } }; - _destination = Mapper.Map(_source); - } + protected override void Because_of() + { + _source = new Source { Values = new List { new SourceItem { Value = 5 }, new SourceItem { Value = 10 } } }; + _destination = Mapper.Map(_source); + } - [Fact] - public void Should_assign_the_value_directly() - { - _destination.Values.Count.ShouldBe(2); - _destination.Values[0].Value.ShouldBe(5); - _destination.Values[1].Value.ShouldBe(10); - } + [Fact] + public void Should_assign_the_value_directly() + { + _destination.Values.Count.ShouldBe(2); + _destination.Values[0].Value.ShouldBe(5); + _destination.Values[1].Value.ShouldBe(10); } +} + +public class When_mapping_to_an_existing_list_with_existing_items : AutoMapperSpecBase +{ + private Destination _destination; + private Source _source; - public class When_mapping_to_an_existing_list_with_existing_items : AutoMapperSpecBase + public class SourceItem { - private Destination _destination; - private Source _source; + public int Value { get; set; } + } - public class SourceItem - { - public int Value { get; set; } - } + public class DestItem + { + public int Value { get; set; } + } - public class DestItem - { - public int Value { get; set; } - } + public class Source + { + public List Values { get; set; } + } - public class Source - { - public List Values { get; set; } - } + public class Destination + { + private List _values = new List(); - public class Destination + public List Values { - private List _values = new List(); - - public List Values - { - get { return _values; } - } + get { return _values; } } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ForMember(dest => dest.Values, opt => opt.UseDestinationValue()); - cfg.CreateMap(); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .ForMember(dest => dest.Values, opt => opt.UseDestinationValue()); + cfg.CreateMap(); + }); - protected override void Because_of() - { - _source = new Source { Values = new List { new SourceItem { Value = 5 }, new SourceItem { Value = 10 } } }; - _destination = new Destination(); - _destination.Values.Add(new DestItem()); - Mapper.Map(_source, _destination); - } + protected override void Because_of() + { + _source = new Source { Values = new List { new SourceItem { Value = 5 }, new SourceItem { Value = 10 } } }; + _destination = new Destination(); + _destination.Values.Add(new DestItem()); + Mapper.Map(_source, _destination); + } - [Fact] - public void Should_clear_the_list_before_mapping() - { - _destination.Values.Count.ShouldBe(2); - } - } + [Fact] + public void Should_clear_the_list_before_mapping() + { + _destination.Values.Count.ShouldBe(2); + } +} - public class When_mapping_to_getter_only_list_with_existing_items : AutoMapperSpecBase +public class When_mapping_to_getter_only_list_with_existing_items : AutoMapperSpecBase +{ + public class SourceItem { - public class SourceItem - { - public int Value { get; set; } - } - public class DestItem - { - public int Value { get; set; } - } - public class Source - { - public List Values { get; set; } - public List IValues { get; set; } - } - public class Destination - { - public List Values { get; } = new(); - public IEnumerable IValues { get; } = new List(); - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - cfg.CreateMap(); - }); - [Fact] - public void Should_clear_the_list_before_mapping() - { - var destination = new Destination { Values = { new DestItem() } }; - ((List)destination.IValues).Add(new DestItem()); - Mapper.Map(new Source(), destination); - destination.Values.ShouldBeEmpty(); - destination.IValues.ShouldBeEmpty(); - } - } - public class When_mapping_to_list_with_existing_items : AutoMapperSpecBase + public int Value { get; set; } + } + public class DestItem { - public class SourceItem - { - public int Value { get; set; } - } - public class DestItem - { - public int Value { get; set; } - } - public class Source - { - public List Values { get; set; } = new(); - } - public class Destination - { - public List Values { get; set; } = new(); - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - cfg.CreateMap(); - }); - [Fact] - public void Should_clear_the_list_before_mapping() - { - var destination = new Destination { Values = { new DestItem { } } }; - Mapper.Map(new Source { Values = { new SourceItem { Value = 42 } } }, destination); - destination.Values.Single().Value.ShouldBe(42); - } - [Fact] - public void Should_clear_the_list_before_mapping_when_the_source_is_null() - { - var destination = new Destination { Values = { new DestItem { } } }; - Mapper.Map(new Source { Values = null }, destination); - destination.Values.ShouldBeEmpty(); - } + public int Value { get; set; } } - - public class When_mapping_a_collection_with_null_members : AutoMapperSpecBase + public class Source + { + public List Values { get; set; } + public List IValues { get; set; } + } + public class Destination { - const string FirstString = null; + public List Values { get; } = new(); + public IEnumerable IValues { get; } = new List(); + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + cfg.CreateMap(); + }); + [Fact] + public void Should_clear_the_list_before_mapping() + { + var destination = new Destination { Values = { new DestItem() } }; + ((List)destination.IValues).Add(new DestItem()); + Mapper.Map(new Source(), destination); + destination.Values.ShouldBeEmpty(); + destination.IValues.ShouldBeEmpty(); + } +} +public class When_mapping_to_list_with_existing_items : AutoMapperSpecBase +{ + public class SourceItem + { + public int Value { get; set; } + } + public class DestItem + { + public int Value { get; set; } + } + public class Source + { + public List Values { get; set; } = new(); + } + public class Destination + { + public List Values { get; set; } = new(); + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + cfg.CreateMap(); + }); + [Fact] + public void Should_clear_the_list_before_mapping() + { + var destination = new Destination { Values = { new DestItem { } } }; + Mapper.Map(new Source { Values = { new SourceItem { Value = 42 } } }, destination); + destination.Values.Single().Value.ShouldBe(42); + } + [Fact] + public void Should_clear_the_list_before_mapping_when_the_source_is_null() + { + var destination = new Destination { Values = { new DestItem { } } }; + Mapper.Map(new Source { Values = null }, destination); + destination.Values.ShouldBeEmpty(); + } +} - private IEnumerable _strings = new List { FirstString }; - private List _mappedStrings = new List(); +public class When_mapping_a_collection_with_null_members : AutoMapperSpecBase +{ + const string FirstString = null; - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.AllowNullDestinationValues = true; - }); + private IEnumerable _strings = new List { FirstString }; + private List _mappedStrings = new List(); - protected override void Because_of() - { - _mappedStrings = Mapper.Map, List>(_strings); - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.AllowNullDestinationValues = true; + }); - [Fact] - public void Should_map_correctly() - { - _mappedStrings.ShouldNotBeNull(); - _mappedStrings.Count.ShouldBe(1); - _mappedStrings[0].ShouldBeNull(); - } + protected override void Because_of() + { + _mappedStrings = Mapper.Map, List>(_strings); + } + + [Fact] + public void Should_map_correctly() + { + _mappedStrings.ShouldNotBeNull(); + _mappedStrings.Count.ShouldBe(1); + _mappedStrings[0].ShouldBeNull(); } } \ No newline at end of file diff --git a/src/UnitTests/AssertionExtensions.cs b/src/UnitTests/AssertionExtensions.cs index 60511b32c2..680236fa89 100644 --- a/src/UnitTests/AssertionExtensions.cs +++ b/src/UnitTests/AssertionExtensions.cs @@ -3,35 +3,34 @@ using System.Linq; using Shouldly; -namespace AutoMapper.UnitTests +namespace AutoMapper.UnitTests; + +public static class AssertionExtensions { - public static class AssertionExtensions - { - public static void ShouldContain(this IEnumerable items, object item) - => ShouldBeEnumerableTestExtensions.ShouldContain(items.Cast(), item); + public static void ShouldContain(this IEnumerable items, object item) + => ShouldBeEnumerableTestExtensions.ShouldContain(items.Cast(), item); - public static void ShouldBeEmpty(this IEnumerable items) - => ShouldBeEnumerableTestExtensions.ShouldBeEmpty(items.Cast()); + public static void ShouldBeEmpty(this IEnumerable items) + => ShouldBeEnumerableTestExtensions.ShouldBeEmpty(items.Cast()); - public static void ShouldBeThrownBy(this Type exceptionType, Action action) - => action.ShouldThrow(exceptionType); + public static void ShouldBeThrownBy(this Type exceptionType, Action action) + => action.ShouldThrow(exceptionType); - public static void ShouldThrowException(this Action action, Action customAssertion) where T : Exception + public static void ShouldThrowException(this Action action, Action customAssertion) where T : Exception + { + bool throws = false; + try { - bool throws = false; - try - { - action(); - } - catch (T e) - { - throws = true; - customAssertion(e); - } - throws.ShouldBeTrue(); + action(); } - - public static void ShouldNotBeThrownBy(this Type exceptionType, Action action) - => action.ShouldNotThrow(); + catch (T e) + { + throws = true; + customAssertion(e); + } + throws.ShouldBeTrue(); } + + public static void ShouldNotBeThrownBy(this Type exceptionType, Action action) + => action.ShouldNotThrow(); } \ No newline at end of file diff --git a/src/UnitTests/AutoMapperTester.cs b/src/UnitTests/AutoMapperTester.cs index 0abf96770f..f1c4130c37 100644 --- a/src/UnitTests/AutoMapperTester.cs +++ b/src/UnitTests/AutoMapperTester.cs @@ -2,40 +2,39 @@ using Shouldly; using Xunit; -namespace AutoMapper.UnitTests +namespace AutoMapper.UnitTests; + +public class AutoMapperTester : IDisposable { - public class AutoMapperTester : IDisposable + [Fact] + public void Should_be_able_to_handle_derived_proxy_types() + { + var config = new MapperConfiguration(cfg => cfg.CreateMap()); + var source = new[] { new DerivedModelType { TheProperty = "Foo" }, new DerivedModelType { TheProperty = "Bar" } }; + + var mapper = config.CreateMapper(); + var destination = (DtoType[])mapper.Map(source, typeof(ModelType[]), typeof(DtoType[])); + + destination[0].TheProperty.ShouldBe("Foo"); + destination[1].TheProperty.ShouldBe("Bar"); + } + + public void Dispose() + { + + } + + public class ModelType + { + public string TheProperty { get; set; } + } + + public class DerivedModelType : ModelType + { + } + + public class DtoType { - [Fact] - public void Should_be_able_to_handle_derived_proxy_types() - { - var config = new MapperConfiguration(cfg => cfg.CreateMap()); - var source = new[] { new DerivedModelType { TheProperty = "Foo" }, new DerivedModelType { TheProperty = "Bar" } }; - - var mapper = config.CreateMapper(); - var destination = (DtoType[])mapper.Map(source, typeof(ModelType[]), typeof(DtoType[])); - - destination[0].TheProperty.ShouldBe("Foo"); - destination[1].TheProperty.ShouldBe("Bar"); - } - - public void Dispose() - { - - } - - public class ModelType - { - public string TheProperty { get; set; } - } - - public class DerivedModelType : ModelType - { - } - - public class DtoType - { - public string TheProperty { get; set; } - } + public string TheProperty { get; set; } } } \ No newline at end of file diff --git a/src/UnitTests/BasicFlattening.cs b/src/UnitTests/BasicFlattening.cs index b972e6f77c..167292563a 100644 --- a/src/UnitTests/BasicFlattening.cs +++ b/src/UnitTests/BasicFlattening.cs @@ -4,235 +4,234 @@ using Shouldly; using System.Linq; -namespace AutoMapper.UnitTests +namespace AutoMapper.UnitTests; + +public class BasicFlattening : AutoMapperSpecBase { - public class BasicFlattening : AutoMapperSpecBase + public class Address { - public class Address - { - public int Id { get; set; } - public string Street { get; set; } - public string City { get; set; } - public string Country { get; set; } - } + public int Id { get; set; } + public string Street { get; set; } + public string City { get; set; } + public string Country { get; set; } + } - public class AddressDTO - { - public int Id { get; set; } - public string City { get; set; } - public string Country { get; set; } - } + public class AddressDTO + { + public int Id { get; set; } + public string City { get; set; } + public string Country { get; set; } + } - public class Customer - { - public int Id { get; set; } - public string Name { get; set; } - public decimal? Credit { get; set; } - public Address Address { get; set; } - public Address HomeAddress { get; set; } - public Address[] Addresses { get; set; } - public ICollection
WorkAddresses { get; set; } - } - - public class CustomerDTO - { - public int Id { get; set; } - public string Name { get; set; } - public Address Address { get; set; } - public AddressDTO HomeAddress { get; set; } - public AddressDTO[] Addresses { get; set; } - public List WorkAddresses { get; set; } - public string AddressCity { get; set; } - } - - public class Foo - { - public string Name { get; set; } + public class Customer + { + public int Id { get; set; } + public string Name { get; set; } + public decimal? Credit { get; set; } + public Address Address { get; set; } + public Address HomeAddress { get; set; } + public Address[] Addresses { get; set; } + public ICollection
WorkAddresses { get; set; } + } - public int Int32 { get; set; } + public class CustomerDTO + { + public int Id { get; set; } + public string Name { get; set; } + public Address Address { get; set; } + public AddressDTO HomeAddress { get; set; } + public AddressDTO[] Addresses { get; set; } + public List WorkAddresses { get; set; } + public string AddressCity { get; set; } + } - public long Int64 { set; get; } + public class Foo + { + public string Name { get; set; } - public int? NullInt { get; set; } + public int Int32 { get; set; } - public float Floatn { get; set; } + public long Int64 { set; get; } - public double Doublen { get; set; } + public int? NullInt { get; set; } - public DateTime DateTime { get; set; } + public float Floatn { get; set; } - public Foo Foo1 { get; set; } + public double Doublen { get; set; } - public IEnumerable Foos { get; set; } + public DateTime DateTime { get; set; } - public Foo[] FooArr { get; set; } + public Foo Foo1 { get; set; } - public int[] IntArr { get; set; } + public IEnumerable Foos { get; set; } - public IEnumerable Ints { get; set; } - } + public Foo[] FooArr { get; set; } + public int[] IntArr { get; set; } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - cfg.CreateMap(); - cfg.CreateMap(); - }); + public IEnumerable Ints { get; set; } + } - [Fact] - public void Should_map() - { - Mapper.Map(new Customer()); - } - [Fact] - public void Should_map_foo() - { - Mapper.Map(new Foo - { - Name = "foo", - Int32 = 12, - Int64 = 123123, - NullInt = 16, - DateTime = DateTime.Now, - Doublen = 2312112, - Foo1 = new Foo { Name = "foo one" }, - Foos = new List - { - new Foo {Name = "j1", Int64 = 123, NullInt = 321}, - new Foo {Name = "j2", Int32 = 12345, NullInt = 54321}, - new Foo {Name = "j3", Int32 = 12345, NullInt = 54321}, - }, - FooArr = new[] - { - new Foo {Name = "a1"}, - new Foo {Name = "a2"}, - new Foo {Name = "a3"}, - }, - IntArr = new[] { 1, 2, 3, 4, 5 }, - Ints = new[] { 7, 8, 9 }, - }); - } - } - - public class NullFlattening : AutoMapperSpecBase - { - Destination _destination; - - public class Source - { - public Source Parent { get; set; } - public Data Data { get; set; } - } - public class Data - { - public int? Integer { get; set; } - } - public class Destination - { - public int? ParentDataInteger { get; set; } - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + cfg.CreateMap(); + cfg.CreateMap(); + }); - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); + [Fact] + public void Should_map() + { + Mapper.Map(new Customer()); + } + + [Fact] + public void Should_map_foo() + { + Mapper.Map(new Foo + { + Name = "foo", + Int32 = 12, + Int64 = 123123, + NullInt = 16, + DateTime = DateTime.Now, + Doublen = 2312112, + Foo1 = new Foo { Name = "foo one" }, + Foos = new List + { + new Foo {Name = "j1", Int64 = 123, NullInt = 321}, + new Foo {Name = "j2", Int32 = 12345, NullInt = 54321}, + new Foo {Name = "j3", Int32 = 12345, NullInt = 54321}, + }, + FooArr = new[] + { + new Foo {Name = "a1"}, + new Foo {Name = "a2"}, + new Foo {Name = "a3"}, + }, + IntArr = new[] { 1, 2, 3, 4, 5 }, + Ints = new[] { 7, 8, 9 }, }); + } +} - protected override void Because_of() - { - _destination = Mapper.Map(new Source()); - } +public class NullFlattening : AutoMapperSpecBase +{ + Destination _destination; - [Fact] - public void Should_handle_inner_nulls() - { - _destination.ParentDataInteger.ShouldBeNull(); - } + public class Source + { + public Source Parent { get; set; } + public Data Data { get; set; } + } + public class Data + { + public int? Integer { get; set; } + } + public class Destination + { + public int? ParentDataInteger { get; set; } } - public class NullTypeMapFlattening : AutoMapperSpecBase + protected override MapperConfiguration CreateConfiguration() => new(cfg => { - private OrderDTO _dto; + cfg.CreateMap(); + }); - public class OrderModel - { - public VendorModel Vendor { get; set; } - public string Number { get; set; } - } + protected override void Because_of() + { + _destination = Mapper.Map(new Source()); + } - public class VendorModel - { - public string Name { get; set; } - public CurrencyModel Currency { get; set; } - } + [Fact] + public void Should_handle_inner_nulls() + { + _destination.ParentDataInteger.ShouldBeNull(); + } +} - public class CurrencyModel - { - public string Name { get; set; } - } +public class NullTypeMapFlattening : AutoMapperSpecBase +{ + private OrderDTO _dto; + public class OrderModel + { + public VendorModel Vendor { get; set; } + public string Number { get; set; } + } - public class OrderDTO - { - public CurrencyDTO VendorCurrency { get; set; } - public string VendorName { get; set; } - public string Number { get; set; } - } + public class VendorModel + { + public string Name { get; set; } + public CurrencyModel Currency { get; set; } + } - public class CurrencyDTO - { - public string Name { get; set; } - } + public class CurrencyModel + { + public string Name { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - cfg.CreateMap(); - }); - protected override void Because_of() - { - var orderModel = new OrderModel() - { - Number = "1", - Vendor = null - }; - _dto = Mapper.Map(orderModel); - } - - [Fact] - public void Should_handle_inner_nulls() - { - _dto.VendorCurrency.ShouldBeNull(); - } + public class OrderDTO + { + public CurrencyDTO VendorCurrency { get; set; } + public string VendorName { get; set; } + public string Number { get; set; } } - public class FlatteningWithSourceValidation : NonValidatingSpecBase + public class CurrencyDTO { - public class Customer - { - public int Id { get; set; } - public int AnotherId { get; set; } - public string Name { get; set; } - public Address Address { get; set; } - } - public class Address - { - public int Id { get; set; } - public string Street { get; set; } - public string City { get; set; } - public string Country { get; set; } - } - public class CustomerDTO + public string Name { get; set; } + } + + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + cfg.CreateMap(); + }); + + protected override void Because_of() + { + var orderModel = new OrderModel() { - public int Id { get; set; } - public string Name { get; set; } - public string AddressCity { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.CreateMap(MemberList.Source).ForMember(d=>d.Id, o=>o.MapFrom(s=>s.AnotherId))); - [Fact] - public void Should_validate() => - new Action(AssertConfigurationIsValid).ShouldThrow().Errors.Single().UnmappedPropertyNames.Single().ShouldBe(nameof(Address.Id)); + Number = "1", + Vendor = null + }; + _dto = Mapper.Map(orderModel); + } + + [Fact] + public void Should_handle_inner_nulls() + { + _dto.VendorCurrency.ShouldBeNull(); + } +} + +public class FlatteningWithSourceValidation : NonValidatingSpecBase +{ + public class Customer + { + public int Id { get; set; } + public int AnotherId { get; set; } + public string Name { get; set; } + public Address Address { get; set; } + } + public class Address + { + public int Id { get; set; } + public string Street { get; set; } + public string City { get; set; } + public string Country { get; set; } + } + public class CustomerDTO + { + public int Id { get; set; } + public string Name { get; set; } + public string AddressCity { get; set; } } + protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.CreateMap(MemberList.Source).ForMember(d=>d.Id, o=>o.MapFrom(s=>s.AnotherId))); + [Fact] + public void Should_validate() => + new Action(AssertConfigurationIsValid).ShouldThrow().Errors.Single().UnmappedPropertyNames.Single().ShouldBe(nameof(Address.Id)); } \ No newline at end of file diff --git a/src/UnitTests/BeforeAfterMapping.cs b/src/UnitTests/BeforeAfterMapping.cs index 8f7f25ee90..e37d45f8fa 100644 --- a/src/UnitTests/BeforeAfterMapping.cs +++ b/src/UnitTests/BeforeAfterMapping.cs @@ -2,325 +2,324 @@ using Shouldly; using Xunit; -namespace AutoMapper.UnitTests.BeforeAfterMapping +namespace AutoMapper.UnitTests.BeforeAfterMapping; + +using Bug; + +public class When_configuring_before_and_after_methods { - using Bug; + public class Source + { + } + public class Destination + { + } - public class When_configuring_before_and_after_methods + [Fact] + public void Before_and_After_should_be_called() { - public class Source - { - } - public class Destination - { - } + var beforeMapCalled = false; + var afterMapCalled = false; - [Fact] - public void Before_and_After_should_be_called() - { - var beforeMapCalled = false; - var afterMapCalled = false; + var config = new MapperConfiguration(cfg => cfg.CreateMap() + .BeforeMap((src, dest) => beforeMapCalled = true) + .AfterMap((src, dest) => afterMapCalled = true)); - var config = new MapperConfiguration(cfg => cfg.CreateMap() - .BeforeMap((src, dest) => beforeMapCalled = true) - .AfterMap((src, dest) => afterMapCalled = true)); + var mapper = config.CreateMapper(); - var mapper = config.CreateMapper(); + mapper.Map(new Source()); - mapper.Map(new Source()); + beforeMapCalled.ShouldBeTrue(); + afterMapCalled.ShouldBeTrue(); + } - beforeMapCalled.ShouldBeTrue(); - afterMapCalled.ShouldBeTrue(); - } + [Fact] + public void Before_and_After_overrides_should_be_called() + { + var beforeMapCalled = false; + var afterMapCalled = false; - [Fact] - public void Before_and_After_overrides_should_be_called() + var config = new MapperConfiguration(cfg => { - var beforeMapCalled = false; - var afterMapCalled = false; - - var config = new MapperConfiguration(cfg => + cfg.CreateMap(); + cfg.ForAllMaps((map, expression) => { - cfg.CreateMap(); - cfg.ForAllMaps((map, expression) => - { - expression.BeforeMap((src, dest, context) => beforeMapCalled = true); - expression.AfterMap((src, dest, context) => afterMapCalled = true); - }); + expression.BeforeMap((src, dest, context) => beforeMapCalled = true); + expression.AfterMap((src, dest, context) => afterMapCalled = true); }); + }); - var mapper = config.CreateMapper(); + var mapper = config.CreateMapper(); - mapper.Map(new Source()); + mapper.Map(new Source()); - beforeMapCalled.ShouldBeTrue(); - afterMapCalled.ShouldBeTrue(); - } + beforeMapCalled.ShouldBeTrue(); + afterMapCalled.ShouldBeTrue(); + } +} + +public class When_configuring_before_and_after_methods_multiple_times +{ + public class Source + { + } + public class Destination + { } - public class When_configuring_before_and_after_methods_multiple_times + [Fact] + public void Before_and_After_should_be_called() { - public class Source - { - } - public class Destination - { - } + var beforeMapCount = 0; + var afterMapCount = 0; - [Fact] - public void Before_and_After_should_be_called() + var config = new MapperConfiguration(cfg => { - var beforeMapCount = 0; - var afterMapCount = 0; + cfg.CreateMap() + .BeforeMap((src, dest) => beforeMapCount++) + .BeforeMap((src, dest) => beforeMapCount++) + .AfterMap((src, dest) => afterMapCount++) + .AfterMap((src, dest) => afterMapCount++); + }); - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap() - .BeforeMap((src, dest) => beforeMapCount++) - .BeforeMap((src, dest) => beforeMapCount++) - .AfterMap((src, dest) => afterMapCount++) - .AfterMap((src, dest) => afterMapCount++); - }); + var mapper = config.CreateMapper(); - var mapper = config.CreateMapper(); + mapper.Map(new Source()); - mapper.Map(new Source()); + beforeMapCount.ShouldBe(2); + afterMapCount.ShouldBe(2); + } - beforeMapCount.ShouldBe(2); - afterMapCount.ShouldBe(2); - } + [Fact] + public void Before_and_After_overrides_should_be_called() + { + var beforeMapCount = 0; + var afterMapCount = 0; - [Fact] - public void Before_and_After_overrides_should_be_called() + var config = new MapperConfiguration(cfg => { - var beforeMapCount = 0; - var afterMapCount = 0; - - var config = new MapperConfiguration(cfg => + cfg.CreateMap(); + cfg.ForAllMaps((map, expression) => { - cfg.CreateMap(); - cfg.ForAllMaps((map, expression) => - { - expression.BeforeMap((src, dest, context) => beforeMapCount++) - .BeforeMap((src, dest, context) => beforeMapCount++); - expression.AfterMap((src, dest, context) => afterMapCount++) - .AfterMap((src, dest, context) => afterMapCount++); - }); + expression.BeforeMap((src, dest, context) => beforeMapCount++) + .BeforeMap((src, dest, context) => beforeMapCount++); + expression.AfterMap((src, dest, context) => afterMapCount++) + .AfterMap((src, dest, context) => afterMapCount++); }); + }); - var mapper = config.CreateMapper(); + var mapper = config.CreateMapper(); - mapper.Map(new Source()); - - beforeMapCount.ShouldBe(2); - afterMapCount.ShouldBe(2); - } + mapper.Map(new Source()); + beforeMapCount.ShouldBe(2); + afterMapCount.ShouldBe(2); } - public class When_using_a_class_to_do_before_after_mappings : AutoMapperSpecBase - { - private Destination _destination; - - public class Source - { - public int Value { get; set; } - } - - public class Destination - { - public int Value { get; set; } - } - - public class BeforeMapAction : IMappingAction - { - private readonly int _decrement; - - public BeforeMapAction(int decrement) - { - _decrement = decrement; - } - - public void Process(Source source, Destination destination, ResolutionContext context) - { - source.Value -= _decrement * 2; - } - } - - public class AfterMapAction : IMappingAction - { - private readonly int _increment; +} - public AfterMapAction(int increment) - { - _increment = increment; - } +public class When_using_a_class_to_do_before_after_mappings : AutoMapperSpecBase +{ + private Destination _destination; - public void Process(Source source, Destination destination, ResolutionContext context) - { - destination.Value += _increment * 5; - } - } + public class Source + { + public int Value { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.ConstructServicesUsing(t => Activator.CreateInstance(t, 2)); + public class Destination + { + public int Value { get; set; } + } - cfg.CreateMap() - .BeforeMap() - .AfterMap(); - }); + public class BeforeMapAction : IMappingAction + { + private readonly int _decrement; - protected override void Because_of() + public BeforeMapAction(int decrement) { - _destination = Mapper.Map(new Source {Value = 4}); + _decrement = decrement; } - [Fact] - public void Should_use_global_constructor_for_building_mapping_actions() + public void Process(Source source, Destination destination, ResolutionContext context) { - _destination.Value.ShouldBe(10); + source.Value -= _decrement * 2; } } - public class When_using_a_class_to_do_before_after_mappings_with_resolutioncontext : AutoMapperSpecBase + public class AfterMapAction : IMappingAction { - private Destination _destination; + private readonly int _increment; - public class Source + public AfterMapAction(int increment) { - public int Value { get; set; } + _increment = increment; } - public class Destination + public void Process(Source source, Destination destination, ResolutionContext context) { - public int Value { get; set; } + destination.Value += _increment * 5; } + } - public class BeforeMapAction : IMappingAction - { - private readonly int _decrement; + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.ConstructServicesUsing(t => Activator.CreateInstance(t, 2)); - public BeforeMapAction(int decrement) - { - _decrement = decrement; - } + cfg.CreateMap() + .BeforeMap() + .AfterMap(); + }); - public void Process(Source source, Destination destination, ResolutionContext context) - { - var customMultiplier = (int)context.Items["CustomMultiplier"]; - source.Value -= _decrement * 2 * customMultiplier; - } - } + protected override void Because_of() + { + _destination = Mapper.Map(new Source {Value = 4}); + } - public class AfterMapAction : IMappingAction - { - private readonly int _increment; + [Fact] + public void Should_use_global_constructor_for_building_mapping_actions() + { + _destination.Value.ShouldBe(10); + } +} - public AfterMapAction(int increment) - { - _increment = increment; - } +public class When_using_a_class_to_do_before_after_mappings_with_resolutioncontext : AutoMapperSpecBase +{ + private Destination _destination; - public void Process(Source source, Destination destination, ResolutionContext context) - { - var customMultiplier = (int)context.Items["CustomMultiplier"]; - destination.Value += _increment * 5 * customMultiplier; - } - } + public class Source + { + public int Value { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.ConstructServicesUsing(t => Activator.CreateInstance(t, 2)); + public class Destination + { + public int Value { get; set; } + } - cfg.CreateMap() - .BeforeMap() - .AfterMap(); - }); + public class BeforeMapAction : IMappingAction + { + private readonly int _decrement; - protected override void Because_of() + public BeforeMapAction(int decrement) { - _destination = Mapper.Map(new Source { Value = 4 }, opt => opt.Items["CustomMultiplier"] = 10); + _decrement = decrement; } - [Fact] - public void Should_use_global_constructor_for_building_mapping_actions() + public void Process(Source source, Destination destination, ResolutionContext context) { - _destination.Value.ShouldBe(64); + var customMultiplier = (int)context.Items["CustomMultiplier"]; + source.Value -= _decrement * 2 * customMultiplier; } } - public class MappingSpecificBeforeMapping : AutoMapperSpecBase + public class AfterMapAction : IMappingAction { - private Dest _dest; + private readonly int _increment; - public class Source + public AfterMapAction(int increment) { - public int Value { get; set; } + _increment = increment; } - public class Dest + public void Process(Source source, Destination destination, ResolutionContext context) { - public int Value { get; set; } + var customMultiplier = (int)context.Items["CustomMultiplier"]; + destination.Value += _increment * 5 * customMultiplier; } + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.ConstructServicesUsing(t => Activator.CreateInstance(t, 2)); - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .BeforeMap((src, dest) => src.Value += 10); - }); + cfg.CreateMap() + .BeforeMap() + .AfterMap(); + }); - protected override void Because_of() - { - _dest = Mapper.Map(new Source - { - Value = 5 - }, opt => opt.BeforeMap((src, dest) => src.Value += 10)); - } + protected override void Because_of() + { + _destination = Mapper.Map(new Source { Value = 4 }, opt => opt.Items["CustomMultiplier"] = 10); + } - [Fact] - public void Should_execute_typemap_and_scoped_beforemap() - { - _dest.Value.ShouldBe(25); - } + [Fact] + public void Should_use_global_constructor_for_building_mapping_actions() + { + _destination.Value.ShouldBe(64); + } +} + +public class MappingSpecificBeforeMapping : AutoMapperSpecBase +{ + private Dest _dest; + + public class Source + { + public int Value { get; set; } } - public class MappingSpecificAfterMapping : AutoMapperSpecBase + public class Dest { - private Dest _dest; + public int Value { get; set; } + } - public class Source - { - public int Value { get; set; } - } - public class Dest + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .BeforeMap((src, dest) => src.Value += 10); + }); + + protected override void Because_of() + { + _dest = Mapper.Map(new Source { - public int Value { get; set; } - } + Value = 5 + }, opt => opt.BeforeMap((src, dest) => src.Value += 10)); + } + [Fact] + public void Should_execute_typemap_and_scoped_beforemap() + { + _dest.Value.ShouldBe(25); + } +} - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .AfterMap((src, dest) => dest.Value += 10); - }); +public class MappingSpecificAfterMapping : AutoMapperSpecBase +{ + private Dest _dest; - protected override void Because_of() - { - _dest = Mapper.Map(new Source - { - Value = 5 - }, opt => opt.AfterMap((src, dest) => dest.Value += 10)); - } + public class Source + { + public int Value { get; set; } + } + + public class Dest + { + public int Value { get; set; } + } - [Fact] - public void Should_execute_typemap_and_scoped_aftermap() + + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .AfterMap((src, dest) => dest.Value += 10); + }); + + protected override void Because_of() + { + _dest = Mapper.Map(new Source { - _dest.Value.ShouldBe(25); - } + Value = 5 + }, opt => opt.AfterMap((src, dest) => dest.Value += 10)); } + [Fact] + public void Should_execute_typemap_and_scoped_aftermap() + { + _dest.Value.ShouldBe(25); + } } + diff --git a/src/UnitTests/BidirectionalRelationships.cs b/src/UnitTests/BidirectionalRelationships.cs index 4541560732..075e04d197 100644 --- a/src/UnitTests/BidirectionalRelationships.cs +++ b/src/UnitTests/BidirectionalRelationships.cs @@ -6,536 +6,535 @@ using Xunit; -namespace AutoMapper.UnitTests. BidirectionalRelationships +namespace AutoMapper.UnitTests. BidirectionalRelationships; + +public class RecursiveMappingWithStruct : AutoMapperSpecBase { - public class RecursiveMappingWithStruct : AutoMapperSpecBase + private ParentDto _dto; + + protected override MapperConfiguration CreateConfiguration() => new(cfg => { - private ParentDto _dto; + cfg.CreateMap(); + cfg.CreateMap(); + cfg.CreateMap(); + }); - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - cfg.CreateMap(); - cfg.CreateMap(); - }); + [Fact] + public void Should_work() + { + var parent = new ParentModel { ID = "PARENT_ONE" }; + parent.ChildrenStruct = new ChildrenStructModel { Children = new List() }; - [Fact] - public void Should_work() - { - var parent = new ParentModel { ID = "PARENT_ONE" }; - parent.ChildrenStruct = new ChildrenStructModel { Children = new List() }; + parent.AddChild(new ChildModel { ID = "CHILD_ONE" }); - parent.AddChild(new ChildModel { ID = "CHILD_ONE" }); + parent.AddChild(new ChildModel { ID = "CHILD_TWO" }); - parent.AddChild(new ChildModel { ID = "CHILD_TWO" }); + _dto = Mapper.Map(parent); - _dto = Mapper.Map(parent); + _dto.ID.ShouldBe("PARENT_ONE"); + _dto.ChildrenStruct.Children[0].ID.ShouldBe("CHILD_ONE"); + _dto.ChildrenStruct.Children[1].ID.ShouldBe("CHILD_TWO"); + } - _dto.ID.ShouldBe("PARENT_ONE"); - _dto.ChildrenStruct.Children[0].ID.ShouldBe("CHILD_ONE"); - _dto.ChildrenStruct.Children[1].ID.ShouldBe("CHILD_TWO"); - } + public struct ParentModel + { + public string ID { get; set; } - public struct ParentModel + public ChildrenStructModel ChildrenStruct { get; set; } + + public void AddChild(ChildModel child) { - public string ID { get; set; } + child.Parent = this; + ChildrenStruct.Children.Add(child); + } + } - public ChildrenStructModel ChildrenStruct { get; set; } + public struct ChildrenStructModel + { + public IList Children { get; set; } + } - public void AddChild(ChildModel child) - { - child.Parent = this; - ChildrenStruct.Children.Add(child); - } - } + public struct ChildModel + { + public string ID { get; set; } + public ParentModel Parent { get; set; } + } - public struct ChildrenStructModel - { - public IList Children { get; set; } - } + public struct ParentDto + { + public string ID { get; set; } + public ChildrenStructDto ChildrenStruct { get; set; } + } - public struct ChildModel - { - public string ID { get; set; } - public ParentModel Parent { get; set; } - } + public struct ChildrenStructDto + { + public IList Children { get; set; } + } - public struct ParentDto - { - public string ID { get; set; } - public ChildrenStructDto ChildrenStruct { get; set; } - } + public struct ChildDto + { + public string ID { get; set; } + public ParentDto Parent { get; set; } + } +} - public struct ChildrenStructDto +public class When_mapping_to_a_destination_with_a_bidirectional_parent_one_to_many_child_relationship : AutoMapperSpecBase +{ + private ParentDto _dto; + + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().PreserveReferences(); + cfg.CreateMap(); + }); + + protected override void Because_of() + { + var parent = new ParentModel { ID = "PARENT_ONE" }; + + parent.AddChild(new ChildModel { ID = "CHILD_ONE" }); + + parent.AddChild(new ChildModel { ID = "CHILD_TWO" }); + + _dto = Mapper.Map(parent); + } + + [Fact] + public void Should_preserve_the_parent_child_relationship_on_the_destination() + { + _dto.Children[0].Parent.ShouldBeSameAs(_dto); + _dto.Children[1].Parent.ShouldBeSameAs(_dto); + } + + public class ParentModel + { + public ParentModel() { - public IList Children { get; set; } + Children = new List(); } - public struct ChildDto + public string ID { get; set; } + + public IList Children { get; private set; } + + public void AddChild(ChildModel child) { - public string ID { get; set; } - public ParentDto Parent { get; set; } + child.Parent = this; + Children.Add(child); } } - public class When_mapping_to_a_destination_with_a_bidirectional_parent_one_to_many_child_relationship : AutoMapperSpecBase + public class ChildModel { - private ParentDto _dto; - - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().PreserveReferences(); - cfg.CreateMap(); - }); + public string ID { get; set; } + public ParentModel Parent { get; set; } + } - protected override void Because_of() - { - var parent = new ParentModel { ID = "PARENT_ONE" }; + public class ParentDto + { + public string ID { get; set; } + public IList Children { get; set; } + } - parent.AddChild(new ChildModel { ID = "CHILD_ONE" }); + public class ChildDto + { + public string ID { get; set; } + public ParentDto Parent { get; set; } + } +} - parent.AddChild(new ChildModel { ID = "CHILD_TWO" }); +public class RecursiveDynamicMapping : AutoMapperSpecBase +{ + private ParentDto _dto; - _dto = Mapper.Map(parent); - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(typeof(ParentModel<>), typeof(ParentDto<>)); + cfg.CreateMap(typeof(ChildModel<>), typeof(ChildDto<>)); + }); - [Fact] - public void Should_preserve_the_parent_child_relationship_on_the_destination() - { - _dto.Children[0].Parent.ShouldBeSameAs(_dto); - _dto.Children[1].Parent.ShouldBeSameAs(_dto); - } + protected override void Because_of() + { + var parent = new ParentModel { ID = "PARENT_ONE" }; - public class ParentModel - { - public ParentModel() - { - Children = new List(); - } + parent.AddChild(new ChildModel { ID = "CHILD_ONE" }); - public string ID { get; set; } + parent.AddChild(new ChildModel { ID = "CHILD_TWO" }); - public IList Children { get; private set; } + _dto = Mapper.Map, ParentDto>(parent); + } - public void AddChild(ChildModel child) - { - child.Parent = this; - Children.Add(child); - } - } + [Fact] + public void Should_preserve_the_parent_child_relationship_on_the_destination() + { + _dto.Children[0].Parent.ShouldBeSameAs(_dto); + _dto.Children[1].Parent.ShouldBeSameAs(_dto); + } - public class ChildModel + public class ParentModel + { + public ParentModel() { - public string ID { get; set; } - public ParentModel Parent { get; set; } + Children = new List>(); } - public class ParentDto - { - public string ID { get; set; } - public IList Children { get; set; } - } + public string ID { get; set; } + + public IList> Children { get; private set; } - public class ChildDto + public void AddChild(ChildModel child) { - public string ID { get; set; } - public ParentDto Parent { get; set; } + child.Parent = this; + Children.Add(child); } } - public class RecursiveDynamicMapping : AutoMapperSpecBase + public class ChildModel { - private ParentDto _dto; - - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(typeof(ParentModel<>), typeof(ParentDto<>)); - cfg.CreateMap(typeof(ChildModel<>), typeof(ChildDto<>)); - }); - - protected override void Because_of() - { - var parent = new ParentModel { ID = "PARENT_ONE" }; + public string ID { get; set; } + public ParentModel Parent { get; set; } + } - parent.AddChild(new ChildModel { ID = "CHILD_ONE" }); + public class ParentDto + { + public string ID { get; set; } + public IList> Children { get; set; } + } - parent.AddChild(new ChildModel { ID = "CHILD_TWO" }); + public class ChildDto + { + public string ID { get; set; } + public ParentDto Parent { get; set; } + } +} - _dto = Mapper.Map, ParentDto>(parent); - } +public class When_mapping_to_a_destination_with_a_bidirectional_parent_one_to_many_child_relationship_using_CustomMapper_with_context : AutoMapperSpecBase +{ + private ParentDto _dto; + private static ParentModel _parent; - [Fact] - public void Should_preserve_the_parent_child_relationship_on_the_destination() + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + _parent = new ParentModel { - _dto.Children[0].Parent.ShouldBeSameAs(_dto); - _dto.Children[1].Parent.ShouldBeSameAs(_dto); - } + ID = 2 + }; - public class ParentModel + List childModels = new List { - public ParentModel() + new ChildModel { - Children = new List>(); + ID = 1, + Parent = _parent } + }; - public string ID { get; set; } + Dictionary parents = childModels.ToDictionary(x => x.ID, x => x.Parent); - public IList> Children { get; private set; } + cfg.CreateMap().ConvertUsing(new ChildIdToParentDtoConverter(parents)); + cfg.CreateMap>().ConvertUsing(new ParentIdToChildDtoListConverter(childModels)); - public void AddChild(ChildModel child) - { - child.Parent = this; - Children.Add(child); - } + cfg.CreateMap() + .PreserveReferences() + .ForMember(dest => dest.Children, opt => opt.MapFrom(src => src.ID)); + cfg.CreateMap(); + }); + + protected override void Because_of() + { + _dto = Mapper.Map(_parent); + } + + [Fact] + public void Should_preserve_the_parent_child_relationship_on_the_destination() + { + _dto.Children[0].Parent.ID.ShouldBe(_dto.ID); + } + + public class ChildIdToParentDtoConverter : ITypeConverter + { + private readonly Dictionary _parentModels; + + public ChildIdToParentDtoConverter(Dictionary parentModels) + { + _parentModels = parentModels; } - public class ChildModel + public ParentDto Convert(int source, ParentDto destination, ResolutionContext resolutionContext) { - public string ID { get; set; } - public ParentModel Parent { get; set; } + ParentModel parentModel = _parentModels[source]; + return (ParentDto) resolutionContext.Mapper.Map(parentModel, destination, typeof(ParentModel), typeof(ParentDto)); } + } - public class ParentDto + public class ParentIdToChildDtoListConverter : ITypeConverter> + { + private readonly IList _childModels; + + public ParentIdToChildDtoListConverter(IList childModels) { - public string ID { get; set; } - public IList> Children { get; set; } + _childModels = childModels; } - public class ChildDto + public List Convert(int source, List destination, ResolutionContext resolutionContext) { - public string ID { get; set; } - public ParentDto Parent { get; set; } + List childModels = _childModels.Where(x => x.Parent.ID == source).ToList(); + return (List)resolutionContext.Mapper.Map(childModels, destination, typeof(List), typeof(List)); } } - public class When_mapping_to_a_destination_with_a_bidirectional_parent_one_to_many_child_relationship_using_CustomMapper_with_context : AutoMapperSpecBase + public class ParentModel { - private ParentDto _dto; - private static ParentModel _parent; + public int ID { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - _parent = new ParentModel - { - ID = 2 - }; + public class ChildModel + { + public int ID { get; set; } + public ParentModel Parent { get; set; } + } - List childModels = new List - { - new ChildModel - { - ID = 1, - Parent = _parent - } - }; + public class ParentDto + { + public int ID { get; set; } + public List Children { get; set; } + } - Dictionary parents = childModels.ToDictionary(x => x.ID, x => x.Parent); + public class ChildDto + { + public int ID { get; set; } + public ParentDto Parent { get; set; } + } +} - cfg.CreateMap().ConvertUsing(new ChildIdToParentDtoConverter(parents)); - cfg.CreateMap>().ConvertUsing(new ParentIdToChildDtoListConverter(childModels)); +public class When_mapping_to_a_destination_with_a_bidirectional_parent_one_to_one_child_relationship : AutoMapperSpecBase +{ + private FooDto _dto; - cfg.CreateMap() - .PreserveReferences() - .ForMember(dest => dest.Children, opt => opt.MapFrom(src => src.ID)); - cfg.CreateMap(); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().PreserveReferences(); + cfg.CreateMap(); + }); - protected override void Because_of() - { - _dto = Mapper.Map(_parent); - } + protected override void Because_of() + { + var foo = new Foo + { + Bar = new Bar + { + Value = "something" + } + }; + foo.Bar.Foo = foo; + _dto = Mapper.Map(foo); + } - [Fact] - public void Should_preserve_the_parent_child_relationship_on_the_destination() - { - _dto.Children[0].Parent.ID.ShouldBe(_dto.ID); - } + [Fact] + public void Should_preserve_the_parent_child_relationship_on_the_destination() + { + _dto.Bar.Foo.ShouldBeSameAs(_dto); + } - public class ChildIdToParentDtoConverter : ITypeConverter - { - private readonly Dictionary _parentModels; + public class Foo + { + public Bar Bar { get; set; } + } - public ChildIdToParentDtoConverter(Dictionary parentModels) - { - _parentModels = parentModels; - } + public class Bar + { + public Foo Foo { get; set; } + public string Value { get; set; } + } - public ParentDto Convert(int source, ParentDto destination, ResolutionContext resolutionContext) - { - ParentModel parentModel = _parentModels[source]; - return (ParentDto) resolutionContext.Mapper.Map(parentModel, destination, typeof(ParentModel), typeof(ParentDto)); - } - } + public class FooDto + { + public BarDto Bar { get; set; } + } - public class ParentIdToChildDtoListConverter : ITypeConverter> - { - private readonly IList _childModels; + public class BarDto + { + public FooDto Foo { get; set; } + public string Value { get; set; } + } +} - public ParentIdToChildDtoListConverter(IList childModels) - { - _childModels = childModels; - } +public class When_mapping_to_a_destination_containing_two_dtos_mapped_from_the_same_source : AutoMapperSpecBase +{ + private FooContainerModel _dto; - public List Convert(int source, List destination, ResolutionContext resolutionContext) - { - List childModels = _childModels.Where(x => x.Parent.ID == source).ToList(); - return (List)resolutionContext.Mapper.Map(childModels, destination, typeof(List), typeof(List)); - } - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + cfg.CreateMap(); + cfg.CreateMap() + .PreserveReferences() + .ForMember(dest => dest.Input, opt => opt.MapFrom(src => src)) + .ForMember(dest => dest.Screen, opt => opt.MapFrom(src => src)); + }); + + protected override void Because_of() + { + var model = new FooModel { Id = 3 }; + _dto = Mapper.Map(model); + } - public class ParentModel - { - public int ID { get; set; } - } + [Fact] + public void Should_not_preserve_identity_when_destinations_are_incompatible() + { + _dto.ShouldBeOfType(); + _dto.Input.ShouldBeOfType(); + _dto.Screen.ShouldBeOfType(); + _dto.Input.Id.ShouldBe(3); + _dto.Screen.Id.ShouldBe("3"); + } - public class ChildModel - { - public int ID { get; set; } - public ParentModel Parent { get; set; } - } + public class FooContainerModel + { + public FooInputModel Input { get; set; } + public FooScreenModel Screen { get; set; } + } - public class ParentDto - { - public int ID { get; set; } - public List Children { get; set; } - } + public class FooScreenModel + { + public string Id { get; set; } + } - public class ChildDto - { - public int ID { get; set; } - public ParentDto Parent { get; set; } - } + public class FooInputModel + { + public long Id { get; set; } } - public class When_mapping_to_a_destination_with_a_bidirectional_parent_one_to_one_child_relationship : AutoMapperSpecBase + public class FooModel { - private FooDto _dto; + public long Id { get; set; } + } +} - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().PreserveReferences(); - cfg.CreateMap(); - }); +public class When_mapping_with_a_bidirectional_relationship_that_includes_arrays : AutoMapperSpecBase - protected override void Because_of() - { - var foo = new Foo - { - Bar = new Bar - { - Value = "something" - } - }; - foo.Bar.Foo = foo; - _dto = Mapper.Map(foo); - } +{ + private ParentDto _dtoParent; - [Fact] - public void Should_preserve_the_parent_child_relationship_on_the_destination() - { - _dto.Bar.Foo.ShouldBeSameAs(_dto); - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().PreserveReferences(); + cfg.CreateMap(); - public class Foo - { - public Bar Bar { get; set; } - } + }); - public class Bar - { - public Foo Foo { get; set; } - public string Value { get; set; } - } + protected override void Because_of() + { + var parent1 = new Parent { Name = "Parent 1" }; + var child1 = new Child { Name = "Child 1" }; - public class FooDto - { - public BarDto Bar { get; set; } - } + parent1.Children.Add(child1); + child1.Parents.Add(parent1); - public class BarDto - { - public FooDto Foo { get; set; } - public string Value { get; set; } - } + _dtoParent = Mapper.Map(parent1); } - public class When_mapping_to_a_destination_containing_two_dtos_mapped_from_the_same_source : AutoMapperSpecBase + [Fact] + public void Should_map_successfully() { - private FooContainerModel _dto; + object.ReferenceEquals(_dtoParent.Children[0].Parents[0], _dtoParent).ShouldBeTrue(); + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - cfg.CreateMap(); - cfg.CreateMap() - .PreserveReferences() - .ForMember(dest => dest.Input, opt => opt.MapFrom(src => src)) - .ForMember(dest => dest.Screen, opt => opt.MapFrom(src => src)); - }); - - protected override void Because_of() - { - var model = new FooModel { Id = 3 }; - _dto = Mapper.Map(model); - } + public class Parent + { + public Guid Id { get; private set; } - [Fact] - public void Should_not_preserve_identity_when_destinations_are_incompatible() - { - _dto.ShouldBeOfType(); - _dto.Input.ShouldBeOfType(); - _dto.Screen.ShouldBeOfType(); - _dto.Input.Id.ShouldBe(3); - _dto.Screen.Id.ShouldBe("3"); - } + public string Name { get; set; } + + public List Children { get; set; } - public class FooContainerModel + public Parent() { - public FooInputModel Input { get; set; } - public FooScreenModel Screen { get; set; } + Id = Guid.NewGuid(); + Children = new List(); } - public class FooScreenModel + public bool Equals(Parent other) { - public string Id { get; set; } + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + return other.Id.Equals(Id); } - public class FooInputModel + public override bool Equals(object obj) { - public long Id { get; set; } + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != typeof (Parent)) return false; + return Equals((Parent) obj); } - public class FooModel + public override int GetHashCode() { - public long Id { get; set; } + return Id.GetHashCode(); } } - public class When_mapping_with_a_bidirectional_relationship_that_includes_arrays : AutoMapperSpecBase - + public class Child { - private ParentDto _dtoParent; + public Guid Id { get; private set; } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().PreserveReferences(); - cfg.CreateMap(); + public string Name { get; set; } - }); + public List Parents { get; set; } - protected override void Because_of() + public Child() { - var parent1 = new Parent { Name = "Parent 1" }; - var child1 = new Child { Name = "Child 1" }; - - parent1.Children.Add(child1); - child1.Parents.Add(parent1); - - _dtoParent = Mapper.Map(parent1); + Id = Guid.NewGuid(); + Parents = new List(); } - [Fact] - public void Should_map_successfully() + public bool Equals(Child other) { - object.ReferenceEquals(_dtoParent.Children[0].Parents[0], _dtoParent).ShouldBeTrue(); + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + return other.Id.Equals(Id); } - public class Parent + public override bool Equals(object obj) { - public Guid Id { get; private set; } - - public string Name { get; set; } - - public List Children { get; set; } - - public Parent() - { - Id = Guid.NewGuid(); - Children = new List(); - } - - public bool Equals(Parent other) - { - if (ReferenceEquals(null, other)) return false; - if (ReferenceEquals(this, other)) return true; - return other.Id.Equals(Id); - } - - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != typeof (Parent)) return false; - return Equals((Parent) obj); - } - - public override int GetHashCode() - { - return Id.GetHashCode(); - } + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != typeof (Child)) return false; + return Equals((Child) obj); } - public class Child + public override int GetHashCode() { - public Guid Id { get; private set; } - - public string Name { get; set; } - - public List Parents { get; set; } - - public Child() - { - Id = Guid.NewGuid(); - Parents = new List(); - } - - public bool Equals(Child other) - { - if (ReferenceEquals(null, other)) return false; - if (ReferenceEquals(this, other)) return true; - return other.Id.Equals(Id); - } - - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != typeof (Child)) return false; - return Equals((Child) obj); - } - - public override int GetHashCode() - { - return Id.GetHashCode(); - } + return Id.GetHashCode(); } + } - public class ParentDto - { - public Guid Id { get; set; } + public class ParentDto + { + public Guid Id { get; set; } - public string Name { get; set; } + public string Name { get; set; } - public List Children { get; set; } + public List Children { get; set; } - public ParentDto() - { - Children = new List(); - } + public ParentDto() + { + Children = new List(); } + } - public class ChildDto - { - public Guid Id { get; set; } + public class ChildDto + { + public Guid Id { get; set; } - public string Name { get; set; } + public string Name { get; set; } - public List Parents { get; set; } + public List Parents { get; set; } - public ChildDto() - { - Parents = new List(); - } + public ChildDto() + { + Parents = new List(); } } } \ No newline at end of file diff --git a/src/UnitTests/BidirectionalRelationshipsWithoutPR.cs b/src/UnitTests/BidirectionalRelationshipsWithoutPR.cs index 99624073fa..81296a4a2e 100644 --- a/src/UnitTests/BidirectionalRelationshipsWithoutPR.cs +++ b/src/UnitTests/BidirectionalRelationshipsWithoutPR.cs @@ -5,748 +5,747 @@ using Shouldly; using Xunit; -namespace AutoMapper.UnitTests +namespace AutoMapper.UnitTests; + +public class CyclesWithInheritance : AutoMapperSpecBase { - public class CyclesWithInheritance : AutoMapperSpecBase + class FlowChart { - class FlowChart - { - public FlowNode[] Nodes; - } - class FlowNode - { - } - class FlowStep : FlowNode - { - public FlowNode Next; - } - class FlowDecision : FlowNode - { - public FlowNode True; - public FlowNode False; - } - class FlowSwitch : FlowNode - { - public IDictionary Connections; - } - class FlowChartModel - { - public FlowNodeModel[] Nodes; - } - class FlowNodeModel - { - public Connection[] Connections; - } - class Connection - { - public FlowNodeModel Node; - } - protected override MapperConfiguration CreateConfiguration() => new(cfg=> - { - cfg.CreateMap(); - cfg.CreateMap() - .Include() - .Include() - .Include(typeof(FlowSwitch<>), typeof(FlowNodeModel)) - .ForMember(d=>d.Connections, o=>o.Ignore()); - cfg.CreateMap().ForMember(d => d.Connections, o => o.MapFrom(s => new[] { s.Next })); - cfg.CreateMap().ForMember(d => d.Connections, o => o.MapFrom(s => new[] { s.True, s.False })); - cfg.CreateMap(typeof(FlowSwitch<>), typeof(FlowNodeModel)); - cfg.CreateMap().ForMember(d => d.Node, o => o.MapFrom(s => s)); - cfg.CreateMap(typeof(KeyValuePair<,>), typeof(Connection)).ForMember("Node", o => o.MapFrom("Key")); - }); - [Fact] - public void Should_map_ok() - { - var flowStep = new FlowStep(); - var flowDecision = new FlowDecision { False = flowStep, True = flowStep }; - flowStep.Next = flowDecision; - var source = new FlowChart { Nodes = new FlowNode[] { flowStep, flowDecision } }; - var dest = Map(source); - } + public FlowNode[] Nodes; } - public class When_the_source_has_cyclical_references_with_dynamic_map : AutoMapperSpecBase + class FlowNode { - public class CDataTypeModel - { - public string Name { get; set; } - public List> FieldDefinitionList { get; set; } - } - public class CDataTypeDTO - { - public string Name { get; set; } - public List> FieldDefinitionList { get; set; } - } - public class CFieldDefinitionModel - { - public string Name { get; set; } - public CDataTypeModel DataType { get; set; } - public CComponentDefinitionModel ComponentDefinition { get; set; } - } - public class CFieldDefinitionDTO - { - public string Name { get; set; } - public CDataTypeDTO DataType { get; set; } - public CComponentDefinitionDTO ComponentDefinition { get; set; } - } - public class CComponentDefinitionModel - { - public string Name { get; set; } - public List> FieldDefinitionList { get; set; } - } - public class CComponentDefinitionDTO - { - public string Name { get; set; } - public List> FieldDefinitionList { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(typeof(CDataTypeModel<>), typeof(CDataTypeDTO<>)).ReverseMap(); - cfg.CreateMap(typeof(CFieldDefinitionModel<>), typeof(CFieldDefinitionDTO<>)).ReverseMap(); - cfg.CreateMap(typeof(CComponentDefinitionModel<>), typeof(CComponentDefinitionDTO<>)).ReverseMap(); - }); - - [Fact] - public void Should_map_ok() - { - var component = new CComponentDefinitionDTO(); - var type = new CDataTypeDTO(); - var field = new CFieldDefinitionDTO { ComponentDefinition = component, DataType = type }; - type.FieldDefinitionList = component.FieldDefinitionList = new List> { field }; - var fieldModel = Mapper.Map>(field); - fieldModel.ShouldBeSameAs(fieldModel.ComponentDefinition.FieldDefinitionList[0]); - fieldModel.ShouldBeSameAs(fieldModel.DataType.FieldDefinitionList[0]); - } } + class FlowStep : FlowNode + { + public FlowNode Next; + } + class FlowDecision : FlowNode + { + public FlowNode True; + public FlowNode False; + } + class FlowSwitch : FlowNode + { + public IDictionary Connections; + } + class FlowChartModel + { + public FlowNodeModel[] Nodes; + } + class FlowNodeModel + { + public Connection[] Connections; + } + class Connection + { + public FlowNodeModel Node; + } + protected override MapperConfiguration CreateConfiguration() => new(cfg=> + { + cfg.CreateMap(); + cfg.CreateMap() + .Include() + .Include() + .Include(typeof(FlowSwitch<>), typeof(FlowNodeModel)) + .ForMember(d=>d.Connections, o=>o.Ignore()); + cfg.CreateMap().ForMember(d => d.Connections, o => o.MapFrom(s => new[] { s.Next })); + cfg.CreateMap().ForMember(d => d.Connections, o => o.MapFrom(s => new[] { s.True, s.False })); + cfg.CreateMap(typeof(FlowSwitch<>), typeof(FlowNodeModel)); + cfg.CreateMap().ForMember(d => d.Node, o => o.MapFrom(s => s)); + cfg.CreateMap(typeof(KeyValuePair<,>), typeof(Connection)).ForMember("Node", o => o.MapFrom("Key")); + }); + [Fact] + public void Should_map_ok() + { + var flowStep = new FlowStep(); + var flowDecision = new FlowDecision { False = flowStep, True = flowStep }; + flowStep.Next = flowDecision; + var source = new FlowChart { Nodes = new FlowNode[] { flowStep, flowDecision } }; + var dest = Map(source); + } +} +public class When_the_source_has_cyclical_references_with_dynamic_map : AutoMapperSpecBase +{ + public class CDataTypeModel + { + public string Name { get; set; } + public List> FieldDefinitionList { get; set; } + } + public class CDataTypeDTO + { + public string Name { get; set; } + public List> FieldDefinitionList { get; set; } + } + public class CFieldDefinitionModel + { + public string Name { get; set; } + public CDataTypeModel DataType { get; set; } + public CComponentDefinitionModel ComponentDefinition { get; set; } + } + public class CFieldDefinitionDTO + { + public string Name { get; set; } + public CDataTypeDTO DataType { get; set; } + public CComponentDefinitionDTO ComponentDefinition { get; set; } + } + public class CComponentDefinitionModel + { + public string Name { get; set; } + public List> FieldDefinitionList { get; set; } + } + public class CComponentDefinitionDTO + { + public string Name { get; set; } + public List> FieldDefinitionList { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(typeof(CDataTypeModel<>), typeof(CDataTypeDTO<>)).ReverseMap(); + cfg.CreateMap(typeof(CFieldDefinitionModel<>), typeof(CFieldDefinitionDTO<>)).ReverseMap(); + cfg.CreateMap(typeof(CComponentDefinitionModel<>), typeof(CComponentDefinitionDTO<>)).ReverseMap(); + }); - public class When_the_same_map_is_used_again : AutoMapperSpecBase + [Fact] + public void Should_map_ok() { - class Source - { - public InnerSource Inner; - public OtherInnerSource OtherInner; - public Item Value1; - public Item Value2; - } + var component = new CComponentDefinitionDTO(); + var type = new CDataTypeDTO(); + var field = new CFieldDefinitionDTO { ComponentDefinition = component, DataType = type }; + type.FieldDefinitionList = component.FieldDefinitionList = new List> { field }; + var fieldModel = Mapper.Map>(field); + fieldModel.ShouldBeSameAs(fieldModel.ComponentDefinition.FieldDefinitionList[0]); + fieldModel.ShouldBeSameAs(fieldModel.DataType.FieldDefinitionList[0]); + } +} - class InnerSource - { - public Item Value; - } +public class When_the_same_map_is_used_again : AutoMapperSpecBase +{ + class Source + { + public InnerSource Inner; + public OtherInnerSource OtherInner; + public Item Value1; + public Item Value2; + } - class OtherInnerSource - { - public Item Value; - } + class InnerSource + { + public Item Value; + } - class InnerDestination - { - public Item Value; - } + class OtherInnerSource + { + public Item Value; + } - class OtherInnerDestination - { - public Item Value; - } + class InnerDestination + { + public Item Value; + } - class Destination - { - public InnerDestination Inner; - public OtherInnerDestination OtherInner; - public Item Value1; - public Item Value2; - } + class OtherInnerDestination + { + public Item Value; + } - class Item - { - public int Value; - } + class Destination + { + public InnerDestination Inner; + public OtherInnerDestination OtherInner; + public Item Value1; + public Item Value2; + } - protected override MapperConfiguration CreateConfiguration() => new(cfg=> - { - cfg.CreateMap(); - cfg.CreateMap(); - cfg.CreateMap(); - cfg.CreateMap(); - }); + class Item + { + public int Value; + } - [Fact] - public void Should_not_set_preserve_references() - { - Configuration.ResolveTypeMap(typeof(Item), typeof(Item)).PreserveReferences.ShouldBeFalse(); - } + protected override MapperConfiguration CreateConfiguration() => new(cfg=> + { + cfg.CreateMap(); + cfg.CreateMap(); + cfg.CreateMap(); + cfg.CreateMap(); + }); + + [Fact] + public void Should_not_set_preserve_references() + { + Configuration.ResolveTypeMap(typeof(Item), typeof(Item)).PreserveReferences.ShouldBeFalse(); } +} - public class When_the_source_has_cyclical_references : AutoMapperSpecBase +public class When_the_source_has_cyclical_references : AutoMapperSpecBase +{ + public class Article { - public class Article - { - public int Id { get; set; } + public int Id { get; set; } - public virtual Supplier Supplier { get; set; } - } + public virtual Supplier Supplier { get; set; } + } - public class Supplier - { - public int Id { get; set; } + public class Supplier + { + public int Id { get; set; } - public virtual ICollection Contacts { get; set; } - } + public virtual ICollection Contacts { get; set; } + } - public class Contact - { - public int Id { get; set; } + public class Contact + { + public int Id { get; set; } - public virtual ICollection Suppliers { get; set; } - } + public virtual ICollection Suppliers { get; set; } + } - public class ArticleViewModel - { - public int Id { get; set; } + public class ArticleViewModel + { + public int Id { get; set; } - public SupplierViewModel Supplier { get; set; } - } + public SupplierViewModel Supplier { get; set; } + } - public class SupplierViewModel - { - public int Id { get; set; } + public class SupplierViewModel + { + public int Id { get; set; } - public List Contacts { get; set; } + public List Contacts { get; set; } - } + } - public class ContactViewModel - { - public int Id { get; set; } + public class ContactViewModel + { + public int Id { get; set; } - public List Suppliers { get; set; } - } + public List Suppliers { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - cfg.CreateMap(); - cfg.CreateMap(); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + cfg.CreateMap(); + cfg.CreateMap(); + }); - [Fact] - public void Should_map_ok() - { - var article = new Article { Supplier = new Supplier() }; - article.Supplier.Contacts = new List { new Contact { Suppliers = new List { article.Supplier } } }; - var supplier = Mapper.Map(article).Supplier; - supplier.ShouldBe(supplier.Contacts[0].Suppliers[0]); - } + [Fact] + public void Should_map_ok() + { + var article = new Article { Supplier = new Supplier() }; + article.Supplier.Contacts = new List { new Contact { Suppliers = new List { article.Supplier } } }; + var supplier = Mapper.Map(article).Supplier; + supplier.ShouldBe(supplier.Contacts[0].Suppliers[0]); } +} - public class When_the_source_has_cyclical_references_with_ForPath : AutoMapperSpecBase +public class When_the_source_has_cyclical_references_with_ForPath : AutoMapperSpecBase +{ + public class Article { - public class Article - { - public int Id { get; set; } + public int Id { get; set; } - public virtual Supplier Supplier { get; set; } - } + public virtual Supplier Supplier { get; set; } + } - public class Supplier - { - public int Id { get; set; } + public class Supplier + { + public int Id { get; set; } - public virtual ICollection Contacts { get; set; } - } + public virtual ICollection Contacts { get; set; } + } - public class Contact - { - public int Id { get; set; } + public class Contact + { + public int Id { get; set; } - public virtual ICollection Suppliers { get; set; } - } + public virtual ICollection Suppliers { get; set; } + } - public class ArticleViewModel - { - public int Id { get; set; } + public class ArticleViewModel + { + public int Id { get; set; } - public SupplierViewModel Supplier { get; set; } - } + public SupplierViewModel Supplier { get; set; } + } - public class SupplierViewModel - { - public int Id { get; set; } + public class SupplierViewModel + { + public int Id { get; set; } - public List Contacts { get; set; } + public List Contacts { get; set; } - } + } - public class ContactViewModel - { - public int Id { get; set; } + public class ContactViewModel + { + public int Id { get; set; } - public List Suppliers1 { get; set; } - } + public List Suppliers1 { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - cfg.CreateMap(); - cfg.CreateMap().ForPath(d=>d.Suppliers1, o=>o.MapFrom(s=>s.Suppliers)); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + cfg.CreateMap(); + cfg.CreateMap().ForPath(d=>d.Suppliers1, o=>o.MapFrom(s=>s.Suppliers)); + }); - [Fact] - public void Should_map_ok() - { - var article = new Article { Supplier = new Supplier() }; - article.Supplier.Contacts = new List { new Contact { Suppliers = new List { article.Supplier } } }; - var supplier = Mapper.Map(article).Supplier; - supplier.ShouldBe(supplier.Contacts[0].Suppliers1[0]); - } + [Fact] + public void Should_map_ok() + { + var article = new Article { Supplier = new Supplier() }; + article.Supplier.Contacts = new List { new Contact { Suppliers = new List { article.Supplier } } }; + var supplier = Mapper.Map(article).Supplier; + supplier.ShouldBe(supplier.Contacts[0].Suppliers1[0]); } +} - public class When_the_source_has_cyclical_references_with_ignored_ForPath : AutoMapperSpecBase +public class When_the_source_has_cyclical_references_with_ignored_ForPath : AutoMapperSpecBase +{ + public class Supplier { - public class Supplier - { - public int Id { get; set; } + public int Id { get; set; } - public virtual Contact Contact { get; set; } - } + public virtual Contact Contact { get; set; } + } - public class Contact - { - public int Id { get; set; } + public class Contact + { + public int Id { get; set; } - public Supplier Supplier { get; set; } - } + public Supplier Supplier { get; set; } + } - public class SupplierViewModel - { - public int Id { get; set; } + public class SupplierViewModel + { + public int Id { get; set; } - public ContactViewModel Contact { get; set; } + public ContactViewModel Contact { get; set; } - } + } - public class ContactViewModel - { - public int Id { get; set; } + public class ContactViewModel + { + public int Id { get; set; } - public SupplierViewModel Supplier1 { get; set; } - } + public SupplierViewModel Supplier1 { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().ForPath(d=>d.Contact.Supplier1, o=> { - cfg.CreateMap().ForPath(d=>d.Contact.Supplier1, o=> - { - o.MapFrom(s => s.Contact.Supplier); - o.Ignore(); - }); + o.MapFrom(s => s.Contact.Supplier); + o.Ignore(); }); + }); - [Fact] - public void Should_map_ok() - { - var supplier = new Supplier(); - supplier.Contact = new Contact { Supplier = supplier }; - Mapper.Map(supplier); - Configuration.GetAllTypeMaps().All(tm => tm.PreserveReferences).ShouldBeFalse(); - } + [Fact] + public void Should_map_ok() + { + var supplier = new Supplier(); + supplier.Contact = new Contact { Supplier = supplier }; + Mapper.Map(supplier); + Configuration.GetAllTypeMaps().All(tm => tm.PreserveReferences).ShouldBeFalse(); } +} - public class When_mapping_to_a_destination_with_a_bidirectional_parent_one_to_many_child_relationship : AutoMapperSpecBase +public class When_mapping_to_a_destination_with_a_bidirectional_parent_one_to_many_child_relationship : AutoMapperSpecBase +{ + private ParentDto _dto; + + protected override MapperConfiguration CreateConfiguration() => new(cfg => { - private ParentDto _dto; + cfg.CreateMap(); + cfg.CreateMap(); + }); - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - cfg.CreateMap(); - }); + protected override void Because_of() + { + var parent = new ParentModel { ID = "PARENT_ONE" }; - protected override void Because_of() - { - var parent = new ParentModel { ID = "PARENT_ONE" }; + parent.AddChild(new ChildModel { ID = "CHILD_ONE" }); - parent.AddChild(new ChildModel { ID = "CHILD_ONE" }); + parent.AddChild(new ChildModel { ID = "CHILD_TWO" }); - parent.AddChild(new ChildModel { ID = "CHILD_TWO" }); + _dto = Mapper.Map(parent); + } - _dto = Mapper.Map(parent); - } + [Fact] + public void Should_preserve_the_parent_child_relationship_on_the_destination() + { + _dto.Children[0].Parent.ShouldBeSameAs(_dto); + _dto.Children[1].Parent.ShouldBeSameAs(_dto); + } - [Fact] - public void Should_preserve_the_parent_child_relationship_on_the_destination() + public class ParentModel + { + public ParentModel() { - _dto.Children[0].Parent.ShouldBeSameAs(_dto); - _dto.Children[1].Parent.ShouldBeSameAs(_dto); + Children = new List(); } - public class ParentModel + public string ID { get; set; } + + public IList Children { get; private set; } + + public void AddChild(ChildModel child) { - public ParentModel() - { - Children = new List(); - } + child.Parent = this; + Children.Add(child); + } + } + + public class ChildModel + { + public string ID { get; set; } + public ParentModel Parent { get; set; } + } + + public class ParentDto + { + public string ID { get; set; } + public IList Children { get; set; } + } - public string ID { get; set; } + public class ChildDto + { + public string ID { get; set; } + public ParentDto Parent { get; set; } + } +} + + +//public class When_mapping_to_a_destination_with_a_bidirectional_parent_one_to_many_child_relationship_using_CustomMapper_StackOverflow : AutoMapperSpecBase +//{ +// private ParentDto _dto; +// private ParentModel _parent; + +// protected override void Establish_context() +// { +// _parent = new ParentModel +// { +// ID = 2 +// }; + +// List childModels = new List +// { +// new ChildModel +// { +// ID = 1, +// Parent = _parent +// } +// }; + +// Dictionary parents = childModels.ToDictionary(x => x.ID, x => x.Parent); + +// Mapper.CreateMap().ConvertUsing(new ChildIdToParentDtoConverter(parents)); +// Mapper.CreateMap>().ConvertUsing(new ParentIdToChildDtoListConverter(childModels)); + +// Mapper.CreateMap() +// .ForMember(dest => dest.Children, opt => opt.MapFrom(src => src.ID)); +// Mapper.CreateMap(); + +// config.AssertConfigurationIsValid(); +// } + +// protected override void Because_of() +// { +// _dto = Mapper.Map(_parent); +// } + +// [Fact(Skip = "This test breaks the Test Runner")] +// public void Should_preserve_the_parent_child_relationship_on_the_destination() +// { +// _dto.Children[0].Parent.ID.ShouldBe(_dto.ID); +// } + +// public class ChildIdToParentDtoConverter : ITypeConverter +// { +// private readonly Dictionary _parentModels; + +// public ChildIdToParentDtoConverter(Dictionary parentModels) +// { +// _parentModels = parentModels; +// } + +// public ParentDto Convert(int childId) +// { +// ParentModel parentModel = _parentModels[childId]; +// MappingEngine mappingEngine = (MappingEngine)Mapper.Engine; +// return mappingEngine.Map(parentModel); +// } +// } + +// public class ParentIdToChildDtoListConverter : ITypeConverter> +// { +// private readonly IList _childModels; + +// public ParentIdToChildDtoListConverter(IList childModels) +// { +// _childModels = childModels; +// } + +// protected override List ConvertCore(int childId) +// { +// List childModels = _childModels.Where(x => x.Parent.ID == childId).ToList(); +// MappingEngine mappingEngine = (MappingEngine)Mapper.Engine; +// return mappingEngine.Map, List>(childModels); +// } +// } + +// public class ParentModel +// { +// public int ID { get; set; } +// } + +// public class ChildModel +// { +// public int ID { get; set; } +// public ParentModel Parent { get; set; } +// } + +// public class ParentDto +// { +// public int ID { get; set; } +// public List Children { get; set; } +// } + +// public class ChildDto +// { +// public int ID { get; set; } +// public ParentDto Parent { get; set; } +// } +//} + +public class When_mapping_to_a_destination_with_a_bidirectional_parent_one_to_one_child_relationship : AutoMapperSpecBase +{ + private FooDto _dto; - public IList Children { get; private set; } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + cfg.CreateMap(); + }); - public void AddChild(ChildModel child) + protected override void Because_of() + { + var foo = new Foo { - child.Parent = this; - Children.Add(child); - } - } + Bar = new Bar + { + Value = "something" + } + }; + foo.Bar.Foo = foo; + _dto = Mapper.Map(foo); + } - public class ChildModel - { - public string ID { get; set; } - public ParentModel Parent { get; set; } - } + [Fact] + public void Should_preserve_the_parent_child_relationship_on_the_destination() + { + _dto.Bar.Foo.ShouldBeSameAs(_dto); + } - public class ParentDto - { - public string ID { get; set; } - public IList Children { get; set; } - } + public class Foo + { + public Bar Bar { get; set; } + } - public class ChildDto - { - public string ID { get; set; } - public ParentDto Parent { get; set; } - } + public class Bar + { + public Foo Foo { get; set; } + public string Value { get; set; } } + public class FooDto + { + public BarDto Bar { get; set; } + } - //public class When_mapping_to_a_destination_with_a_bidirectional_parent_one_to_many_child_relationship_using_CustomMapper_StackOverflow : AutoMapperSpecBase - //{ - // private ParentDto _dto; - // private ParentModel _parent; - - // protected override void Establish_context() - // { - // _parent = new ParentModel - // { - // ID = 2 - // }; - - // List childModels = new List - // { - // new ChildModel - // { - // ID = 1, - // Parent = _parent - // } - // }; - - // Dictionary parents = childModels.ToDictionary(x => x.ID, x => x.Parent); - - // Mapper.CreateMap().ConvertUsing(new ChildIdToParentDtoConverter(parents)); - // Mapper.CreateMap>().ConvertUsing(new ParentIdToChildDtoListConverter(childModels)); - - // Mapper.CreateMap() - // .ForMember(dest => dest.Children, opt => opt.MapFrom(src => src.ID)); - // Mapper.CreateMap(); - - // config.AssertConfigurationIsValid(); - // } - - // protected override void Because_of() - // { - // _dto = Mapper.Map(_parent); - // } - - // [Fact(Skip = "This test breaks the Test Runner")] - // public void Should_preserve_the_parent_child_relationship_on_the_destination() - // { - // _dto.Children[0].Parent.ID.ShouldBe(_dto.ID); - // } - - // public class ChildIdToParentDtoConverter : ITypeConverter - // { - // private readonly Dictionary _parentModels; - - // public ChildIdToParentDtoConverter(Dictionary parentModels) - // { - // _parentModels = parentModels; - // } - - // public ParentDto Convert(int childId) - // { - // ParentModel parentModel = _parentModels[childId]; - // MappingEngine mappingEngine = (MappingEngine)Mapper.Engine; - // return mappingEngine.Map(parentModel); - // } - // } - - // public class ParentIdToChildDtoListConverter : ITypeConverter> - // { - // private readonly IList _childModels; - - // public ParentIdToChildDtoListConverter(IList childModels) - // { - // _childModels = childModels; - // } - - // protected override List ConvertCore(int childId) - // { - // List childModels = _childModels.Where(x => x.Parent.ID == childId).ToList(); - // MappingEngine mappingEngine = (MappingEngine)Mapper.Engine; - // return mappingEngine.Map, List>(childModels); - // } - // } - - // public class ParentModel - // { - // public int ID { get; set; } - // } - - // public class ChildModel - // { - // public int ID { get; set; } - // public ParentModel Parent { get; set; } - // } - - // public class ParentDto - // { - // public int ID { get; set; } - // public List Children { get; set; } - // } - - // public class ChildDto - // { - // public int ID { get; set; } - // public ParentDto Parent { get; set; } - // } - //} - - public class When_mapping_to_a_destination_with_a_bidirectional_parent_one_to_one_child_relationship : AutoMapperSpecBase - { - private FooDto _dto; - - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - cfg.CreateMap(); - }); + public class BarDto + { + public FooDto Foo { get; set; } + public string Value { get; set; } + } +} - protected override void Because_of() - { - var foo = new Foo - { - Bar = new Bar - { - Value = "something" - } - }; - foo.Bar.Foo = foo; - _dto = Mapper.Map(foo); - } +public class When_mapping_to_a_destination_containing_two_dtos_mapped_from_the_same_source : AutoMapperSpecBase +{ + private FooContainerModel _dto; - [Fact] - public void Should_preserve_the_parent_child_relationship_on_the_destination() - { - _dto.Bar.Foo.ShouldBeSameAs(_dto); - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + cfg.CreateMap(); + cfg.CreateMap() + .ForMember(dest => dest.Input, opt => opt.MapFrom(src => src)) + .ForMember(dest => dest.Screen, opt => opt.MapFrom(src => src)); + }); + + protected override void Because_of() + { + var model = new FooModel { Id = 3 }; + _dto = Mapper.Map(model); + } - public class Foo - { - public Bar Bar { get; set; } - } + [Fact] + public void Should_not_preserve_identity_when_destinations_are_incompatible() + { + _dto.ShouldBeOfType(); + _dto.Input.ShouldBeOfType(); + _dto.Screen.ShouldBeOfType(); + _dto.Input.Id.ShouldBe(3); + _dto.Screen.Id.ShouldBe("3"); + } - public class Bar - { - public Foo Foo { get; set; } - public string Value { get; set; } - } + public class FooContainerModel + { + public FooInputModel Input { get; set; } + public FooScreenModel Screen { get; set; } + } - public class FooDto - { - public BarDto Bar { get; set; } - } + public class FooScreenModel + { + public string Id { get; set; } + } - public class BarDto - { - public FooDto Foo { get; set; } - public string Value { get; set; } - } + public class FooInputModel + { + public long Id { get; set; } } - public class When_mapping_to_a_destination_containing_two_dtos_mapped_from_the_same_source : AutoMapperSpecBase + public class FooModel { - private FooContainerModel _dto; + public long Id { get; set; } + } +} - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - cfg.CreateMap(); - cfg.CreateMap() - .ForMember(dest => dest.Input, opt => opt.MapFrom(src => src)) - .ForMember(dest => dest.Screen, opt => opt.MapFrom(src => src)); - }); +public class When_mapping_with_a_bidirectional_relationship_that_includes_arrays : AutoMapperSpecBase - protected override void Because_of() - { - var model = new FooModel { Id = 3 }; - _dto = Mapper.Map(model); - } +{ + private ParentDto _dtoParent; - [Fact] - public void Should_not_preserve_identity_when_destinations_are_incompatible() - { - _dto.ShouldBeOfType(); - _dto.Input.ShouldBeOfType(); - _dto.Screen.ShouldBeOfType(); - _dto.Input.Id.ShouldBe(3); - _dto.Screen.Id.ShouldBe("3"); - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + cfg.CreateMap(); - public class FooContainerModel - { - public FooInputModel Input { get; set; } - public FooScreenModel Screen { get; set; } - } + }); - public class FooScreenModel - { - public string Id { get; set; } - } + protected override void Because_of() + { + var parent1 = new Parent { Name = "Parent 1" }; + var child1 = new Child { Name = "Child 1" }; - public class FooInputModel - { - public long Id { get; set; } - } + parent1.Children.Add(child1); + child1.Parents.Add(parent1); - public class FooModel - { - public long Id { get; set; } - } + _dtoParent = Mapper.Map(parent1); } - public class When_mapping_with_a_bidirectional_relationship_that_includes_arrays : AutoMapperSpecBase + [Fact] + public void Should_map_successfully() + { + object.ReferenceEquals(_dtoParent.Children[0].Parents[0], _dtoParent).ShouldBeTrue(); + } + public class Parent { - private ParentDto _dtoParent; + public Guid Id { get; private set; } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - cfg.CreateMap(); + public string Name { get; set; } - }); + public List Children { get; set; } - protected override void Because_of() + public Parent() { - var parent1 = new Parent { Name = "Parent 1" }; - var child1 = new Child { Name = "Child 1" }; - - parent1.Children.Add(child1); - child1.Parents.Add(parent1); - - _dtoParent = Mapper.Map(parent1); + Id = Guid.NewGuid(); + Children = new List(); } - [Fact] - public void Should_map_successfully() + public bool Equals(Parent other) { - object.ReferenceEquals(_dtoParent.Children[0].Parents[0], _dtoParent).ShouldBeTrue(); + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + return other.Id.Equals(Id); } - public class Parent + public override bool Equals(object obj) { - public Guid Id { get; private set; } - - public string Name { get; set; } - - public List Children { get; set; } - - public Parent() - { - Id = Guid.NewGuid(); - Children = new List(); - } - - public bool Equals(Parent other) - { - if (ReferenceEquals(null, other)) return false; - if (ReferenceEquals(this, other)) return true; - return other.Id.Equals(Id); - } - - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != typeof (Parent)) return false; - return Equals((Parent) obj); - } - - public override int GetHashCode() - { - return Id.GetHashCode(); - } + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != typeof (Parent)) return false; + return Equals((Parent) obj); } - public class Child + public override int GetHashCode() { - public Guid Id { get; private set; } + return Id.GetHashCode(); + } + } - public string Name { get; set; } + public class Child + { + public Guid Id { get; private set; } - public List Parents { get; set; } + public string Name { get; set; } - public Child() - { - Id = Guid.NewGuid(); - Parents = new List(); - } + public List Parents { get; set; } - public bool Equals(Child other) - { - if (ReferenceEquals(null, other)) return false; - if (ReferenceEquals(this, other)) return true; - return other.Id.Equals(Id); - } + public Child() + { + Id = Guid.NewGuid(); + Parents = new List(); + } - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != typeof (Child)) return false; - return Equals((Child) obj); - } + public bool Equals(Child other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + return other.Id.Equals(Id); + } - public override int GetHashCode() - { - return Id.GetHashCode(); - } + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != typeof (Child)) return false; + return Equals((Child) obj); } - public class ParentDto + public override int GetHashCode() { - public Guid Id { get; set; } + return Id.GetHashCode(); + } + } - public string Name { get; set; } + public class ParentDto + { + public Guid Id { get; set; } - public List Children { get; set; } + public string Name { get; set; } - public ParentDto() - { - Children = new List(); - } - } + public List Children { get; set; } - public class ChildDto + public ParentDto() { - public Guid Id { get; set; } + Children = new List(); + } + } - public string Name { get; set; } + public class ChildDto + { + public Guid Id { get; set; } - public List Parents { get; set; } + public string Name { get; set; } - public ChildDto() - { - Parents = new List(); - } + public List Parents { get; set; } + + public ChildDto() + { + Parents = new List(); } } } \ No newline at end of file diff --git a/src/UnitTests/Bug/AfterMapNestedObjects.cs b/src/UnitTests/Bug/AfterMapNestedObjects.cs index 63e2fc86f1..15855bab19 100644 --- a/src/UnitTests/Bug/AfterMapNestedObjects.cs +++ b/src/UnitTests/Bug/AfterMapNestedObjects.cs @@ -1,48 +1,47 @@ using Shouldly; using Xunit; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class AfterMapNestedObjects : AutoMapperSpecBase { - public class AfterMapNestedObjects : AutoMapperSpecBase + bool _afterMapCalled; + + public class Inner + { + public string Prop1 { get; set; } + } + + public class Outer + { + public Inner Inner { get; set; } + } + + public class InnerDTO + { + public string Prop1 { get; set; } + } + + public class OuterDTO + { + public InnerDTO Inner { get; set; } + } + + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + cfg.CreateMap(); + }); + + protected override void Because_of() + { + var outer = new Outer { Inner = new Inner() { Prop1 = "Prop1" } }; + Mapper.Map(outer, o => o.AfterMap((s, d) => _afterMapCalled = true)); + } + + [Fact] + public void Should_call_aftermap_for_outer_objects() { - bool _afterMapCalled; - - public class Inner - { - public string Prop1 { get; set; } - } - - public class Outer - { - public Inner Inner { get; set; } - } - - public class InnerDTO - { - public string Prop1 { get; set; } - } - - public class OuterDTO - { - public InnerDTO Inner { get; set; } - } - - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - cfg.CreateMap(); - }); - - protected override void Because_of() - { - var outer = new Outer { Inner = new Inner() { Prop1 = "Prop1" } }; - Mapper.Map(outer, o => o.AfterMap((s, d) => _afterMapCalled = true)); - } - - [Fact] - public void Should_call_aftermap_for_outer_objects() - { - _afterMapCalled.ShouldBeTrue(); - } + _afterMapCalled.ShouldBeTrue(); } } \ No newline at end of file diff --git a/src/UnitTests/Bug/AllowNullCollectionsAssignableArray.cs b/src/UnitTests/Bug/AllowNullCollectionsAssignableArray.cs index 239dd178cd..48ea1cb8ca 100644 --- a/src/UnitTests/Bug/AllowNullCollectionsAssignableArray.cs +++ b/src/UnitTests/Bug/AllowNullCollectionsAssignableArray.cs @@ -3,40 +3,39 @@ using System; using System.Collections.Generic; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class AllowNullCollectionsAssignableArray : AutoMapperSpecBase { - public class AllowNullCollectionsAssignableArray : AutoMapperSpecBase - { - private Destination _destination; + private Destination _destination; - class Source - { - public string[] ArrayOfItems { get; set; } - } - class Destination - { - public string[] ArrayOfItems { get; set; } - } + class Source + { + public string[] ArrayOfItems { get; set; } + } + class Destination + { + public string[] ArrayOfItems { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.AllowNullCollections = false; - cfg.CreateMap(); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.AllowNullCollections = false; + cfg.CreateMap(); + }); - protected override void Because_of() + protected override void Because_of() + { + _destination = new Destination { - _destination = new Destination - { - ArrayOfItems = new string[] { "Red Fish", "Blue Fish" }, - }; - Mapper.Map(new Source(), _destination); - } + ArrayOfItems = new string[] { "Red Fish", "Blue Fish" }, + }; + Mapper.Map(new Source(), _destination); + } - [Fact] - public void Should_overwrite_destination_array() - { - _destination.ArrayOfItems.ShouldBeEmpty(); - } + [Fact] + public void Should_overwrite_destination_array() + { + _destination.ArrayOfItems.ShouldBeEmpty(); } } \ No newline at end of file diff --git a/src/UnitTests/Bug/AllowNullDestinationValuesBugs.cs b/src/UnitTests/Bug/AllowNullDestinationValuesBugs.cs index f7ab65a9db..fa62aba12d 100644 --- a/src/UnitTests/Bug/AllowNullDestinationValuesBugs.cs +++ b/src/UnitTests/Bug/AllowNullDestinationValuesBugs.cs @@ -1,63 +1,62 @@ using Xunit; using Shouldly; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class When_mapping_to_an_assignable_object_with_nullable_off : AutoMapperSpecBase { - public class When_mapping_to_an_assignable_object_with_nullable_off : AutoMapperSpecBase - { - private Destination _destination; - - public class Source - { - public Inner Property { get; set; } - } - - public class Destination - { - public Inner SomeOtherProperty { get; set; } - } - - public class Inner - { - public string Name { get; set; } - } - - protected override MapperConfiguration CreateConfiguration() => new(config => - { - config.AllowNullDestinationValues = false; - config.CreateMap(); - config.CreateMap() - .ForMember(dest => dest.SomeOtherProperty, opt => opt.MapFrom(src => src.Property)); - }); - - protected override void Because_of() - { - Source source = new Source(); - - _destination = Mapper.Map(source); - } - - [Fact] - public void Should_create_the_assingable_member() - { - _destination.ShouldNotBeNull(); - _destination.SomeOtherProperty.ShouldNotBeNull(); - } + private Destination _destination; + + public class Source + { + public Inner Property { get; set; } + } + + public class Destination + { + public Inner SomeOtherProperty { get; set; } } - public class When_AllowNullDestinationValues_is_false : AutoMapperSpecBase - { - public class Source - { - } - public class Destination - { - } - protected override MapperConfiguration CreateConfiguration() => new(config => - { - config.AllowNullDestinationValues = false; - config.CreateMap(); - }); - [Fact] - public void Null_should_map_to_non_null() => Mapper.Map(null).ShouldNotBeNull(); + + public class Inner + { + public string Name { get; set; } } + + protected override MapperConfiguration CreateConfiguration() => new(config => + { + config.AllowNullDestinationValues = false; + config.CreateMap(); + config.CreateMap() + .ForMember(dest => dest.SomeOtherProperty, opt => opt.MapFrom(src => src.Property)); + }); + + protected override void Because_of() + { + Source source = new Source(); + + _destination = Mapper.Map(source); + } + + [Fact] + public void Should_create_the_assingable_member() + { + _destination.ShouldNotBeNull(); + _destination.SomeOtherProperty.ShouldNotBeNull(); + } +} +public class When_AllowNullDestinationValues_is_false : AutoMapperSpecBase +{ + public class Source + { + } + public class Destination + { + } + protected override MapperConfiguration CreateConfiguration() => new(config => + { + config.AllowNullDestinationValues = false; + config.CreateMap(); + }); + [Fact] + public void Null_should_map_to_non_null() => Mapper.Map(null).ShouldNotBeNull(); } \ No newline at end of file diff --git a/src/UnitTests/Bug/AssertConfigurationIsValidNullables.cs b/src/UnitTests/Bug/AssertConfigurationIsValidNullables.cs index 514a731588..7485d7a7d4 100644 --- a/src/UnitTests/Bug/AssertConfigurationIsValidNullables.cs +++ b/src/UnitTests/Bug/AssertConfigurationIsValidNullables.cs @@ -2,24 +2,23 @@ using Shouldly; using System; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class AssertConfigurationIsValidNullables : AutoMapperSpecBase { - public class AssertConfigurationIsValidNullables : AutoMapperSpecBase + class Source { - class Source - { - public int? Number { get; set; } - } - class Destination - { - public decimal? Number { get; set; } - } - - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - }); - [Fact] - public void Validate() => AssertConfigurationIsValid(); + public int? Number { get; set; } + } + class Destination + { + public decimal? Number { get; set; } } + + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + }); + [Fact] + public void Validate() => AssertConfigurationIsValid(); } \ No newline at end of file diff --git a/src/UnitTests/Bug/AutoMapperInheritanceProblemDemo.cs b/src/UnitTests/Bug/AutoMapperInheritanceProblemDemo.cs index a49ff888bc..3fe38ccddb 100644 --- a/src/UnitTests/Bug/AutoMapperInheritanceProblemDemo.cs +++ b/src/UnitTests/Bug/AutoMapperInheritanceProblemDemo.cs @@ -1,107 +1,106 @@ using Xunit; using Shouldly; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class SettersInBaseClasses : AutoMapperSpecBase { - public class SettersInBaseClasses : AutoMapperSpecBase + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + cfg.CreateMap(); + cfg.CreateMap(); + cfg.CreateMap(); + cfg.CreateMap(); + cfg.CreateMap(); + }); + + [Fact] + public void PublicSetterInParentWorks() { - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - cfg.CreateMap(); - cfg.CreateMap(); - cfg.CreateMap(); - cfg.CreateMap(); - cfg.CreateMap(); - }); - - [Fact] - public void PublicSetterInParentWorks() - { - var source = new Source {ParentProperty = "ParentProperty", ChildProperty = 1}; - var target = Mapper.Map(source); - target.ParentProperty.ShouldBe(source.ParentProperty); - target.ChildProperty.ShouldBe(source.ChildProperty); - } - - - [Fact] - public void PublicSetterInGrandparentWorks() - { - var source = new Source {ParentProperty = "ParentProperty", ChildProperty = 1}; - var target = Mapper.Map(source); - target.ParentProperty.ShouldBe(source.ParentProperty); - target.ChildProperty.ShouldBe(source.ChildProperty); - } - - [Fact] - public void PublicSetterInGrandGrandparentWorks() - { - var source = new Source {ParentProperty = "ParentProperty", ChildProperty = 1}; - var target = Mapper.Map(source); - target.ParentProperty.ShouldBe(source.ParentProperty); - target.ChildProperty.ShouldBe(source.ChildProperty); - } - - [Fact] - public void PrivateSetterInParentWorks() - { - var source = new Source {ParentProperty = "ParentProperty", ChildProperty = 1}; - var target = Mapper.Map(source); - target.ParentProperty.ShouldBe(source.ParentProperty); - target.ChildProperty.ShouldBe(source.ChildProperty); - } - - [Fact] - public void PrivateSetterInGrandparentWorks() - { - var source = new Source {ParentProperty = "ParentProperty", ChildProperty = 1}; - var target = Mapper.Map(source); - target.ParentProperty.ShouldBe(source.ParentProperty); - target.ChildProperty.ShouldBe(source.ChildProperty); - } - - [Fact] - public void PrivateSetterInGrandGrandparentWorks() - { - var source = new Source {ParentProperty = "ParentProperty", ChildProperty = 1}; - var target = Mapper.Map(source); - target.ParentProperty.ShouldBe(source.ParentProperty); - target.ChildProperty.ShouldBe(source.ChildProperty); - } + var source = new Source {ParentProperty = "ParentProperty", ChildProperty = 1}; + var target = Mapper.Map(source); + target.ParentProperty.ShouldBe(source.ParentProperty); + target.ChildProperty.ShouldBe(source.ChildProperty); } - public class Source + + [Fact] + public void PublicSetterInGrandparentWorks() { - public string ParentProperty { get; set; } - public int ChildProperty{get; set;} + var source = new Source {ParentProperty = "ParentProperty", ChildProperty = 1}; + var target = Mapper.Map(source); + target.ParentProperty.ShouldBe(source.ParentProperty); + target.ChildProperty.ShouldBe(source.ChildProperty); } - public class Parent { - public string ParentProperty{get; set;} + [Fact] + public void PublicSetterInGrandGrandparentWorks() + { + var source = new Source {ParentProperty = "ParentProperty", ChildProperty = 1}; + var target = Mapper.Map(source); + target.ParentProperty.ShouldBe(source.ParentProperty); + target.ChildProperty.ShouldBe(source.ChildProperty); } - public class Child : Parent { - public int ChildProperty {get; set;} + [Fact] + public void PrivateSetterInParentWorks() + { + var source = new Source {ParentProperty = "ParentProperty", ChildProperty = 1}; + var target = Mapper.Map(source); + target.ParentProperty.ShouldBe(source.ParentProperty); + target.ChildProperty.ShouldBe(source.ChildProperty); } - public class GrandChild : Child { + [Fact] + public void PrivateSetterInGrandparentWorks() + { + var source = new Source {ParentProperty = "ParentProperty", ChildProperty = 1}; + var target = Mapper.Map(source); + target.ParentProperty.ShouldBe(source.ParentProperty); + target.ChildProperty.ShouldBe(source.ChildProperty); } - public class GrandGrandChild : GrandChild { + [Fact] + public void PrivateSetterInGrandGrandparentWorks() + { + var source = new Source {ParentProperty = "ParentProperty", ChildProperty = 1}; + var target = Mapper.Map(source); + target.ParentProperty.ShouldBe(source.ParentProperty); + target.ChildProperty.ShouldBe(source.ChildProperty); } +} - public class ParentPrivate { - public string ParentProperty{get; private set;} - } +public class Source +{ + public string ParentProperty { get; set; } + public int ChildProperty{get; set;} +} - public class ChildPrivate : ParentPrivate { - public int ChildProperty {get;private set;} - } +public class Parent { + public string ParentProperty{get; set;} +} - public class GrandChildPrivate : ChildPrivate { - } +public class Child : Parent { + public int ChildProperty {get; set;} +} - public class GrandGrandChildPrivate : GrandChildPrivate { - } +public class GrandChild : Child { +} + +public class GrandGrandChild : GrandChild { +} + +public class ParentPrivate { + public string ParentProperty{get; private set;} +} + +public class ChildPrivate : ParentPrivate { + public int ChildProperty {get;private set;} +} + +public class GrandChildPrivate : ChildPrivate { +} + +public class GrandGrandChildPrivate : GrandChildPrivate { } \ No newline at end of file diff --git a/src/UnitTests/Bug/BaseMapWithIncludesAndUnincludedMappings.cs b/src/UnitTests/Bug/BaseMapWithIncludesAndUnincludedMappings.cs index e8b7626e99..c9a9859fdf 100644 --- a/src/UnitTests/Bug/BaseMapWithIncludesAndUnincludedMappings.cs +++ b/src/UnitTests/Bug/BaseMapWithIncludesAndUnincludedMappings.cs @@ -1,122 +1,121 @@ using Xunit; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class BaseMapWithIncludesAndUnincludedMappings { - public class BaseMapWithIncludesAndUnincludedMappings + public class ADTO { - public class ADTO - { - public int Prop { get; set; } - } + public int Prop { get; set; } + } - public class BDTO : ADTO - { - public int PropB { get; set; } - } + public class BDTO : ADTO + { + public int PropB { get; set; } + } - public class BDTO2 : ADTO - { + public class BDTO2 : ADTO + { - } + } - public class A - { - public int Prop { get; set; } - } + public class A + { + public int Prop { get; set; } + } - public class B : A - { - public int PropB { get; set; } - } + public class B : A + { + public int PropB { get; set; } + } - public void base_has_include_of_source_but_mapping_with_both_sides_being_unmapped_types_from_the_base_fails() + public void base_has_include_of_source_but_mapping_with_both_sides_being_unmapped_types_from_the_base_fails() + { + var config = new MapperConfiguration(cfg => { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap().Include(); - cfg.CreateMap(); - }); - var a = config.CreateMapper().Map(new B(), new BDTO2()); // Throws invalid cast exception trying to convert BDTO2 to BDTO - } + cfg.CreateMap().Include(); + cfg.CreateMap(); + }); + var a = config.CreateMapper().Map(new B(), new BDTO2()); // Throws invalid cast exception trying to convert BDTO2 to BDTO } +} - public class BaseMapChildProperty +public class BaseMapChildProperty +{ + public class Container { - public class Container - { - public BaseA Item { get; set; } - } + public BaseA Item { get; set; } + } - public class Container2 - { - public BaseB Item { get; set; } - } - public abstract class BaseA - { - public string Name { get; set; } - } + public class Container2 + { + public BaseB Item { get; set; } + } + public abstract class BaseA + { + public string Name { get; set; } + } - public abstract class BaseB - { - public string Name { get; set; } - } + public abstract class BaseB + { + public string Name { get; set; } + } - public class ProxyOfSubA : SubA - { - } - public class SubA : BaseA - { - public string Description { get; set; } - } + public class ProxyOfSubA : SubA + { + } + public class SubA : BaseA + { + public string Description { get; set; } + } - public class SubB : BaseB - { - public string Description { get; set; } - } + public class SubB : BaseB + { + public string Description { get; set; } + } - [Fact] - public void TestInitialiserProxyOfSub() + [Fact] + public void TestInitialiserProxyOfSub() + { + var config = new MapperConfiguration(cfg => { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap(); - cfg.CreateMap().As(); - cfg.CreateMap(); - }); + cfg.CreateMap(); + cfg.CreateMap().As(); + cfg.CreateMap(); + }); - var mapped = config.CreateMapper() - .Map(new Container() { Item = new ProxyOfSubA() { Name = "Martin", Description = "Hello" } }); - Assert.IsType(mapped.Item); + var mapped = config.CreateMapper() + .Map(new Container() { Item = new ProxyOfSubA() { Name = "Martin", Description = "Hello" } }); + Assert.IsType(mapped.Item); - } + } - [Fact] - public void TestInitialiserProxyOfSub1() + [Fact] + public void TestInitialiserProxyOfSub1() + { + var config = new MapperConfiguration(cfg => { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap(); - cfg.CreateMap(); - }); + cfg.CreateMap(); + cfg.CreateMap(); + }); - var mapped = config.CreateMapper().Map(new ProxyOfSubA() { Name = "Martin", Description = "Hello" }); - Assert.IsType(mapped); + var mapped = config.CreateMapper().Map(new ProxyOfSubA() { Name = "Martin", Description = "Hello" }); + Assert.IsType(mapped); - } + } - [Fact] - public void TestInitialiserProxyOfSubInclude() + [Fact] + public void TestInitialiserProxyOfSubInclude() + { + var config = new MapperConfiguration(cfg => { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap().Include(); - cfg.CreateMap(); - cfg.CreateMap(); - }); + cfg.CreateMap().Include(); + cfg.CreateMap(); + cfg.CreateMap(); + }); - var mapped = config.CreateMapper().Map(new Container() { Item = new ProxyOfSubA() { Name = "Martin", Description = "Hello" } }); - Assert.IsType(mapped.Item); + var mapped = config.CreateMapper().Map(new Container() { Item = new ProxyOfSubA() { Name = "Martin", Description = "Hello" } }); + Assert.IsType(mapped.Item); - } } } \ No newline at end of file diff --git a/src/UnitTests/Bug/CannotConvertEnumToNullable.cs b/src/UnitTests/Bug/CannotConvertEnumToNullable.cs index fbcd17bd04..b8a366a752 100644 --- a/src/UnitTests/Bug/CannotConvertEnumToNullable.cs +++ b/src/UnitTests/Bug/CannotConvertEnumToNullable.cs @@ -1,36 +1,35 @@ using Shouldly; using Xunit; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class CannotConvertEnumToNullable { - public class CannotConvertEnumToNullable + public enum DummyTypes : int { - public enum DummyTypes : int - { - Foo = 1, - Bar = 2 - } + Foo = 1, + Bar = 2 + } - public class DummySource - { - public DummyTypes Dummy { get; set; } - } + public class DummySource + { + public DummyTypes Dummy { get; set; } + } - public class DummyDestination - { - public int? Dummy { get; set; } - } + public class DummyDestination + { + public int? Dummy { get; set; } + } - [Fact] - public void Should_map_enum_to_nullable() - { - var config = new MapperConfiguration(cfg => cfg.CreateMap()); - config.AssertConfigurationIsValid(); - DummySource src = new DummySource() { Dummy = DummyTypes.Bar }; + [Fact] + public void Should_map_enum_to_nullable() + { + var config = new MapperConfiguration(cfg => cfg.CreateMap()); + config.AssertConfigurationIsValid(); + DummySource src = new DummySource() { Dummy = DummyTypes.Bar }; - var destination = config.CreateMapper().Map(src); + var destination = config.CreateMapper().Map(src); - destination.Dummy.ShouldBe((int)DummyTypes.Bar); - } + destination.Dummy.ShouldBe((int)DummyTypes.Bar); } } diff --git a/src/UnitTests/Bug/CannotMapICollectionToAggregateSumDestination.cs b/src/UnitTests/Bug/CannotMapICollectionToAggregateSumDestination.cs index 655821e993..deda64617e 100644 --- a/src/UnitTests/Bug/CannotMapICollectionToAggregateSumDestination.cs +++ b/src/UnitTests/Bug/CannotMapICollectionToAggregateSumDestination.cs @@ -4,50 +4,49 @@ using AutoMapper.QueryableExtensions; using System.Collections.Generic; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class CannotMapICollectionToAggregateSumDestination { - public class CannotMapICollectionToAggregateSumDestination + class DummySource { - class DummySource - { - public ICollection DummyCollection { get; set; } - } + public ICollection DummyCollection { get; set; } + } - class DummyDestination - { - public int DummyCollectionSum { get; set; } - } + class DummyDestination + { + public int DummyCollectionSum { get; set; } + } - [Fact] - public void Should_map_icollection_to_aggregate_sum_destination() + [Fact] + public void Should_map_icollection_to_aggregate_sum_destination() + { + // arrange + var config = new MapperConfiguration(cfg => { - // arrange - var config = new MapperConfiguration(cfg => - { - cfg.CreateProjection(); - }); + cfg.CreateProjection(); + }); - // act - // do nothing + // act + // do nothing - // assert - config.AssertConfigurationIsValid(); - } + // assert + config.AssertConfigurationIsValid(); + } - [Fact] - public void Should_project_icollection_to_aggregate_sum_destination() - { - // arrange - var config = new MapperConfiguration(cfg => cfg.CreateProjection()); - var source = new DummySource() { DummyCollection = new[] { 1, 4, 5 } }; - - // act - var destination = new[] { source }.AsQueryable() - .ProjectTo(config) - .Single(); - - // assert - destination.DummyCollectionSum.ShouldBe(10); - } + [Fact] + public void Should_project_icollection_to_aggregate_sum_destination() + { + // arrange + var config = new MapperConfiguration(cfg => cfg.CreateProjection()); + var source = new DummySource() { DummyCollection = new[] { 1, 4, 5 } }; + + // act + var destination = new[] { source }.AsQueryable() + .ProjectTo(config) + .Single(); + + // assert + destination.DummyCollectionSum.ShouldBe(10); } } diff --git a/src/UnitTests/Bug/CannotProjectIEnumerableToAggregateDestinations.cs b/src/UnitTests/Bug/CannotProjectIEnumerableToAggregateDestinations.cs index 6ef5b376c1..b715448352 100644 --- a/src/UnitTests/Bug/CannotProjectIEnumerableToAggregateDestinations.cs +++ b/src/UnitTests/Bug/CannotProjectIEnumerableToAggregateDestinations.cs @@ -4,40 +4,39 @@ using AutoMapper.QueryableExtensions; using System.Collections.Generic; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class CannotProjectIEnumerableToAggregateDestinations { - public class CannotProjectIEnumerableToAggregateDestinations + class DummySource { - class DummySource - { - public IEnumerable DummyEnumerable { get; set; } - } + public IEnumerable DummyEnumerable { get; set; } + } - class DummyDestination - { - public int DummyEnumerableCount { get; set; } - public int DummyEnumerableSum { get; set; } - public int DummyEnumerableMin { get; set; } - public int DummyEnumerableMax { get; set; } - } + class DummyDestination + { + public int DummyEnumerableCount { get; set; } + public int DummyEnumerableSum { get; set; } + public int DummyEnumerableMin { get; set; } + public int DummyEnumerableMax { get; set; } + } - [Fact] - public void Should_project_ienumerable_to_aggregate_destinations() - { - // arrange - var config = new MapperConfiguration(cfg => cfg.CreateProjection()); - var source = new DummySource() { DummyEnumerable = new[] { 1, 4, 5 } }; + [Fact] + public void Should_project_ienumerable_to_aggregate_destinations() + { + // arrange + var config = new MapperConfiguration(cfg => cfg.CreateProjection()); + var source = new DummySource() { DummyEnumerable = new[] { 1, 4, 5 } }; - // act - var destination = new[] { source }.AsQueryable() - .ProjectTo(config) - .Single(); + // act + var destination = new[] { source }.AsQueryable() + .ProjectTo(config) + .Single(); - // assert - destination.DummyEnumerableCount.ShouldBe(3); - destination.DummyEnumerableSum.ShouldBe(10); - destination.DummyEnumerableMin.ShouldBe(1); - destination.DummyEnumerableMax.ShouldBe(5); - } + // assert + destination.DummyEnumerableCount.ShouldBe(3); + destination.DummyEnumerableSum.ShouldBe(10); + destination.DummyEnumerableMin.ShouldBe(1); + destination.DummyEnumerableMax.ShouldBe(5); } } diff --git a/src/UnitTests/Bug/CannotProjectStringToNullableEnum.cs b/src/UnitTests/Bug/CannotProjectStringToNullableEnum.cs index 688ce4950b..d080c8710d 100644 --- a/src/UnitTests/Bug/CannotProjectStringToNullableEnum.cs +++ b/src/UnitTests/Bug/CannotProjectStringToNullableEnum.cs @@ -4,42 +4,41 @@ using AutoMapper; using AutoMapper.QueryableExtensions; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class CannotProjectStringToNullableEnum { - public class CannotProjectStringToNullableEnum + public enum DummyTypes : int { - public enum DummyTypes : int - { - Foo = 1, - Bar = 2 - } + Foo = 1, + Bar = 2 + } - public class DummySource - { - public string Dummy { get; set; } - } + public class DummySource + { + public string Dummy { get; set; } + } - public class DummyDestination - { - public DummyTypes? Dummy { get; set; } - } + public class DummyDestination + { + public DummyTypes? Dummy { get; set; } + } - [Fact] - public void Should_project_string_to_nullable_enum() + [Fact] + public void Should_project_string_to_nullable_enum() + { + var config = new MapperConfiguration(cfg => { - var config = new MapperConfiguration(cfg => - { - cfg.CreateProjection().ConvertUsing(s => (DummyTypes)System.Enum.Parse(typeof(DummyTypes),s)); - cfg.CreateProjection(); - }); + cfg.CreateProjection().ConvertUsing(s => (DummyTypes)System.Enum.Parse(typeof(DummyTypes),s)); + cfg.CreateProjection(); + }); - config.AssertConfigurationIsValid(); + config.AssertConfigurationIsValid(); - var src = new DummySource[] { new DummySource { Dummy = "Foo" } }; + var src = new DummySource[] { new DummySource { Dummy = "Foo" } }; - var destination = src.AsQueryable().ProjectTo(config).First(); + var destination = src.AsQueryable().ProjectTo(config).First(); - destination.Dummy.ShouldBe(DummyTypes.Foo); - } + destination.Dummy.ShouldBe(DummyTypes.Foo); } } diff --git a/src/UnitTests/Bug/CaseSensitivityBug.cs b/src/UnitTests/Bug/CaseSensitivityBug.cs index 7476b43293..4dc42d645b 100644 --- a/src/UnitTests/Bug/CaseSensitivityBug.cs +++ b/src/UnitTests/Bug/CaseSensitivityBug.cs @@ -1,23 +1,22 @@ -namespace AutoMapper.UnitTests.Bug -{ - using Xunit; +namespace AutoMapper.UnitTests.Bug; + +using Xunit; - public class CaseSensitivityBug : AutoMapperSpecBase +public class CaseSensitivityBug : AutoMapperSpecBase +{ + protected override MapperConfiguration CreateConfiguration() => new(cfg => { - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - }); - public class Foo - { - public int ID { get; set; } - } + cfg.CreateMap(); + }); + public class Foo + { + public int ID { get; set; } + } - public class Bar - { - public int id { get; set; } - } - [Fact] - public void Validate() => AssertConfigurationIsValid(); + public class Bar + { + public int id { get; set; } } + [Fact] + public void Validate() => AssertConfigurationIsValid(); } \ No newline at end of file diff --git a/src/UnitTests/Bug/CollectionBaseClassGetConvention.cs b/src/UnitTests/Bug/CollectionBaseClassGetConvention.cs index 56eb404adb..c52dc4a304 100644 --- a/src/UnitTests/Bug/CollectionBaseClassGetConvention.cs +++ b/src/UnitTests/Bug/CollectionBaseClassGetConvention.cs @@ -5,44 +5,43 @@ using AutoMapper; using Xunit; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class CollectionBaseClassGetConvention : AutoMapperSpecBase { - public class CollectionBaseClassGetConvention : AutoMapperSpecBase - { - Destination _destination; - static int[] SomeCollection = new[] { 1, 2, 3 }; + Destination _destination; + static int[] SomeCollection = new[] { 1, 2, 3 }; - public abstract class SourceBase + public abstract class SourceBase + { + public IEnumerable GetItems() { - public IEnumerable GetItems() - { - return SomeCollection; - } + return SomeCollection; } + } - public class Source : SourceBase - { - } + public class Source : SourceBase + { + } - public class Destination - { - public IEnumerable Items { get; set; } - } + public class Destination + { + public IEnumerable Items { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + }); - protected override void Because_of() - { - _destination = Mapper.Map(new Source()); - } + protected override void Because_of() + { + _destination = Mapper.Map(new Source()); + } - [Fact] - public void Should_map_collection_with_get_convention() - { - _destination.Items.SequenceEqual(SomeCollection).ShouldBeTrue(); - } + [Fact] + public void Should_map_collection_with_get_convention() + { + _destination.Items.SequenceEqual(SomeCollection).ShouldBeTrue(); } } \ No newline at end of file diff --git a/src/UnitTests/Bug/CollectionMapperMapsISetIncorrectly.cs b/src/UnitTests/Bug/CollectionMapperMapsISetIncorrectly.cs index a7dbfd8a0b..8e594d57c5 100644 --- a/src/UnitTests/Bug/CollectionMapperMapsISetIncorrectly.cs +++ b/src/UnitTests/Bug/CollectionMapperMapsISetIncorrectly.cs @@ -3,44 +3,43 @@ using AutoMapper.Internal.Mappers; using Xunit; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class CollectionMapperMapsIEnumerableToISetIncorrectly { - public class CollectionMapperMapsIEnumerableToISetIncorrectly + public class TypeWithStringProperty { - public class TypeWithStringProperty - { - public string Value { get; set; } - } + public string Value { get; set; } + } - public class SourceWithIEnumerable - { - public IEnumerable Stuff { get; set; } - } + public class SourceWithIEnumerable + { + public IEnumerable Stuff { get; set; } + } - public class TargetWithISet - { - public ISet Stuff { get; set; } - } + public class TargetWithISet + { + public ISet Stuff { get; set; } + } - [Fact] - public void ShouldMapToNewISet() - { - var config = new MapperConfiguration(cfg => - cfg.CreateMap() - .ForMember(dest => dest.Stuff, opt => opt.MapFrom(src => src.Stuff.Select(s => s.Value)))); + [Fact] + public void ShouldMapToNewISet() + { + var config = new MapperConfiguration(cfg => + cfg.CreateMap() + .ForMember(dest => dest.Stuff, opt => opt.MapFrom(src => src.Stuff.Select(s => s.Value)))); - var source = new SourceWithIEnumerable - { - Stuff = new[] - { - new TypeWithStringProperty { Value = "Microphone" }, - new TypeWithStringProperty { Value = "Check" }, - new TypeWithStringProperty { Value = "1, 2" }, - new TypeWithStringProperty { Value = "What is this?" } - } - }; + var source = new SourceWithIEnumerable + { + Stuff = new[] + { + new TypeWithStringProperty { Value = "Microphone" }, + new TypeWithStringProperty { Value = "Check" }, + new TypeWithStringProperty { Value = "1, 2" }, + new TypeWithStringProperty { Value = "What is this?" } + } + }; - var target = config.CreateMapper().Map(source); - } + var target = config.CreateMapper().Map(source); } } diff --git a/src/UnitTests/Bug/CollectionWhere.cs b/src/UnitTests/Bug/CollectionWhere.cs index b18d712c08..b507d2e53f 100644 --- a/src/UnitTests/Bug/CollectionWhere.cs +++ b/src/UnitTests/Bug/CollectionWhere.cs @@ -4,51 +4,50 @@ using System.Linq; using System.Collections.Generic; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class CollectionWhere : AutoMapperSpecBase { - public class CollectionWhere : AutoMapperSpecBase - { - private Destination _destination; - private List _sourceList = new List() { 1, 2, 3 }; + private Destination _destination; + private List _sourceList = new List() { 1, 2, 3 }; - class Source - { - public int Id { get; set; } + class Source + { + public int Id { get; set; } - public IEnumerable ListProperty { get; set; } - } + public IEnumerable ListProperty { get; set; } + } - class Destination - { - public int Id { get; set; } + class Destination + { + public int Id { get; set; } - public IEnumerable ListProperty { get; set; } - } + public IEnumerable ListProperty { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + }); - protected override void Because_of() + protected override void Because_of() + { + var source = new Source() { - var source = new Source() - { - Id = 1, - ListProperty = _sourceList, - }; - _destination = new Destination() - { - Id = 2, - ListProperty = new List() { 4, 5, 6 }.Where(a=>true).ToArray() - }; - _destination = Mapper.Map(source, _destination); - } - - [Fact] - public void Should_map_collections_with_where() + Id = 1, + ListProperty = _sourceList, + }; + _destination = new Destination() { - Enumerable.SequenceEqual(_destination.ListProperty, _sourceList).ShouldBeTrue(); - } + Id = 2, + ListProperty = new List() { 4, 5, 6 }.Where(a=>true).ToArray() + }; + _destination = Mapper.Map(source, _destination); + } + + [Fact] + public void Should_map_collections_with_where() + { + Enumerable.SequenceEqual(_destination.ListProperty, _sourceList).ShouldBeTrue(); } } \ No newline at end of file diff --git a/src/UnitTests/Bug/CollectionsNullability.cs b/src/UnitTests/Bug/CollectionsNullability.cs index 42c2f96205..e8009d651c 100644 --- a/src/UnitTests/Bug/CollectionsNullability.cs +++ b/src/UnitTests/Bug/CollectionsNullability.cs @@ -3,38 +3,37 @@ using System; using System.Collections.Generic; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class CollectionsNullability : AutoMapperSpecBase { - public class CollectionsNullability : AutoMapperSpecBase - { - Holder _destination; + Holder _destination; - public class Container - { - public List Items { get; set; } - } + public class Container + { + public List Items { get; set; } + } - class Holder - { - public Container[] Containers { get; set; } - } + class Holder + { + public Container[] Containers { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - cfg.CreateMap(); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + cfg.CreateMap(); + }); - protected override void Because_of() - { - var from = new Holder { Containers = new[] { new Container() } }; - _destination = Mapper.Map(from); - } + protected override void Because_of() + { + var from = new Holder { Containers = new[] { new Container() } }; + _destination = Mapper.Map(from); + } - [Fact] - public void Should_map_null_collection_to_not_null() - { - _destination.Containers[0].Items.ShouldNotBeNull(); - } + [Fact] + public void Should_map_null_collection_to_not_null() + { + _destination.Containers[0].Items.ShouldNotBeNull(); } } \ No newline at end of file diff --git a/src/UnitTests/Bug/ConstructUsingReturnsNull.cs b/src/UnitTests/Bug/ConstructUsingReturnsNull.cs index 03918597ed..8392d5e683 100644 --- a/src/UnitTests/Bug/ConstructUsingReturnsNull.cs +++ b/src/UnitTests/Bug/ConstructUsingReturnsNull.cs @@ -2,29 +2,28 @@ using Shouldly; using System; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class ConstructUsingReturnsNull : AutoMapperSpecBase { - public class ConstructUsingReturnsNull : AutoMapperSpecBase + class Source + { + public int Number { get; set; } + } + class Destination { - class Source - { - public int Number { get; set; } - } - class Destination - { - public int Number { get; set; } - } + public int Number { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().ConstructUsing((Source source) => null); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().ConstructUsing((Source source) => null); + }); - [Fact] - public void Should_throw_when_construct_using_returns_null() - { - new Action(() => Mapper.Map(new Source())) - .ShouldThrowException(ex=>ex.InnerException.ShouldBeOfType()); - } + [Fact] + public void Should_throw_when_construct_using_returns_null() + { + new Action(() => Mapper.Map(new Source())) + .ShouldThrowException(ex=>ex.InnerException.ShouldBeOfType()); } } \ No newline at end of file diff --git a/src/UnitTests/Bug/ConstructorParameterNamedType.cs b/src/UnitTests/Bug/ConstructorParameterNamedType.cs index 06afd07f89..ad3fcfde1f 100644 --- a/src/UnitTests/Bug/ConstructorParameterNamedType.cs +++ b/src/UnitTests/Bug/ConstructorParameterNamedType.cs @@ -2,29 +2,28 @@ using Shouldly; using Xunit; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class ConstructorParameterNamedType { - public class ConstructorParameterNamedType + public class SourceClass { } + + public class DestinationClass { - public class SourceClass { } + public DestinationClass() { } - public class DestinationClass + public DestinationClass(int type) { - public DestinationClass() { } - - public DestinationClass(int type) - { - Type = type; - } - - public int Type { get; private set; } + Type = type; } - [Fact] - public void Should_handle_constructor_parameter_named_type() - { - var config = new MapperConfiguration(c => c.CreateMap()); - new Action(config.AssertConfigurationIsValid).ShouldThrowException(ex=>ex.Errors[0].UnmappedPropertyNames[0].ShouldBe("Type")); - } + public int Type { get; private set; } + } + + [Fact] + public void Should_handle_constructor_parameter_named_type() + { + var config = new MapperConfiguration(c => c.CreateMap()); + new Action(config.AssertConfigurationIsValid).ShouldThrowException(ex=>ex.Errors[0].UnmappedPropertyNames[0].ShouldBe("Type")); } } \ No newline at end of file diff --git a/src/UnitTests/Bug/ConvertMapperThreading.cs b/src/UnitTests/Bug/ConvertMapperThreading.cs index f167045cb3..f82d14fd9a 100644 --- a/src/UnitTests/Bug/ConvertMapperThreading.cs +++ b/src/UnitTests/Bug/ConvertMapperThreading.cs @@ -6,42 +6,41 @@ using System.Diagnostics; using System.Runtime.ExceptionServices; -namespace AutoMapper.UnitTests +namespace AutoMapper.UnitTests; + +public class ConvertMapperThreading { - public class ConvertMapperThreading + class Source { - class Source - { - public string Number { get; set; } - } + public string Number { get; set; } + } - class Destination - { - public int Number { get; set; } - } + class Destination + { + public int Number { get; set; } + } - [Fact] - public void Should_work() + [Fact] + public void Should_work() + { + var tasks = Enumerable.Range(0, 5).Select(i => Task.Factory.StartNew(() => + { + new MapperConfiguration(c => c.CreateMap()); + })).ToArray(); + try { - var tasks = Enumerable.Range(0, 5).Select(i => Task.Factory.StartNew(() => - { - new MapperConfiguration(c => c.CreateMap()); - })).ToArray(); - try - { - Task.WaitAll(tasks); - } - catch(AggregateException ex) + Task.WaitAll(tasks); + } + catch(AggregateException ex) + { + ex.Handle(e => { - ex.Handle(e => + if(e is InvalidOperationException) { - if(e is InvalidOperationException) - { - throw e; - } - return false; - }); - } - } + throw e; + } + return false; + }); + } } } \ No newline at end of file diff --git a/src/UnitTests/Bug/CreateMapExpressionWithIgnoredPropertyBug.cs b/src/UnitTests/Bug/CreateMapExpressionWithIgnoredPropertyBug.cs index 6595b0e657..527d295216 100644 --- a/src/UnitTests/Bug/CreateMapExpressionWithIgnoredPropertyBug.cs +++ b/src/UnitTests/Bug/CreateMapExpressionWithIgnoredPropertyBug.cs @@ -4,31 +4,30 @@ using Shouldly; using Xunit; -namespace AutoMapper.UnitTests.Bug -{ - using QueryableExtensions; +namespace AutoMapper.UnitTests.Bug; + +using QueryableExtensions; - public class CreateMapExpressionWithIgnoredPropertyBug +public class CreateMapExpressionWithIgnoredPropertyBug +{ + [Fact] + public void ShouldNotMapPropertyWhenItIsIgnored() { - [Fact] - public void ShouldNotMapPropertyWhenItIsIgnored() + var config = new MapperConfiguration(cfg => { - var config = new MapperConfiguration(cfg => - { - cfg.CreateProjection() - .ForMember(x => x.Name, x => x.Ignore()); - }); + cfg.CreateProjection() + .ForMember(x => x.Name, x => x.Ignore()); + }); - IQueryable collection = (new List { new Person { Name = "Person1" } }).AsQueryable(); + IQueryable collection = (new List { new Person { Name = "Person1" } }).AsQueryable(); - List result = collection.ProjectTo(config).ToList(); + List result = collection.ProjectTo(config).ToList(); - result.ForEach(x => x.Name.ShouldBeNull()); - } + result.ForEach(x => x.Name.ShouldBeNull()); + } - public class Person - { - public string Name { get; set; } - } + public class Person + { + public string Name { get; set; } } } \ No newline at end of file diff --git a/src/UnitTests/Bug/CustomConverters.cs b/src/UnitTests/Bug/CustomConverters.cs index cf08e7a9b8..7dbedb6f3b 100644 --- a/src/UnitTests/Bug/CustomConverters.cs +++ b/src/UnitTests/Bug/CustomConverters.cs @@ -2,148 +2,147 @@ using Shouldly; using System; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class NullableTypeConverter : AutoMapperSpecBase { - public class NullableTypeConverter : AutoMapperSpecBase - { - Destination _destination; + Destination _destination; - class Source - { - public DateTimeOffset? Date { get; set; } - } + class Source + { + public DateTimeOffset? Date { get; set; } + } - class Destination - { - public DateTime? Date { get; set; } - } + class Destination + { + public DateTime? Date { get; set; } + } - public class NullableDateTimeOffsetConverter : ITypeConverter + public class NullableDateTimeOffsetConverter : ITypeConverter + { + public DateTime? Convert(DateTimeOffset? source, DateTime? destination, ResolutionContext context) { - public DateTime? Convert(DateTimeOffset? source, DateTime? destination, ResolutionContext context) + if(source.HasValue) { - if(source.HasValue) - { - return source.Value.DateTime; - } - return default(DateTime?); + return source.Value.DateTime; } + return default(DateTime?); } + } - protected override MapperConfiguration CreateConfiguration() => new(c => - { - c.CreateMap(); - c.CreateMap().ConvertUsing(); - }); + protected override MapperConfiguration CreateConfiguration() => new(c => + { + c.CreateMap(); + c.CreateMap().ConvertUsing(); + }); - protected override void Because_of() - { - _destination = Mapper.Map(new Source { Date = DateTimeOffset.MaxValue }); - } + protected override void Because_of() + { + _destination = Mapper.Map(new Source { Date = DateTimeOffset.MaxValue }); + } - [Fact] - public void Should_use_the_converter() - { - _destination.Date.ShouldBe(DateTime.MaxValue); - } + [Fact] + public void Should_use_the_converter() + { + _destination.Date.ShouldBe(DateTime.MaxValue); } +} - public class CustomConverters : AutoMapperSpecBase +public class CustomConverters : AutoMapperSpecBase +{ + public class NullableIntToBoolConverter : ITypeConverter { - public class NullableIntToBoolConverter : ITypeConverter + public bool Convert(int? source, bool destination, ResolutionContext context) { - public bool Convert(int? source, bool destination, ResolutionContext context) - { - if(source == null) - return false; + if(source == null) + return false; - return source == 1; - } + return source == 1; } + } - public class BoolToNullableIntConverter : ITypeConverter + public class BoolToNullableIntConverter : ITypeConverter + { + public int? Convert(bool source, int? destination, ResolutionContext context) { - public int? Convert(bool source, int? destination, ResolutionContext context) - { - return source ? 1 : 0; - } + return source ? 1 : 0; } + } - public class IntToBoolConverter : ITypeConverter + public class IntToBoolConverter : ITypeConverter + { + public bool Convert(int source, bool destination, ResolutionContext context) { - public bool Convert(int source, bool destination, ResolutionContext context) - { - return source == 1; - } + return source == 1; } + } - public class BoolToIntConverter : ITypeConverter + public class BoolToIntConverter : ITypeConverter + { + public int Convert(bool source, int destination, ResolutionContext context) { - public int Convert(bool source, int destination, ResolutionContext context) - { - return source ? 1 : 0; - } + return source ? 1 : 0; } + } - private class IntEntity - { - public int IntProperty { get; set; } - - public IntEntity() { } + private class IntEntity + { + public int IntProperty { get; set; } - public IntEntity(int value) - { - IntProperty = value; - } - } + public IntEntity() { } - private class BoolModel + public IntEntity(int value) { - public bool IntProperty { get; set; } + IntProperty = value; + } + } - public BoolModel() { } + private class BoolModel + { + public bool IntProperty { get; set; } - public BoolModel(bool value) - { - IntProperty = value; - } - } + public BoolModel() { } - private class NullableIntEntity + public BoolModel(bool value) { - public int? IntProperty { get; set; } + IntProperty = value; + } + } - public NullableIntEntity() { } + private class NullableIntEntity + { + public int? IntProperty { get; set; } - public NullableIntEntity(int? value) - { - IntProperty = value; - } - } - + public NullableIntEntity() { } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().ConvertUsing(); - cfg.CreateMap().ConvertUsing(); - cfg.CreateMap().ConvertUsing(); - cfg.CreateMap().ConvertUsing(); - cfg.CreateMap().ReverseMap(); - cfg.CreateMap().ReverseMap(); - }); - - [Fact] - public void CheckConverters() + public NullableIntEntity(int? value) { - Mapper.Map(1).ShouldBeTrue(); - Mapper.Map(0).ShouldBeFalse(); - Mapper.Map(0).ShouldBeFalse(); - Mapper.Map(1).ShouldBeTrue(); - Mapper.Map(true).ShouldBe(1); - Mapper.Map(false).ShouldBe(0); - Mapper.Map(true).ShouldBe(1); - Mapper.Map(false).ShouldBe(0); - Mapper.Map(null).ShouldBeFalse(); + IntProperty = value; } } + + + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().ConvertUsing(); + cfg.CreateMap().ConvertUsing(); + cfg.CreateMap().ConvertUsing(); + cfg.CreateMap().ConvertUsing(); + cfg.CreateMap().ReverseMap(); + cfg.CreateMap().ReverseMap(); + }); + + [Fact] + public void CheckConverters() + { + Mapper.Map(1).ShouldBeTrue(); + Mapper.Map(0).ShouldBeFalse(); + Mapper.Map(0).ShouldBeFalse(); + Mapper.Map(1).ShouldBeTrue(); + Mapper.Map(true).ShouldBe(1); + Mapper.Map(false).ShouldBe(0); + Mapper.Map(true).ShouldBe(1); + Mapper.Map(false).ShouldBe(0); + Mapper.Map(null).ShouldBeFalse(); + } } \ No newline at end of file diff --git a/src/UnitTests/Bug/CustomIEnumerableBug.cs b/src/UnitTests/Bug/CustomIEnumerableBug.cs index 80f864ac5f..807bdd431a 100644 --- a/src/UnitTests/Bug/CustomIEnumerableBug.cs +++ b/src/UnitTests/Bug/CustomIEnumerableBug.cs @@ -6,58 +6,57 @@ using Shouldly; using Xunit; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class One { - public class One - { - public IEnumerable Stuff { get; set; } - } + public IEnumerable Stuff { get; set; } +} - public class Two - { - public IEnumerable Stuff { get; set; } - } +public class Two +{ + public IEnumerable Stuff { get; set; } +} - public class Item - { - public string Value { get; set; } - } +public class Item +{ + public string Value { get; set; } +} - public class StringToItemConverter : ITypeConverter, IEnumerable> +public class StringToItemConverter : ITypeConverter, IEnumerable> +{ + public IEnumerable Convert(IEnumerable source, IEnumerable destination, ResolutionContext context) { - public IEnumerable Convert(IEnumerable source, IEnumerable destination, ResolutionContext context) - { - var result = new List(); - foreach (string s in source) - if (!String.IsNullOrEmpty(s)) - result.Add(new Item { Value = s }); - return result; - } + var result = new List(); + foreach (string s in source) + if (!String.IsNullOrEmpty(s)) + result.Add(new Item { Value = s }); + return result; } - public class AutoMapperBugTest +} +public class AutoMapperBugTest +{ + [Fact] + public void ShouldMapOneToTwo() { - [Fact] - public void ShouldMapOneToTwo() + var config = new MapperConfiguration(cfg => { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap(); + cfg.CreateMap(); - cfg.CreateMap, IEnumerable>().ConvertUsing(); - }); + cfg.CreateMap, IEnumerable>().ConvertUsing(); + }); - config.AssertConfigurationIsValid(); + config.AssertConfigurationIsValid(); - var engine = config.CreateMapper(); - var one = new One - { - Stuff = new List { "hi", "", "mom" } - }; + var engine = config.CreateMapper(); + var one = new One + { + Stuff = new List { "hi", "", "mom" } + }; - var two = engine.Map(one); + var two = engine.Map(one); - two.ShouldNotBeNull(); - two.Stuff.Count().ShouldBe(2); - } + two.ShouldNotBeNull(); + two.Stuff.Count().ShouldBe(2); } } diff --git a/src/UnitTests/Bug/DeepCloningBug.cs b/src/UnitTests/Bug/DeepCloningBug.cs index c4d26640d9..14ff7f18f5 100644 --- a/src/UnitTests/Bug/DeepCloningBug.cs +++ b/src/UnitTests/Bug/DeepCloningBug.cs @@ -1,46 +1,45 @@ -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +using System; +using Shouldly; +using Xunit; + +public class DeepCloningBug : AutoMapperSpecBase { - using System; - using Shouldly; - using Xunit; + private Outer _source; + private Outer _dest; + + public class Outer + { + public Inner Foo { get; set; } + } + + public class Inner + { + + } + + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + cfg.CreateMap(); + }); + + protected override void Because_of() + { + _source = new Outer { Foo = new Inner() }; + _dest = Mapper.Map(_source); + } + + [Fact] + public void Should_map_new_top_object() + { + _dest.ShouldNotBeSameAs(_source); + } - public class DeepCloningBug : AutoMapperSpecBase + [Fact] + public void Should_map_new_second_level_object() { - private Outer _source; - private Outer _dest; - - public class Outer - { - public Inner Foo { get; set; } - } - - public class Inner - { - - } - - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - cfg.CreateMap(); - }); - - protected override void Because_of() - { - _source = new Outer { Foo = new Inner() }; - _dest = Mapper.Map(_source); - } - - [Fact] - public void Should_map_new_top_object() - { - _dest.ShouldNotBeSameAs(_source); - } - - [Fact] - public void Should_map_new_second_level_object() - { - _dest.Foo.ShouldNotBeSameAs(_source.Foo); - } + _dest.Foo.ShouldNotBeSameAs(_source.Foo); } } \ No newline at end of file diff --git a/src/UnitTests/Bug/DeepInheritanceIssue.cs b/src/UnitTests/Bug/DeepInheritanceIssue.cs index 391bd68a5a..1f1f4ba1a1 100644 --- a/src/UnitTests/Bug/DeepInheritanceIssue.cs +++ b/src/UnitTests/Bug/DeepInheritanceIssue.cs @@ -1,80 +1,79 @@ using Shouldly; using Xunit; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class DeepInheritanceIssue { - public class DeepInheritanceIssue + [Fact] + public void Example() { - [Fact] - public void Example() + var config = new MapperConfiguration(cfg => { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap(); + cfg.CreateMap(); - cfg.CreateMap() - .Include() - .Include(); + cfg.CreateMap() + .Include() + .Include(); - cfg.CreateMap() - .Include(); + cfg.CreateMap() + .Include(); - cfg.CreateMap(); - }); + cfg.CreateMap(); + }); - var expectedCSrc = new CSrc() {StringA = "A", StringB = "B", StringC = "C"}; - var expectedBSrc = new BSrc() {StringA = "A", StringB = "B"}; + var expectedCSrc = new CSrc() {StringA = "A", StringB = "B", StringC = "C"}; + var expectedBSrc = new BSrc() {StringA = "A", StringB = "B"}; - var expectedContCSrc = new ContainsASrc() {A = expectedCSrc}; - var expectedContBSrc = new ContainsASrc() {A = expectedBSrc}; + var expectedContCSrc = new ContainsASrc() {A = expectedCSrc}; + var expectedContBSrc = new ContainsASrc() {A = expectedBSrc}; - var mapper = config.CreateMapper(); - var actualContCDest = mapper.Map(expectedContCSrc); - var actualContBDest = mapper.Map(expectedContBSrc); // THROWS + var mapper = config.CreateMapper(); + var actualContCDest = mapper.Map(expectedContCSrc); + var actualContBDest = mapper.Map(expectedContBSrc); // THROWS - config.AssertConfigurationIsValid(); - actualContBDest.ShouldNotBeNull(); - actualContCDest.ShouldNotBeNull(); - } + config.AssertConfigurationIsValid(); + actualContBDest.ShouldNotBeNull(); + actualContCDest.ShouldNotBeNull(); } +} - public class ContainsASrc - { - public ASrc A { get; set; } - } +public class ContainsASrc +{ + public ASrc A { get; set; } +} - public abstract class ASrc - { - public string StringA { get; set; } - } +public abstract class ASrc +{ + public string StringA { get; set; } +} - public class BSrc : ASrc - { - public string StringB { get; set; } - } +public class BSrc : ASrc +{ + public string StringB { get; set; } +} - public class CSrc : BSrc - { - public string StringC { get; set; } - } +public class CSrc : BSrc +{ + public string StringC { get; set; } +} - public class ContainsADest - { - public ADest A { get; set; } - } +public class ContainsADest +{ + public ADest A { get; set; } +} - public abstract class ADest - { - public string StringA { get; set; } - } +public abstract class ADest +{ + public string StringA { get; set; } +} - public class BDest : ADest - { - public string StringB { get; set; } - } +public class BDest : ADest +{ + public string StringB { get; set; } +} - public class CDest : BDest - { - public string StringC { get; set; } - } +public class CDest : BDest +{ + public string StringC { get; set; } } \ No newline at end of file diff --git a/src/UnitTests/Bug/DestinationValueInitializedByCtorBug.cs b/src/UnitTests/Bug/DestinationValueInitializedByCtorBug.cs index f122a6ae52..5454f7e8b2 100644 --- a/src/UnitTests/Bug/DestinationValueInitializedByCtorBug.cs +++ b/src/UnitTests/Bug/DestinationValueInitializedByCtorBug.cs @@ -6,60 +6,59 @@ using Shouldly; using Xunit; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class DestinationValueInitializedByCtorBug : AutoMapperSpecBase { - public class DestinationValueInitializedByCtorBug : AutoMapperSpecBase + public class ItemToMapDto { - public class ItemToMapDto - { - public ItemToMapDto() - { - /* Remove the line below and the mapping works correctly*/ - this.Tag = new TagDto() { Name = Guid.NewGuid().ToString() }; - } - public string Name { get; set; } - public TagDto Tag { get; set; } - } - public class TagDto - { - public string Name { get; set; } - public bool IsTrue { get; set; } - } - public class ItemToMap + public ItemToMapDto() { - public string Name { get; set; } - public Tag Tag { get; set; } - } - public class Tag - { - public string Name { get; set; } - public bool IsTrue { get; set; } + /* Remove the line below and the mapping works correctly*/ + this.Tag = new TagDto() { Name = Guid.NewGuid().ToString() }; } + public string Name { get; set; } + public TagDto Tag { get; set; } + } + public class TagDto + { + public string Name { get; set; } + public bool IsTrue { get; set; } + } + public class ItemToMap + { + public string Name { get; set; } + public Tag Tag { get; set; } + } + public class Tag + { + public string Name { get; set; } + public bool IsTrue { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - cfg.CreateMap(); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + cfg.CreateMap(); + }); - [Fact] - public void Should_map_all_null_values_to_its_substitute() - { - var tag = new Tag(); + [Fact] + public void Should_map_all_null_values_to_its_substitute() + { + var tag = new Tag(); - List entities = new List(); + List entities = new List(); - for (int i = 0; i < 10; i++) + for (int i = 0; i < 10; i++) + { + entities.Add(new ItemToMap() { - entities.Add(new ItemToMap() - { - Name = Guid.NewGuid().ToString(), - Tag = tag, - }); - } - - Mapper.Map, List>(entities); - typeof(AutoMapperMappingException).ShouldNotBeThrownBy(() => Mapper.Map, List>(entities)); + Name = Guid.NewGuid().ToString(), + Tag = tag, + }); } + + Mapper.Map, List>(entities); + typeof(AutoMapperMappingException).ShouldNotBeThrownBy(() => Mapper.Map, List>(entities)); } } diff --git a/src/UnitTests/Bug/DuplicateExtensionMethods.cs b/src/UnitTests/Bug/DuplicateExtensionMethods.cs index 79804c44e6..052bf97ef5 100644 --- a/src/UnitTests/Bug/DuplicateExtensionMethods.cs +++ b/src/UnitTests/Bug/DuplicateExtensionMethods.cs @@ -3,42 +3,41 @@ using System; using System.Collections.Generic; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class DuplicateExtensionMethods : AutoMapperSpecBase { - public class DuplicateExtensionMethods : AutoMapperSpecBase + public class Outlay { - public class Outlay - { - public int Amount { get; set; } - } - - public enum AccountKind { None } + public int Amount { get; set; } + } - class Source - { - public int UserId { get; set; } - public string UserName { get; set; } - public string UserPhone { get; set; } - public string IDCard { get; set; } - public AccountKind Kind { get; set; } - public decimal UnUsedAmount { get; set; } - public List Outlay { get; set; } - } - class Destination - { - public int UserId { get; set; } - public string UserName { get; set; } - public string UserPhone { get; set; } - public string IDCard { get; set; } - public AccountKind Kind { get; set; } - public decimal UnUsedAmount { get; set; } - } + public enum AccountKind { None } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - }); - [Fact] - public void Validate() => AssertConfigurationIsValid(); + class Source + { + public int UserId { get; set; } + public string UserName { get; set; } + public string UserPhone { get; set; } + public string IDCard { get; set; } + public AccountKind Kind { get; set; } + public decimal UnUsedAmount { get; set; } + public List Outlay { get; set; } } + class Destination + { + public int UserId { get; set; } + public string UserName { get; set; } + public string UserPhone { get; set; } + public string IDCard { get; set; } + public AccountKind Kind { get; set; } + public decimal UnUsedAmount { get; set; } + } + + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + }); + [Fact] + public void Validate() => AssertConfigurationIsValid(); } \ No newline at end of file diff --git a/src/UnitTests/Bug/DuplicateValuesBugWithoutPR.cs b/src/UnitTests/Bug/DuplicateValuesBugWithoutPR.cs index 78f3bbfaf8..64c42dbc3b 100644 --- a/src/UnitTests/Bug/DuplicateValuesBugWithoutPR.cs +++ b/src/UnitTests/Bug/DuplicateValuesBugWithoutPR.cs @@ -2,71 +2,70 @@ using Xunit; using Shouldly; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class DuplicateValuesIssue { - public class DuplicateValuesIssue + public class SourceObject { - public class SourceObject - { - public int Id; - public IList Children; + public int Id; + public IList Children; - public void AddChild(SourceObject childObject) - { - if(this.Children == null) - this.Children = new List(); + public void AddChild(SourceObject childObject) + { + if(this.Children == null) + this.Children = new List(); - Children.Add(childObject); - } + Children.Add(childObject); } + } - public class DestObject - { - public int Id; - public IList Children; + public class DestObject + { + public int Id; + public IList Children; - public DestObject() - { - } + public DestObject() + { + } - public void AddChild(DestObject childObject) - { - if(this.Children == null) - this.Children = new List(); + public void AddChild(DestObject childObject) + { + if(this.Children == null) + this.Children = new List(); - Children.Add(childObject); - } + Children.Add(childObject); } + } - [Fact] - public void Should_map_the_existing_array_elements_over() - { - var sourceList = new List(); - var destList = new List(); + [Fact] + public void Should_map_the_existing_array_elements_over() + { + var sourceList = new List(); + var destList = new List(); - var config = new MapperConfiguration(cfg => cfg.CreateMap()); - config.AssertConfigurationIsValid(); + var config = new MapperConfiguration(cfg => cfg.CreateMap()); + config.AssertConfigurationIsValid(); - var source1 = new SourceObject - { - Id = 1, - }; - sourceList.Add(source1); + var source1 = new SourceObject + { + Id = 1, + }; + sourceList.Add(source1); - var source2 = new SourceObject - { - Id = 2, - }; - sourceList.Add(source2); + var source2 = new SourceObject + { + Id = 2, + }; + sourceList.Add(source2); - source1.AddChild(source2); // This causes the problem + source1.AddChild(source2); // This causes the problem - config.CreateMapper().Map(sourceList, destList); + config.CreateMapper().Map(sourceList, destList); - destList.Count.ShouldBe(2); - destList[0].Children.Count.ShouldBe(1); - destList[0].Children[0].ShouldBeSameAs(destList[1]); - } + destList.Count.ShouldBe(2); + destList[0].Children.Count.ShouldBe(1); + destList[0].Children[0].ShouldBeSameAs(destList[1]); } } \ No newline at end of file diff --git a/src/UnitTests/Bug/EFCollections.cs b/src/UnitTests/Bug/EFCollections.cs index f2fb1981eb..dda07596dc 100644 --- a/src/UnitTests/Bug/EFCollections.cs +++ b/src/UnitTests/Bug/EFCollections.cs @@ -4,57 +4,56 @@ using Xunit; using Shouldly; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class EFCollections : AutoMapperSpecBase { - public class EFCollections : AutoMapperSpecBase - { - private Dest _dest; + private Dest _dest; - public class Source - { - public ICollection Children { get; set; } + public class Source + { + public ICollection Children { get; set; } - } + } - public class OtherSource : Source - { - } + public class OtherSource : Source + { + } - public class OtherChild : Child - { + public class OtherChild : Child + { - } + } - public class Dest - { - public ICollection Children { get; set; } - } + public class Dest + { + public ICollection Children { get; set; } + } - public class DestChild {} + public class DestChild {} - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - cfg.CreateMap(); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + cfg.CreateMap(); + }); - protected override void Because_of() + protected override void Because_of() + { + var source = new OtherSource { - var source = new OtherSource + Children = new Collection { - Children = new Collection - { - new OtherChild(), - new OtherChild() - } - }; - _dest = Mapper.Map(source); - } - - [Fact] - public void Should_map_collection_items() - { - _dest.Children.Count.ShouldBe(2); - } + new OtherChild(), + new OtherChild() + } + }; + _dest = Mapper.Map(source); + } + + [Fact] + public void Should_map_collection_items() + { + _dest.Children.Count.ShouldBe(2); } } diff --git a/src/UnitTests/Bug/EmptyNullSubstituteBug.cs b/src/UnitTests/Bug/EmptyNullSubstituteBug.cs index 556b304c3e..bb96dab042 100644 --- a/src/UnitTests/Bug/EmptyNullSubstituteBug.cs +++ b/src/UnitTests/Bug/EmptyNullSubstituteBug.cs @@ -1,56 +1,55 @@ -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +using Shouldly; +using Xunit; + +public class EmptyNullSubstituteBug : NonValidatingSpecBase { - using Shouldly; - using Xunit; + private Entity _destination; - public class EmptyNullSubstituteBug : NonValidatingSpecBase + public class Model { - private Entity _destination; + public string Name { get; set; } + public int Age { get; set; } + } - public class Model - { - public string Name { get; set; } - public int Age { get; set; } - } + public class Entity + { + public string Name { get; set; } + public int Age { get; set; } + public string ClientIPAddress { get; set; } + public string NotifyEmail { get; set; } + } - public class Entity - { - public string Name { get; set; } - public int Age { get; set; } - public string ClientIPAddress { get; set; } - public string NotifyEmail { get; set; } - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .ForMember(e => e.ClientIPAddress, opts => opts.NullSubstitute("")) + .ForMember(e => e.NotifyEmail, opts => opts.NullSubstitute("")); + }); - protected override MapperConfiguration CreateConfiguration() => new(cfg => + protected override void Because_of() + { + var model = new Model { - cfg.CreateMap() - .ForMember(e => e.ClientIPAddress, opts => opts.NullSubstitute("")) - .ForMember(e => e.NotifyEmail, opts => opts.NullSubstitute("")); - }); + Name = "Eric Cartman", + Age = 12 + }; - protected override void Because_of() + _destination = new Entity { - var model = new Model - { - Name = "Eric Cartman", - Age = 12 - }; - - _destination = new Entity - { - Name = "Eric Cartman", - Age = 12, - ClientIPAddress = "192.22.2.1", - NotifyEmail = "stan@gmail.com" - }; - - _destination = Mapper.Map(model, _destination); - } - - [Fact] - public void Should_keep_existing_ip_address() - { - _destination.ClientIPAddress.ShouldBe("192.22.2.1"); - } + Name = "Eric Cartman", + Age = 12, + ClientIPAddress = "192.22.2.1", + NotifyEmail = "stan@gmail.com" + }; + + _destination = Mapper.Map(model, _destination); + } + + [Fact] + public void Should_keep_existing_ip_address() + { + _destination.ClientIPAddress.ShouldBe("192.22.2.1"); } } \ No newline at end of file diff --git a/src/UnitTests/Bug/EnumCaseSensitivityBug.cs b/src/UnitTests/Bug/EnumCaseSensitivityBug.cs index 3db4353a22..170f9fd09d 100644 --- a/src/UnitTests/Bug/EnumCaseSensitivityBug.cs +++ b/src/UnitTests/Bug/EnumCaseSensitivityBug.cs @@ -1,42 +1,41 @@ using Shouldly; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +using Xunit; + +public class EnumCaseSensitivityBug : AutoMapperSpecBase { - using Xunit; + private SecondEnum _resultSecondEnum; + private FirstEnum _resultFirstEnum; + + public enum FirstEnum + { + Dog, + Cat + } + + public enum SecondEnum + { + cat, + dog + } + + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + // not creating a map on purpose to trigger use of EnumToEnumMapper + }); + + protected override void Because_of() + { + _resultSecondEnum = Mapper.Map(FirstEnum.Cat); + _resultFirstEnum = Mapper.Map(SecondEnum.dog); + } - public class EnumCaseSensitivityBug : AutoMapperSpecBase + [Fact] + public void Should_match_on_the_name_even_if_values_match() { - private SecondEnum _resultSecondEnum; - private FirstEnum _resultFirstEnum; - - public enum FirstEnum - { - Dog, - Cat - } - - public enum SecondEnum - { - cat, - dog - } - - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - // not creating a map on purpose to trigger use of EnumToEnumMapper - }); - - protected override void Because_of() - { - _resultSecondEnum = Mapper.Map(FirstEnum.Cat); - _resultFirstEnum = Mapper.Map(SecondEnum.dog); - } - - [Fact] - public void Should_match_on_the_name_even_if_values_match() - { - _resultSecondEnum.ShouldBe(SecondEnum.cat); - _resultFirstEnum.ShouldBe(FirstEnum.Dog); - } + _resultSecondEnum.ShouldBe(SecondEnum.cat); + _resultFirstEnum.ShouldBe(FirstEnum.Dog); } } \ No newline at end of file diff --git a/src/UnitTests/Bug/EnumMatchingOnValue.cs b/src/UnitTests/Bug/EnumMatchingOnValue.cs index 2e2afa4d2a..8a3f9dff5a 100644 --- a/src/UnitTests/Bug/EnumMatchingOnValue.cs +++ b/src/UnitTests/Bug/EnumMatchingOnValue.cs @@ -1,53 +1,51 @@ using Shouldly; using Xunit; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class EnumMatchingOnValue : AutoMapperSpecBase { - public class EnumMatchingOnValue : AutoMapperSpecBase - { - private SecondClass _result; + private SecondClass _result; - public class FirstClass - { - public FirstEnum EnumValue { get; set; } - } + public class FirstClass + { + public FirstEnum EnumValue { get; set; } + } - public enum FirstEnum - { - NamedEnum = 1, - SecondNameEnum = 2 - } + public enum FirstEnum + { + NamedEnum = 1, + SecondNameEnum = 2 + } - public class SecondClass - { - public SecondEnum EnumValue { get; set; } - } + public class SecondClass + { + public SecondEnum EnumValue { get; set; } + } - public enum SecondEnum - { - DifferentNamedEnum = 1, - SecondNameEnum = 2 - } + public enum SecondEnum + { + DifferentNamedEnum = 1, + SecondNameEnum = 2 + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + }); - protected override void Because_of() - { - var source = new FirstClass - { - EnumValue = FirstEnum.NamedEnum - }; - _result = Mapper.Map(source); - } - - [Fact] - public void Should_match_on_the_name_even_if_values_match() + protected override void Because_of() + { + var source = new FirstClass { - _result.EnumValue.ShouldBe(SecondEnum.DifferentNamedEnum); - } + EnumValue = FirstEnum.NamedEnum + }; + _result = Mapper.Map(source); } + [Fact] + public void Should_match_on_the_name_even_if_values_match() + { + _result.EnumValue.ShouldBe(SecondEnum.DifferentNamedEnum); + } } \ No newline at end of file diff --git a/src/UnitTests/Bug/ExistingArrays.cs b/src/UnitTests/Bug/ExistingArrays.cs index 54df3318cb..14d9620491 100644 --- a/src/UnitTests/Bug/ExistingArrays.cs +++ b/src/UnitTests/Bug/ExistingArrays.cs @@ -3,61 +3,60 @@ using System.Linq; using Xunit; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class ExistingArrays : AutoMapperSpecBase { - public class ExistingArrays : AutoMapperSpecBase + protected override MapperConfiguration CreateConfiguration() => new(cfg => { - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - cfg.CreateMap(); - }); + cfg.CreateMap(); + cfg.CreateMap(); + }); - [Fact] - public void should_map_array_inside_object() - { - var source = new Source { Values = new[] { "1", "2" } }; - var dest = Mapper.Map(source); - } + [Fact] + public void should_map_array_inside_object() + { + var source = new Source { Values = new[] { "1", "2" } }; + var dest = Mapper.Map(source); + } - [Fact] - public void should_map_over_enumerable_empty() - { - var source = new Source { Values = new[] { "1", "2" } }; - var dest = Mapper.Map(source); - } + [Fact] + public void should_map_over_enumerable_empty() + { + var source = new Source { Values = new[] { "1", "2" } }; + var dest = Mapper.Map(source); + } - public class Source + public class Source + { + public Source() { - public Source() - { - Values = new string[0]; - } - - public string[] Values { get; set; } + Values = new string[0]; } - public class Dest - { - public Dest() - { - // remove this line will get it fixed. - Values = new string[0]; - } + public string[] Values { get; set; } + } - public string[] Values { get; set; } + public class Dest + { + public Dest() + { + // remove this line will get it fixed. + Values = new string[0]; } - public class DestWithIEnumerableInitializer - { - public DestWithIEnumerableInitializer() - { - // remove this line will get it fixed. - Values = Enumerable.Empty(); - } + public string[] Values { get; set; } + } - public IEnumerable Values { get; set; } + public class DestWithIEnumerableInitializer + { + public DestWithIEnumerableInitializer() + { + // remove this line will get it fixed. + Values = Enumerable.Empty(); } + + public IEnumerable Values { get; set; } } } \ No newline at end of file diff --git a/src/UnitTests/Bug/ForAllMembersAndDoNotUseDestinationValue.cs b/src/UnitTests/Bug/ForAllMembersAndDoNotUseDestinationValue.cs index b9a2313439..04897f3568 100644 --- a/src/UnitTests/Bug/ForAllMembersAndDoNotUseDestinationValue.cs +++ b/src/UnitTests/Bug/ForAllMembersAndDoNotUseDestinationValue.cs @@ -2,39 +2,38 @@ using Shouldly; using System; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class ForAllMembersAndResolveUsing : AutoMapperSpecBase { - public class ForAllMembersAndResolveUsing : AutoMapperSpecBase - { - private Destination _destination; + private Destination _destination; - class Source - { - public int Number { get; set; } - } - class Destination - { - public int Number { get; set; } - } + class Source + { + public int Number { get; set; } + } + class Destination + { + public int Number { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().ForAllMembers(opt => opt.MapFrom(s=>12)); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().ForAllMembers(opt => opt.MapFrom(s=>12)); + }); - protected override void Because_of() + protected override void Because_of() + { + var source = new Source { - var source = new Source - { - Number = 23 - }; - _destination = Mapper.Map(source); - } + Number = 23 + }; + _destination = Mapper.Map(source); + } - [Fact] - public void Should_work_together() - { - _destination.Number.ShouldBe(12); - } + [Fact] + public void Should_work_together() + { + _destination.Number.ShouldBe(12); } } \ No newline at end of file diff --git a/src/UnitTests/Bug/GenericCreateMapWithCircularReferences.cs b/src/UnitTests/Bug/GenericCreateMapWithCircularReferences.cs index c35fc143f0..e5c71a4899 100644 --- a/src/UnitTests/Bug/GenericCreateMapWithCircularReferences.cs +++ b/src/UnitTests/Bug/GenericCreateMapWithCircularReferences.cs @@ -2,85 +2,84 @@ using AutoMapper.Internal.Mappers; using Xunit; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class GenericCreateMapsWithCircularReference : AutoMapperSpecBase { - public class GenericCreateMapsWithCircularReference : AutoMapperSpecBase + protected override MapperConfiguration CreateConfiguration() => new(cfg => { - protected override MapperConfiguration CreateConfiguration() => new(cfg => + cfg.CreateMap(typeof(User<>), typeof(UserPoco<>)); + cfg.CreateMap(typeof(Role<>), typeof(RolePoco<>)); + cfg.CreateMap(typeof(UsersInRole<>), typeof(UsersInRolePoco<>)); + cfg.ForAllMaps((t, c) => { - cfg.CreateMap(typeof(User<>), typeof(UserPoco<>)); - cfg.CreateMap(typeof(Role<>), typeof(RolePoco<>)); - cfg.CreateMap(typeof(UsersInRole<>), typeof(UsersInRolePoco<>)); - cfg.ForAllMaps((t, c) => - { - c.PreserveReferences(); - }); + c.PreserveReferences(); }); + }); - [Fact] - public void Main() + [Fact] + public void Main() + { + var role = new Role(); + var user = new User() { - var role = new Role(); - var user = new User() - { - UsersInRoles = new List>() - }; - user.UsersInRoles.Add(new UsersInRole() - { - Role = role, - User = user - }); - - var result = Mapper.Map>(user); - } - - public partial class Role + UsersInRoles = new List>() + }; + user.UsersInRoles.Add(new UsersInRole() { - public Role() - { - this.UsersInRoles = new List>(); - } - public virtual IList> UsersInRoles { get; set; } - } + Role = role, + User = user + }); - public partial class RolePoco - { - public RolePoco() - { - this.UsersInRoles = new List>(); - } - public virtual IList> UsersInRoles { get; set; } - } + var result = Mapper.Map>(user); + } - public partial class User + public partial class Role + { + public Role() { - public User() - { - this.UsersInRoles = new List>(); - } - public virtual IList> UsersInRoles { get; set; } + this.UsersInRoles = new List>(); } + public virtual IList> UsersInRoles { get; set; } + } - public partial class UserPoco + public partial class RolePoco + { + public RolePoco() { - public UserPoco() - { - this.UsersInRoles = new List>(); - } - public virtual IList> UsersInRoles { get; set; } + this.UsersInRoles = new List>(); } + public virtual IList> UsersInRoles { get; set; } + } - public partial class UsersInRole + public partial class User + { + public User() { - public virtual Role Role { get; set; } - public virtual User User { get; set; } + this.UsersInRoles = new List>(); } + public virtual IList> UsersInRoles { get; set; } + } - public partial class UsersInRolePoco + public partial class UserPoco + { + public UserPoco() { - public virtual RolePoco Role { get; set; } - public virtual UserPoco User { get; set; } + this.UsersInRoles = new List>(); } + public virtual IList> UsersInRoles { get; set; } + } + public partial class UsersInRole + { + public virtual Role Role { get; set; } + public virtual User User { get; set; } } + + public partial class UsersInRolePoco + { + public virtual RolePoco Role { get; set; } + public virtual UserPoco User { get; set; } + } + } \ No newline at end of file diff --git a/src/UnitTests/Bug/GenericTypeConverter.cs b/src/UnitTests/Bug/GenericTypeConverter.cs index d56efc91dd..2162f389a0 100644 --- a/src/UnitTests/Bug/GenericTypeConverter.cs +++ b/src/UnitTests/Bug/GenericTypeConverter.cs @@ -5,164 +5,163 @@ using Shouldly; using Xunit; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class GenericTypeConverterWithTwoArguments : AutoMapperSpecBase { - public class GenericTypeConverterWithTwoArguments : AutoMapperSpecBase + List _destination; + + protected override MapperConfiguration CreateConfiguration() => new(c=>c.CreateMap(typeof(List<>), typeof(List<>)).ConvertUsing(typeof(Converter<,>))); + + protected override void Because_of() { - List _destination; + _destination = Mapper.Map, List>(Enumerable.Range(1, 10).ToList()); + } - protected override MapperConfiguration CreateConfiguration() => new(c=>c.CreateMap(typeof(List<>), typeof(List<>)).ConvertUsing(typeof(Converter<,>))); + [Fact] + public void Should_work() + { + _destination.ShouldBe(Converter.Result); + } - protected override void Because_of() - { - _destination = Mapper.Map, List>(Enumerable.Range(1, 10).ToList()); - } + public class Converter : ITypeConverter, List> + { + public static readonly List Result = new List(); - [Fact] - public void Should_work() + public List Convert(List source, List destination, ResolutionContext context) { - _destination.ShouldBe(Converter.Result); + return Result; } + } +} - public class Converter : ITypeConverter, List> - { - public static readonly List Result = new List(); +public class GenericTypeConverter : AutoMapperSpecBase +{ + Destination _destination; + OtherDestination _otherDestination; + int _openGenericToNonGenericDestination; + Destination _nonGenericToOpenGenericDestination; + OtherDestination _closedGenericToOpenGenericDestination; + Destination _openGenericToClosedGenericDestination; + + public class Source + { + public T Value { get; set; } + } - public List Convert(List source, List destination, ResolutionContext context) - { - return Result; - } - } + public class Destination + { + public T Value { get; set; } } - public class GenericTypeConverter : AutoMapperSpecBase + public class OtherSource { - Destination _destination; - OtherDestination _otherDestination; - int _openGenericToNonGenericDestination; - Destination _nonGenericToOpenGenericDestination; - OtherDestination _closedGenericToOpenGenericDestination; - Destination _openGenericToClosedGenericDestination; - - public class Source - { - public T Value { get; set; } - } + public T Value { get; set; } + } - public class Destination - { - public T Value { get; set; } - } + public class OtherDestination + { + public T Value { get; set; } + } - public class OtherSource - { - public T Value { get; set; } - } + public class Converter : + ITypeConverter, Destination>, + ITypeConverter, OtherDestination>, + ITypeConverter, int>, + ITypeConverter>, + ITypeConverter, Destination>, + ITypeConverter, OtherDestination> + { + public static Destination SomeDestination = new Destination(); + public static OtherDestination SomeOtherDestination = new OtherDestination(); + public static int NongenericDestination = default(int); + public static OtherDestination OpenDestinationViaClosedSource = new OtherDestination(); + public static Destination ClosedDestinationViaOpenSource = new Destination(); - public class OtherDestination + public Destination Convert(Source source, Destination dest, ResolutionContext context) { - public T Value { get; set; } + return SomeDestination; } - public class Converter : - ITypeConverter, Destination>, - ITypeConverter, OtherDestination>, - ITypeConverter, int>, - ITypeConverter>, - ITypeConverter, Destination>, - ITypeConverter, OtherDestination> + OtherDestination ITypeConverter, OtherDestination>.Convert(OtherSource source, OtherDestination dest, ResolutionContext context) { - public static Destination SomeDestination = new Destination(); - public static OtherDestination SomeOtherDestination = new OtherDestination(); - public static int NongenericDestination = default(int); - public static OtherDestination OpenDestinationViaClosedSource = new OtherDestination(); - public static Destination ClosedDestinationViaOpenSource = new Destination(); - - public Destination Convert(Source source, Destination dest, ResolutionContext context) - { - return SomeDestination; - } - - OtherDestination ITypeConverter, OtherDestination>.Convert(OtherSource source, OtherDestination dest, ResolutionContext context) - { - return SomeOtherDestination; - } - - int ITypeConverter, int>.Convert(Source source, int dest, ResolutionContext context) - { - return NongenericDestination; - } - - Destination ITypeConverter>.Convert(int source, Destination dest, ResolutionContext context) - { - return SomeDestination; - } - - Destination ITypeConverter, Destination>.Convert(OtherSource source, Destination dest, ResolutionContext context) - { - return ClosedDestinationViaOpenSource; - } - - OtherDestination ITypeConverter, OtherDestination>.Convert(Source source, OtherDestination dest, ResolutionContext context) - { - return OpenDestinationViaClosedSource; - } + return SomeOtherDestination; } - public class Converter : ITypeConverter> - + int ITypeConverter, int>.Convert(Source source, int dest, ResolutionContext context) { - public static IReadOnlyDictionary ReadOnlyDictionaryDestination = new Dictionary(); - - public IReadOnlyDictionary Convert(Hashtable source, IReadOnlyDictionary dest, ResolutionContext context) - { - return ReadOnlyDictionaryDestination; - } + return NongenericDestination; } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(typeof (Source<>), typeof (Destination<>)).ConvertUsing(typeof (Converter<>)); - cfg.CreateMap(typeof (OtherSource<>), typeof (OtherDestination<>)).ConvertUsing(typeof (Converter<>)); - cfg.CreateMap(typeof (Source<>), typeof (int)).ConvertUsing(typeof (Converter<>)); - cfg.CreateMap(typeof (int), typeof (Destination<>)).ConvertUsing(typeof (Converter<>)); - cfg.CreateMap(typeof (OtherSource<>), typeof (Destination)).ConvertUsing(typeof (Converter<>)); - cfg.CreateMap(typeof(Source), typeof(OtherDestination<>)).ConvertUsing(typeof(Converter<>)); - cfg.CreateMap(typeof (Hashtable), typeof (IReadOnlyDictionary<,>)).ConvertUsing(typeof (Converter<,>)); - }); - - protected override void Because_of() + Destination ITypeConverter>.Convert(int source, Destination dest, ResolutionContext context) { - _destination = Mapper.Map>(new Source()); - _otherDestination = Mapper.Map>(new OtherSource()); - _openGenericToNonGenericDestination = Mapper.Map(new Source()); - _nonGenericToOpenGenericDestination = Mapper.Map>(default(int)); - _openGenericToClosedGenericDestination = Mapper.Map>(new OtherSource()); - _closedGenericToOpenGenericDestination = Mapper.Map>(new Source()); + return SomeDestination; } - [Fact] - public void Should_use_generic_converter_with_correct_interface() + Destination ITypeConverter, Destination>.Convert(OtherSource source, Destination dest, ResolutionContext context) { - _destination.ShouldBeSameAs(Converter.SomeDestination); - _otherDestination.ShouldBeSameAs(Converter.SomeOtherDestination); - _openGenericToNonGenericDestination.ShouldBe(Converter.NongenericDestination); - _nonGenericToOpenGenericDestination.ShouldBeSameAs(Converter.SomeDestination); - _openGenericToClosedGenericDestination.ShouldBe(Converter.ClosedDestinationViaOpenSource); - _closedGenericToOpenGenericDestination.ShouldBe(Converter.OpenDestinationViaClosedSource); + return ClosedDestinationViaOpenSource; } - [Fact] - public void Should_use_generic_converter_when_covered_by_object_map() + OtherDestination ITypeConverter, OtherDestination>.Convert(Source source, OtherDestination dest, ResolutionContext context) { - Mapper.Map>(new Hashtable()).ShouldBeSameAs(Converter.ReadOnlyDictionaryDestination); + return OpenDestinationViaClosedSource; } + } + + public class Converter : ITypeConverter> + + { + public static IReadOnlyDictionary ReadOnlyDictionaryDestination = new Dictionary(); - [Fact] - public void Should_use_generic_converter_with_correct_closed_type() + public IReadOnlyDictionary Convert(Hashtable source, IReadOnlyDictionary dest, ResolutionContext context) { - Mapper.Map>(new Source()).ShouldBeSameAs(Converter.SomeDestination); - Mapper.Map>(new Source()).ShouldBeSameAs(Converter.SomeDestination); + return ReadOnlyDictionaryDestination; } } + + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(typeof (Source<>), typeof (Destination<>)).ConvertUsing(typeof (Converter<>)); + cfg.CreateMap(typeof (OtherSource<>), typeof (OtherDestination<>)).ConvertUsing(typeof (Converter<>)); + cfg.CreateMap(typeof (Source<>), typeof (int)).ConvertUsing(typeof (Converter<>)); + cfg.CreateMap(typeof (int), typeof (Destination<>)).ConvertUsing(typeof (Converter<>)); + cfg.CreateMap(typeof (OtherSource<>), typeof (Destination)).ConvertUsing(typeof (Converter<>)); + cfg.CreateMap(typeof(Source), typeof(OtherDestination<>)).ConvertUsing(typeof(Converter<>)); + cfg.CreateMap(typeof (Hashtable), typeof (IReadOnlyDictionary<,>)).ConvertUsing(typeof (Converter<,>)); + }); + + protected override void Because_of() + { + _destination = Mapper.Map>(new Source()); + _otherDestination = Mapper.Map>(new OtherSource()); + _openGenericToNonGenericDestination = Mapper.Map(new Source()); + _nonGenericToOpenGenericDestination = Mapper.Map>(default(int)); + _openGenericToClosedGenericDestination = Mapper.Map>(new OtherSource()); + _closedGenericToOpenGenericDestination = Mapper.Map>(new Source()); + } + + [Fact] + public void Should_use_generic_converter_with_correct_interface() + { + _destination.ShouldBeSameAs(Converter.SomeDestination); + _otherDestination.ShouldBeSameAs(Converter.SomeOtherDestination); + _openGenericToNonGenericDestination.ShouldBe(Converter.NongenericDestination); + _nonGenericToOpenGenericDestination.ShouldBeSameAs(Converter.SomeDestination); + _openGenericToClosedGenericDestination.ShouldBe(Converter.ClosedDestinationViaOpenSource); + _closedGenericToOpenGenericDestination.ShouldBe(Converter.OpenDestinationViaClosedSource); + } + + [Fact] + public void Should_use_generic_converter_when_covered_by_object_map() + { + Mapper.Map>(new Hashtable()).ShouldBeSameAs(Converter.ReadOnlyDictionaryDestination); + } + + [Fact] + public void Should_use_generic_converter_with_correct_closed_type() + { + Mapper.Map>(new Source()).ShouldBeSameAs(Converter.SomeDestination); + Mapper.Map>(new Source()).ShouldBeSameAs(Converter.SomeDestination); + } } diff --git a/src/UnitTests/Bug/GuidTryExpression.cs b/src/UnitTests/Bug/GuidTryExpression.cs index e5909de7c3..a9408e4454 100644 --- a/src/UnitTests/Bug/GuidTryExpression.cs +++ b/src/UnitTests/Bug/GuidTryExpression.cs @@ -2,40 +2,39 @@ using Shouldly; using System; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class GuidTryExpression : AutoMapperSpecBase { - public class GuidTryExpression : AutoMapperSpecBase - { - private Destination _destination; - private Guid _value = Guid.NewGuid(); + private Destination _destination; + private Guid _value = Guid.NewGuid(); - class Source - { - public Guid Value { get; set; } - } - class Destination - { - public string Value { get; set; } - } + class Source + { + public Guid Value { get; set; } + } + class Destination + { + public string Value { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().ForMember(d => d.Value, o => o.MapFrom(s => s.Value)); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().ForMember(d => d.Value, o => o.MapFrom(s => s.Value)); + }); - protected override void Because_of() + protected override void Because_of() + { + var source = new Source { - var source = new Source - { - Value = _value - }; - _destination = Mapper.Map(source); - } + Value = _value + }; + _destination = Mapper.Map(source); + } - [Fact] - public void Should_map_int_to_nullable_decimal() - { - _destination.Value.ShouldBe(_value.ToString()); - } + [Fact] + public void Should_map_int_to_nullable_decimal() + { + _destination.Value.ShouldBe(_value.ToString()); } } \ No newline at end of file diff --git a/src/UnitTests/Bug/IgnoreAll.cs b/src/UnitTests/Bug/IgnoreAll.cs index d55818e784..ea0d1ba266 100644 --- a/src/UnitTests/Bug/IgnoreAll.cs +++ b/src/UnitTests/Bug/IgnoreAll.cs @@ -1,74 +1,72 @@ using Xunit; -namespace AutoMapper.UnitTests.Bug -{ - using Shouldly; +namespace AutoMapper.UnitTests.Bug; - public class When_configuring_all_members_and_some_do_not_match - { - public class ModelObjectNotMatching - { - public string Foo_notfound { get; set; } - public string Bar_notfound; - } +using Shouldly; - public class ModelDto - { - public string Foo { get; set; } - public string Bar; - } +public class When_configuring_all_members_and_some_do_not_match +{ + public class ModelObjectNotMatching + { + public string Foo_notfound { get; set; } + public string Bar_notfound; + } - [Fact] - public void Should_still_apply_configuration_to_missing_members() - { - var config = new MapperConfiguration(cfg => cfg.CreateMap() - .ForAllMembers(opt => opt.Ignore())); - config.AssertConfigurationIsValid(); - } + public class ModelDto + { + public string Foo { get; set; } + public string Bar; } - public class When_configuring_all_non_source_value_null_members : NonValidatingSpecBase + [Fact] + public void Should_still_apply_configuration_to_missing_members() { - private Dest _destination; + var config = new MapperConfiguration(cfg => cfg.CreateMap() + .ForAllMembers(opt => opt.Ignore())); + config.AssertConfigurationIsValid(); + } +} - public class Source - { - public string Value1 { get; set; } - public int? Value2 { get; set; } - } +public class When_configuring_all_non_source_value_null_members : NonValidatingSpecBase +{ + private Dest _destination; - public class Dest - { - public string Value1 { get; set; } - public int? Value2 { get; set; } - public string Unmapped { get; set; } - } + public class Source + { + public string Value1 { get; set; } + public int? Value2 { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ForAllMembers(opt => opt.Condition((src, dest, srcVal, destVal, c) => srcVal != null)); - }); + public class Dest + { + public string Value1 { get; set; } + public int? Value2 { get; set; } + public string Unmapped { get; set; } + } - protected override void Because_of() - { - var source = new Source(); - _destination = new Dest - { - Value1 = "Foo", - Value2 = 10, - Unmapped = "Asdf" - }; - Mapper.Map(source, _destination); - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .ForAllMembers(opt => opt.Condition((src, dest, srcVal, destVal, c) => srcVal != null)); + }); - [Fact] - public void Should_only_apply_source_value_when_not_null() + protected override void Because_of() + { + var source = new Source(); + _destination = new Dest { - _destination.Value1.ShouldNotBeNull(); - _destination.Value2.ShouldNotBe(null); - _destination.Unmapped.ShouldNotBeNull(); - } + Value1 = "Foo", + Value2 = 10, + Unmapped = "Asdf" + }; + Mapper.Map(source, _destination); } + [Fact] + public void Should_only_apply_source_value_when_not_null() + { + _destination.Value1.ShouldNotBeNull(); + _destination.Value2.ShouldNotBe(null); + _destination.Unmapped.ShouldNotBeNull(); + } } \ No newline at end of file diff --git a/src/UnitTests/Bug/IncludeBaseInheritance.cs b/src/UnitTests/Bug/IncludeBaseInheritance.cs index a36b8251d6..a30bd56932 100644 --- a/src/UnitTests/Bug/IncludeBaseInheritance.cs +++ b/src/UnitTests/Bug/IncludeBaseInheritance.cs @@ -2,73 +2,72 @@ using Shouldly; using System; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class IncludeBaseInheritance : AutoMapperSpecBase { - public class IncludeBaseInheritance : AutoMapperSpecBase - { - DestinationLevel2 _destination; + DestinationLevel2 _destination; - public class SourceLevel0 - { - public string SPropertyLevel0 { get; set; } - } + public class SourceLevel0 + { + public string SPropertyLevel0 { get; set; } + } - public class SourceLevel1 : SourceLevel0 - { - public string SPropertyLevel1 { get; set; } - } + public class SourceLevel1 : SourceLevel0 + { + public string SPropertyLevel1 { get; set; } + } - public class SourceLevel2 : SourceLevel1 - { - public string DPropertyLevel0 { get; set; } - public string SPropertyLevel2 { get; set; } - } + public class SourceLevel2 : SourceLevel1 + { + public string DPropertyLevel0 { get; set; } + public string SPropertyLevel2 { get; set; } + } - public class DestinationLevel0 - { - public string DPropertyLevel0 { get; set; } - } + public class DestinationLevel0 + { + public string DPropertyLevel0 { get; set; } + } - public class DestinationLevel1 : DestinationLevel0 - { - public string DPropertyLevel1 { get; set; } - } + public class DestinationLevel1 : DestinationLevel0 + { + public string DPropertyLevel1 { get; set; } + } - public class DestinationLevel2 : DestinationLevel1 - { - public string DPropertyLevel2 { get; set; } - } + public class DestinationLevel2 : DestinationLevel1 + { + public string DPropertyLevel2 { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ForMember(dest => dest.DPropertyLevel0, o => o.MapFrom(src => src.SPropertyLevel0)); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .ForMember(dest => dest.DPropertyLevel0, o => o.MapFrom(src => src.SPropertyLevel0)); - cfg.CreateMap() - .IncludeBase() - .ForMember(dest => dest.DPropertyLevel1, o => o.MapFrom(src => src.SPropertyLevel1)); + cfg.CreateMap() + .IncludeBase() + .ForMember(dest => dest.DPropertyLevel1, o => o.MapFrom(src => src.SPropertyLevel1)); - cfg.CreateMap() - .IncludeBase() - .ForMember(dest => dest.DPropertyLevel2, o => o.MapFrom(src => src.SPropertyLevel2)); - }); + cfg.CreateMap() + .IncludeBase() + .ForMember(dest => dest.DPropertyLevel2, o => o.MapFrom(src => src.SPropertyLevel2)); + }); - protected override void Because_of() + protected override void Because_of() + { + var source = new SourceLevel2 { - var source = new SourceLevel2 - { - SPropertyLevel0 = "SPropertyLevel0", - SPropertyLevel1 = "SPropertyLevel1", - SPropertyLevel2 = "SPropertyLevel2", - DPropertyLevel0 = "DPropertyLevel0", - }; - _destination = Mapper.Map(source); - } + SPropertyLevel0 = "SPropertyLevel0", + SPropertyLevel1 = "SPropertyLevel1", + SPropertyLevel2 = "SPropertyLevel2", + DPropertyLevel0 = "DPropertyLevel0", + }; + _destination = Mapper.Map(source); + } - [Fact] - public void Should_inherit_resolvers() - { - _destination.DPropertyLevel0.ShouldBe("SPropertyLevel0"); - } + [Fact] + public void Should_inherit_resolvers() + { + _destination.DPropertyLevel0.ShouldBe("SPropertyLevel0"); } } \ No newline at end of file diff --git a/src/UnitTests/Bug/IncludeInheritance.cs b/src/UnitTests/Bug/IncludeInheritance.cs index 216b093dad..0cd02c8774 100644 --- a/src/UnitTests/Bug/IncludeInheritance.cs +++ b/src/UnitTests/Bug/IncludeInheritance.cs @@ -2,73 +2,72 @@ using Shouldly; using System; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class IncludeInheritance : AutoMapperSpecBase { - public class IncludeInheritance : AutoMapperSpecBase - { - DestinationLevel2 _destination; + DestinationLevel2 _destination; - public class SourceLevel0 - { - public string SPropertyLevel0 { get; set; } - } + public class SourceLevel0 + { + public string SPropertyLevel0 { get; set; } + } - public class SourceLevel1 : SourceLevel0 - { - public string SPropertyLevel1 { get; set; } - } + public class SourceLevel1 : SourceLevel0 + { + public string SPropertyLevel1 { get; set; } + } - public class SourceLevel2 : SourceLevel1 - { - public string DPropertyLevel0 { get; set; } - public string SPropertyLevel2 { get; set; } - } + public class SourceLevel2 : SourceLevel1 + { + public string DPropertyLevel0 { get; set; } + public string SPropertyLevel2 { get; set; } + } - public class DestinationLevel0 - { - public string DPropertyLevel0 { get; set; } - } + public class DestinationLevel0 + { + public string DPropertyLevel0 { get; set; } + } - public class DestinationLevel1 : DestinationLevel0 - { - public string DPropertyLevel1 { get; set; } - } + public class DestinationLevel1 : DestinationLevel0 + { + public string DPropertyLevel1 { get; set; } + } - public class DestinationLevel2 : DestinationLevel1 - { - public string DPropertyLevel2 { get; set; } - } + public class DestinationLevel2 : DestinationLevel1 + { + public string DPropertyLevel2 { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .Include() - .ForMember(dest => dest.DPropertyLevel0, o => o.MapFrom(src => src.SPropertyLevel0)); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .Include() + .ForMember(dest => dest.DPropertyLevel0, o => o.MapFrom(src => src.SPropertyLevel0)); - cfg.CreateMap() - .Include() - .ForMember(dest => dest.DPropertyLevel1, o => o.MapFrom(src => src.SPropertyLevel1)); + cfg.CreateMap() + .Include() + .ForMember(dest => dest.DPropertyLevel1, o => o.MapFrom(src => src.SPropertyLevel1)); - cfg.CreateMap() - .ForMember(dest => dest.DPropertyLevel2, o => o.MapFrom(src => src.SPropertyLevel2)); - }); + cfg.CreateMap() + .ForMember(dest => dest.DPropertyLevel2, o => o.MapFrom(src => src.SPropertyLevel2)); + }); - protected override void Because_of() + protected override void Because_of() + { + var source = new SourceLevel2 { - var source = new SourceLevel2 - { - SPropertyLevel0 = "SPropertyLevel0", - SPropertyLevel1 = "SPropertyLevel1", - SPropertyLevel2 = "SPropertyLevel2", - DPropertyLevel0 = "DPropertyLevel0", - }; - _destination = Mapper.Map(source); - } + SPropertyLevel0 = "SPropertyLevel0", + SPropertyLevel1 = "SPropertyLevel1", + SPropertyLevel2 = "SPropertyLevel2", + DPropertyLevel0 = "DPropertyLevel0", + }; + _destination = Mapper.Map(source); + } - [Fact] - public void Should_inherit_resolvers() - { - _destination.DPropertyLevel0.ShouldBe("SPropertyLevel0"); - } + [Fact] + public void Should_inherit_resolvers() + { + _destination.DPropertyLevel0.ShouldBe("SPropertyLevel0"); } } \ No newline at end of file diff --git a/src/UnitTests/Bug/InitializeNRE.cs b/src/UnitTests/Bug/InitializeNRE.cs index 0c4fec30f9..524d286d32 100644 --- a/src/UnitTests/Bug/InitializeNRE.cs +++ b/src/UnitTests/Bug/InitializeNRE.cs @@ -3,66 +3,65 @@ using System; using System.Collections.Generic; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class InitializeNRE2 : AutoMapperSpecBase { - public class InitializeNRE2 : AutoMapperSpecBase + public interface IRes : IValueResolver { - public interface IRes : IValueResolver - { - } - - public class Res : IRes - { - public int Resolve(Source source, Destination destination, int destMember, ResolutionContext context) - { - return 1000; - } - } - - public class Source - { - } + } - public class Destination + public class Res : IRes + { + public int Resolve(Source source, Destination destination, int destMember, ResolutionContext context) { - public int Value { get; set; } + return 1000; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.ConstructServicesUsing(t => new Res()); - cfg.CreateMap().ForMember(d => d.Value, o => o.MapFrom()); - }); - [Fact] - public void Validate() => AssertConfigurationIsValid(); + public class Source + { } + public class Destination + { + public int Value { get; set; } + } - public class InitializeNRE : AutoMapperSpecBase + protected override MapperConfiguration CreateConfiguration() => new(cfg => { - public class TestEntity - { - public string SomeData { get; set; } + cfg.ConstructServicesUsing(t => new Res()); + cfg.CreateMap().ForMember(d => d.Value, o => o.MapFrom()); + }); + [Fact] + public void Validate() => AssertConfigurationIsValid(); +} - public int SomeCount { get; set; } - public ICollection Tags { get; set; } - } +public class InitializeNRE : AutoMapperSpecBase +{ + public class TestEntity + { + public string SomeData { get; set; } - public class TestViewModel - { - public string SomeData { get; set; } + public int SomeCount { get; set; } - public int SomeCount { get; set; } + public ICollection Tags { get; set; } + } - public string Tags { get; set; } - } + public class TestViewModel + { + public string SomeData { get; set; } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - }); - [Fact] - public void Validate() => AssertConfigurationIsValid(); + public int SomeCount { get; set; } + + public string Tags { get; set; } } + + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + }); + [Fact] + public void Validate() => AssertConfigurationIsValid(); } \ No newline at end of file diff --git a/src/UnitTests/Bug/IntToNullableDecimal.cs b/src/UnitTests/Bug/IntToNullableDecimal.cs index 4739fed3ec..d0f673df8e 100644 --- a/src/UnitTests/Bug/IntToNullableDecimal.cs +++ b/src/UnitTests/Bug/IntToNullableDecimal.cs @@ -2,39 +2,38 @@ using Shouldly; using System; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class IntToNullableDecimal : AutoMapperSpecBase { - public class IntToNullableDecimal : AutoMapperSpecBase - { - private Destination _destination; + private Destination _destination; - class Source - { - public int Number { get; set; } - } - class Destination - { - public decimal? Number { get; set; } - } + class Source + { + public int Number { get; set; } + } + class Destination + { + public decimal? Number { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + }); - protected override void Because_of() + protected override void Because_of() + { + var source = new Source { - var source = new Source - { - Number = 23 - }; - _destination = Mapper.Map(source); - } + Number = 23 + }; + _destination = Mapper.Map(source); + } - [Fact] - public void Should_map_int_to_nullable_decimal() - { - _destination.Number.ShouldBe(23); - } + [Fact] + public void Should_map_int_to_nullable_decimal() + { + _destination.Number.ShouldBe(23); } } \ No newline at end of file diff --git a/src/UnitTests/Bug/InterfaceSelfMappingBug.cs b/src/UnitTests/Bug/InterfaceSelfMappingBug.cs index 0b95848b26..c86733010d 100644 --- a/src/UnitTests/Bug/InterfaceSelfMappingBug.cs +++ b/src/UnitTests/Bug/InterfaceSelfMappingBug.cs @@ -1,47 +1,46 @@ using Xunit; using Shouldly; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class InterfaceSelfMappingBug { - public class InterfaceSelfMappingBug + public interface IFoo { - public interface IFoo - { - int Value { get; set; } - } + int Value { get; set; } + } - public class Bar : IFoo - { - public int Value { get; set; } - } + public class Bar : IFoo + { + public int Value { get; set; } + } - public class Baz : IFoo + public class Baz : IFoo + { + public int Value { get; set; } + } + + [Fact] + public void Example() + { + var config = new MapperConfiguration(cfg => { - public int Value { get; set; } - } + cfg.AllowNullCollections = true; + cfg.CreateMap(); + }); + config.AssertConfigurationIsValid(); - [Fact] - public void Example() + IFoo bar = new Bar { - var config = new MapperConfiguration(cfg => - { - cfg.AllowNullCollections = true; - cfg.CreateMap(); - }); - config.AssertConfigurationIsValid(); - - IFoo bar = new Bar - { - Value = 5 - }; - IFoo baz = new Baz - { - Value = 10 - }; - - config.CreateMapper().Map(bar, baz); - - baz.Value.ShouldBe(5); - } + Value = 5 + }; + IFoo baz = new Baz + { + Value = 10 + }; + + config.CreateMapper().Map(bar, baz); + + baz.Value.ShouldBe(5); } } \ No newline at end of file diff --git a/src/UnitTests/Bug/InternalProperties.cs b/src/UnitTests/Bug/InternalProperties.cs index f221da0f38..728bd89457 100644 --- a/src/UnitTests/Bug/InternalProperties.cs +++ b/src/UnitTests/Bug/InternalProperties.cs @@ -2,37 +2,36 @@ using Shouldly; using System; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class InternalProperties : AutoMapperSpecBase { - public class InternalProperties : AutoMapperSpecBase - { - public int SomeValue = 2354; - private Destination _destination; + public int SomeValue = 2354; + private Destination _destination; - class Source - { - internal int Number { get; set; } - } - class Destination - { - internal int Number { get; set; } - } + class Source + { + internal int Number { get; set; } + } + class Destination + { + internal int Number { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.ShouldMapProperty = p => true; - cfg.CreateMap(); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.ShouldMapProperty = p => true; + cfg.CreateMap(); + }); - protected override void Because_of() - { - _destination = Mapper.Map(new Source { Number = SomeValue }); - } + protected override void Because_of() + { + _destination = Mapper.Map(new Source { Number = SomeValue }); + } - [Fact] - public void Should_map_internal_property() - { - _destination.Number.ShouldBe(SomeValue); - } + [Fact] + public void Should_map_internal_property() + { + _destination.Number.ShouldBe(SomeValue); } } \ No newline at end of file diff --git a/src/UnitTests/Bug/JsonNet.cs b/src/UnitTests/Bug/JsonNet.cs index 2c0e2707d0..c5d1511891 100644 --- a/src/UnitTests/Bug/JsonNet.cs +++ b/src/UnitTests/Bug/JsonNet.cs @@ -5,192 +5,191 @@ using System.Collections; using System.Collections.Generic; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +using StringKeyValuePair = KeyValuePair; + +public class JsonNetDictionary : AutoMapperSpecBase { - using StringKeyValuePair = KeyValuePair; + private Destination _destination; - public class JsonNetDictionary : AutoMapperSpecBase + class JObject : Dictionary, IEnumerable, IEnumerable> { - private Destination _destination; - - class JObject : Dictionary, IEnumerable, IEnumerable> + public JObject(string json) : base( + (from pair in json.Split('&') + let items = pair.Split(',') + select new StringKeyValuePair(items[0], items[1])) + .ToDictionary(kvp => kvp.Key, kvp => kvp.Value)) { - public JObject(string json) : base( - (from pair in json.Split('&') - let items = pair.Split(',') - select new StringKeyValuePair(items[0], items[1])) - .ToDictionary(kvp => kvp.Key, kvp => kvp.Value)) - { - } } + } - class Source - { - public string JsonString { get; set; } - } - class Destination - { - public dynamic Json { get; set; } - } + class Source + { + public string JsonString { get; set; } + } + class Destination + { + public dynamic Json { get; set; } + } + + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .ForMember(d => d.Json, o => o.MapFrom(s => new JObject(s.JsonString))); + }); - protected override MapperConfiguration CreateConfiguration() => new(cfg => + protected override void Because_of() + { + var source = new Source { - cfg.CreateMap() - .ForMember(d => d.Json, o => o.MapFrom(s => new JObject(s.JsonString))); - }); + JsonString = "1,one&2,two&3,three" + }; + _destination = Mapper.Map(source); + } - protected override void Because_of() + [Fact] + public void Should_map_dictionary_with_non_KeyValuePair_enumerable() + { + var json = (JObject)_destination.Json; + json.Count.ShouldBe(3); + json["1"].ShouldBe("one"); + json["2"].ShouldBe("two"); + json["3"].ShouldBe("three"); + } +} + +public class JObjectField : AutoMapperSpecBase +{ + class JContainer : IEnumerable + { + IEnumerator IEnumerable.GetEnumerator() { - var source = new Source - { - JsonString = "1,one&2,two&3,three" - }; - _destination = Mapper.Map(source); + return ((IEnumerable)this).GetEnumerator(); } - [Fact] - public void Should_map_dictionary_with_non_KeyValuePair_enumerable() + IEnumerator IEnumerable.GetEnumerator() { - var json = (JObject)_destination.Json; - json.Count.ShouldBe(3); - json["1"].ShouldBe("one"); - json["2"].ShouldBe("two"); - json["3"].ShouldBe("three"); + return (IEnumerator)new[] { DBNull.Value }.GetEnumerator(); } } - public class JObjectField : AutoMapperSpecBase + class JObject : JContainer, IDictionary { - class JContainer : IEnumerable + public JObject() { - IEnumerator IEnumerable.GetEnumerator() - { - return ((IEnumerable)this).GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return (IEnumerator)new[] { DBNull.Value }.GetEnumerator(); - } } - class JObject : JContainer, IDictionary + public string this[string key] { - public JObject() - { - } - - public string this[string key] - { - get - { - throw new NotImplementedException(); - } - - set - { - throw new NotImplementedException(); - } - } - - public int Count - { - get - { - throw new NotImplementedException(); - } - } - - public bool IsReadOnly - { - get - { - throw new NotImplementedException(); - } - } - - public ICollection Keys - { - get - { - throw new NotImplementedException(); - } - } - - public ICollection Values - { - get - { - throw new NotImplementedException(); - } - } - - public void Add(StringKeyValuePair item) + get { throw new NotImplementedException(); } - public void Add(string key, string value) + set { throw new NotImplementedException(); } + } - public void Clear() + public int Count + { + get { throw new NotImplementedException(); } + } - public bool Contains(StringKeyValuePair item) + public bool IsReadOnly + { + get { throw new NotImplementedException(); } + } - public bool ContainsKey(string key) + public ICollection Keys + { + get { throw new NotImplementedException(); } + } - public void CopyTo(StringKeyValuePair[] array, int arrayIndex) + public ICollection Values + { + get { throw new NotImplementedException(); } + } - public IEnumerator GetEnumerator() - { - throw new NotImplementedException(); - } + public void Add(StringKeyValuePair item) + { + throw new NotImplementedException(); + } - public bool Remove(StringKeyValuePair item) - { - throw new NotImplementedException(); - } + public void Add(string key, string value) + { + throw new NotImplementedException(); + } - public bool Remove(string key) - { - throw new NotImplementedException(); - } + public void Clear() + { + throw new NotImplementedException(); + } - public bool TryGetValue(string key, out string value) - { - throw new NotImplementedException(); - } + public bool Contains(StringKeyValuePair item) + { + throw new NotImplementedException(); + } + + public bool ContainsKey(string key) + { + throw new NotImplementedException(); + } + + public void CopyTo(StringKeyValuePair[] array, int arrayIndex) + { + throw new NotImplementedException(); } - class Source + public IEnumerator GetEnumerator() { - public JObject Json { get; set; } + throw new NotImplementedException(); } - class Destination + public bool Remove(StringKeyValuePair item) { - public JObject Json { get; set; } + throw new NotImplementedException(); } - protected override MapperConfiguration CreateConfiguration() => new(cfg => + public bool Remove(string key) { - cfg.CreateMap(); - }); - [Fact] - public void Validate() => AssertConfigurationIsValid(); + throw new NotImplementedException(); + } + + public bool TryGetValue(string key, out string value) + { + throw new NotImplementedException(); + } + } + + class Source + { + public JObject Json { get; set; } } + + class Destination + { + public JObject Json { get; set; } + } + + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + }); + [Fact] + public void Validate() => AssertConfigurationIsValid(); } \ No newline at end of file diff --git a/src/UnitTests/Bug/LazyCollectionMapping.cs b/src/UnitTests/Bug/LazyCollectionMapping.cs index 1760cc419d..0d08cc5345 100644 --- a/src/UnitTests/Bug/LazyCollectionMapping.cs +++ b/src/UnitTests/Bug/LazyCollectionMapping.cs @@ -5,69 +5,68 @@ using Shouldly; using Xunit; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class LazyCollectionMapping { - public class LazyCollectionMapping + public class OneTimeEnumerator : IEnumerable { - public class OneTimeEnumerator : IEnumerable - { - private readonly IEnumerable inner; - - public OneTimeEnumerator(IEnumerable inner) - { - this.inner = inner; - } - - private bool isEnumerated; + private readonly IEnumerable inner; - public IEnumerator GetEnumerator() - { - if (isEnumerated) - throw new NotSupportedException(); - isEnumerated = true; - return inner.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } + public OneTimeEnumerator(IEnumerable inner) + { + this.inner = inner; } - public class Source + private bool isEnumerated; + + public IEnumerator GetEnumerator() { - public IEnumerable Collection { get; set; } + if (isEnumerated) + throw new NotSupportedException(); + isEnumerated = true; + return inner.GetEnumerator(); } - public class Destination + IEnumerator IEnumerable.GetEnumerator() { - public IEnumerable Collection { get; set; } + return GetEnumerator(); } + } - [Fact] - public void OneTimeEnumerator_should_throw_exception_if_enumerating_twice() - { - IEnumerable enumerable = Create(new[] {"one", "two", "three"}); - - enumerable.Count().ShouldBe(3); + public class Source + { + public IEnumerable Collection { get; set; } + } - typeof (NotSupportedException).ShouldBeThrownBy(() => enumerable.Count()); - } + public class Destination + { + public IEnumerable Collection { get; set; } + } + + [Fact] + public void OneTimeEnumerator_should_throw_exception_if_enumerating_twice() + { + IEnumerable enumerable = Create(new[] {"one", "two", "three"}); - [Fact] - public void Should_not_enumerate_twice() - { - var config = new MapperConfiguration(cfg => cfg.CreateMap()); + enumerable.Count().ShouldBe(3); + + typeof (NotSupportedException).ShouldBeThrownBy(() => enumerable.Count()); + } + + [Fact] + public void Should_not_enumerate_twice() + { + var config = new MapperConfiguration(cfg => cfg.CreateMap()); - var source = new Source {Collection = Create(new[] {"one", "two", "three"})}; - var enumerable = config.CreateMapper().Map(source, new Destination()); + var source = new Source {Collection = Create(new[] {"one", "two", "three"})}; + var enumerable = config.CreateMapper().Map(source, new Destination()); - enumerable.Collection.Count().ShouldBe(3); - } + enumerable.Collection.Count().ShouldBe(3); + } - public static IEnumerable Create(IEnumerable inner) - { - return new OneTimeEnumerator(inner); - } + public static IEnumerable Create(IEnumerable inner) + { + return new OneTimeEnumerator(inner); } } \ No newline at end of file diff --git a/src/UnitTests/Bug/ListSourceMapperBug.cs b/src/UnitTests/Bug/ListSourceMapperBug.cs index 2456a47602..d30f8f3adc 100644 --- a/src/UnitTests/Bug/ListSourceMapperBug.cs +++ b/src/UnitTests/Bug/ListSourceMapperBug.cs @@ -1,46 +1,45 @@ -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +using System; +using System.Collections; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Linq; +using Shouldly; +using Xunit; + +public class ListSourceMapperBug { - using System; - using System.Collections; - using System.Collections.ObjectModel; - using System.ComponentModel; - using System.Linq; - using Shouldly; - using Xunit; - - public class ListSourceMapperBug + public class CustomCollection : Collection, IListSource { - public class CustomCollection : Collection, IListSource + public IList GetList() { - public IList GetList() - { - return new ReadOnlyCollection(this.ToList()); - } - - public bool ContainsListCollection - { - get { return true; } - } + return new ReadOnlyCollection(this.ToList()); } - public class Source + public bool ContainsListCollection { + get { return true; } } + } - public class Dest - { - } + public class Source + { + } - [Fact] - public void CustomListSourceShouldNotBlowUp() - { - var config = new MapperConfiguration(cfg => cfg.CreateMap()); + public class Dest + { + } - var source = new CustomCollection {new Source()}; + [Fact] + public void CustomListSourceShouldNotBlowUp() + { + var config = new MapperConfiguration(cfg => cfg.CreateMap()); - var dests = config.CreateMapper().Map, CustomCollection>(source); + var source = new CustomCollection {new Source()}; - dests.Count.ShouldBe(1); - } + var dests = config.CreateMapper().Map, CustomCollection>(source); + + dests.Count.ShouldBe(1); } } \ No newline at end of file diff --git a/src/UnitTests/Bug/MapAtRuntime/BaseEntity.cs b/src/UnitTests/Bug/MapAtRuntime/BaseEntity.cs index 5e9eb334ee..4645e62803 100644 --- a/src/UnitTests/Bug/MapAtRuntime/BaseEntity.cs +++ b/src/UnitTests/Bug/MapAtRuntime/BaseEntity.cs @@ -4,10 +4,9 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDatabaseModel3 +namespace OmmitedDatabaseModel3; + +public class BaseEntity { - public class BaseEntity - { - public Guid Id { get; set; } - } + public Guid Id { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntime/BaseEntityDTO.cs b/src/UnitTests/Bug/MapAtRuntime/BaseEntityDTO.cs index d3f363d7f3..1c9ecc31d6 100644 --- a/src/UnitTests/Bug/MapAtRuntime/BaseEntityDTO.cs +++ b/src/UnitTests/Bug/MapAtRuntime/BaseEntityDTO.cs @@ -4,10 +4,9 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDTOModel3 +namespace OmmitedDTOModel3; + +public class BaseEntity { - public class BaseEntity - { - public Guid Id { get; set; } - } + public Guid Id { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntime/Entity1.cs b/src/UnitTests/Bug/MapAtRuntime/Entity1.cs index bd5efc24fa..246f0d30a2 100644 --- a/src/UnitTests/Bug/MapAtRuntime/Entity1.cs +++ b/src/UnitTests/Bug/MapAtRuntime/Entity1.cs @@ -4,26 +4,25 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDatabaseModel3 -{ - public class Entity1 : BaseEntity +namespace OmmitedDatabaseModel3; + +public class Entity1 : BaseEntity +{ + public Entity1() { - public Entity1() - { - this.Entities2 = new Entity2(); - } - public Guid Entity17Id { get; set; } - public Entity17 Entity17 { get; set; } - public Guid? Entity22Id { get; set; } - public Entity22 Entity22 { get; set; } - public Guid? Entity20Id { get; set; } - public Entity20 Entity20 { get; set; } - public Guid? Entity12Id { get; set; } - public Entity12 Entity12 { get; set; } - public Guid Entity14Id { get; set; } - public Entity14 Entity14 { get; set; } - public Guid Entity8Id { get; set; } - public Entity8 Entity8 { get; set; } - public Entity2 Entities2 { get; set; } + this.Entities2 = new Entity2(); } + public Guid Entity17Id { get; set; } + public Entity17 Entity17 { get; set; } + public Guid? Entity22Id { get; set; } + public Entity22 Entity22 { get; set; } + public Guid? Entity20Id { get; set; } + public Entity20 Entity20 { get; set; } + public Guid? Entity12Id { get; set; } + public Entity12 Entity12 { get; set; } + public Guid Entity14Id { get; set; } + public Entity14 Entity14 { get; set; } + public Guid Entity8Id { get; set; } + public Entity8 Entity8 { get; set; } + public Entity2 Entities2 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntime/Entity10.cs b/src/UnitTests/Bug/MapAtRuntime/Entity10.cs index a3afeb80da..0c9a0a6105 100644 --- a/src/UnitTests/Bug/MapAtRuntime/Entity10.cs +++ b/src/UnitTests/Bug/MapAtRuntime/Entity10.cs @@ -1,13 +1,12 @@ using System.Collections.Generic; -namespace OmmitedDatabaseModel3 +namespace OmmitedDatabaseModel3; + +public class Entity10 : BaseEntity { - public class Entity10 : BaseEntity + public Entity10() { - public Entity10() - { - this.Entities11 = new Entity11(); - } - public Entity11 Entities11 { get; set; } + this.Entities11 = new Entity11(); } + public Entity11 Entities11 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntime/Entity11.cs b/src/UnitTests/Bug/MapAtRuntime/Entity11.cs index e3f332794f..194b6cb1fe 100644 --- a/src/UnitTests/Bug/MapAtRuntime/Entity11.cs +++ b/src/UnitTests/Bug/MapAtRuntime/Entity11.cs @@ -4,16 +4,15 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDatabaseModel3 +namespace OmmitedDatabaseModel3; + +public class Entity11 : BaseEntity { - public class Entity11 : BaseEntity + public Entity11() { - public Entity11() - { - this.Entities10 = new Entity10(); - this.Entities8 = new Entity8(); - } - public Entity10 Entities10 { get; set; } - public Entity8 Entities8 { get; set; } + this.Entities10 = new Entity10(); + this.Entities8 = new Entity8(); } + public Entity10 Entities10 { get; set; } + public Entity8 Entities8 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntime/Entity12.cs b/src/UnitTests/Bug/MapAtRuntime/Entity12.cs index f536dd4245..76f357cb9b 100644 --- a/src/UnitTests/Bug/MapAtRuntime/Entity12.cs +++ b/src/UnitTests/Bug/MapAtRuntime/Entity12.cs @@ -4,18 +4,17 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDatabaseModel3 +namespace OmmitedDatabaseModel3; + +public class Entity12 : BaseEntity { - public class Entity12 : BaseEntity + public Entity12() { - public Entity12() - { - //this.Entities20 = new Entity20(); - //this.Entities14 = new Entity14(); - //this.Entities16 = new Entity16(); - } - public Entity20 Entities20 { get; set; } - public Entity16 Entities16 { get; set; } - public Entity14 Entities14 { get; set; } + //this.Entities20 = new Entity20(); + //this.Entities14 = new Entity14(); + //this.Entities16 = new Entity16(); } + public Entity20 Entities20 { get; set; } + public Entity16 Entities16 { get; set; } + public Entity14 Entities14 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntime/Entity13.cs b/src/UnitTests/Bug/MapAtRuntime/Entity13.cs index ae8a6cb6c9..9f8bd9aaea 100644 --- a/src/UnitTests/Bug/MapAtRuntime/Entity13.cs +++ b/src/UnitTests/Bug/MapAtRuntime/Entity13.cs @@ -4,13 +4,12 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDatabaseModel3 +namespace OmmitedDatabaseModel3; + +public class Entity13 : BaseEntity { - public class Entity13 : BaseEntity - { - public Guid Entity17Id { get; set; } - public Entity17 Entity17 { get; set; } - public Guid Entity8Id { get; set; } - public Entity8 Entity8 { get; set; } - } + public Guid Entity17Id { get; set; } + public Entity17 Entity17 { get; set; } + public Guid Entity8Id { get; set; } + public Entity8 Entity8 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntime/Entity14.cs b/src/UnitTests/Bug/MapAtRuntime/Entity14.cs index 9bbc83f5fd..e0644551de 100644 --- a/src/UnitTests/Bug/MapAtRuntime/Entity14.cs +++ b/src/UnitTests/Bug/MapAtRuntime/Entity14.cs @@ -5,17 +5,16 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDatabaseModel3 +namespace OmmitedDatabaseModel3; + +public class Entity14 : BaseEntity { - public class Entity14 : BaseEntity + public Entity14() { - public Entity14() - { - this.Entities12 = new Entity12(); - this.Entities1 = new Entity1(); - } - - public Entity12 Entities12 { get; set; } - public Entity1 Entities1 { get; set; } + this.Entities12 = new Entity12(); + this.Entities1 = new Entity1(); } + + public Entity12 Entities12 { get; set; } + public Entity1 Entities1 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntime/Entity15.cs b/src/UnitTests/Bug/MapAtRuntime/Entity15.cs index 408f6b5047..17ba3d94db 100644 --- a/src/UnitTests/Bug/MapAtRuntime/Entity15.cs +++ b/src/UnitTests/Bug/MapAtRuntime/Entity15.cs @@ -4,11 +4,10 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDatabaseModel3 +namespace OmmitedDatabaseModel3; + +public class Entity15 : BaseEntity { - public class Entity15 : BaseEntity - { - public Guid Entity17Id { get; set; } - public Entity17 Entity17 { get; set; } - } + public Guid Entity17Id { get; set; } + public Entity17 Entity17 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntime/Entity16.cs b/src/UnitTests/Bug/MapAtRuntime/Entity16.cs index df5dbb4bb7..5c42e375b1 100644 --- a/src/UnitTests/Bug/MapAtRuntime/Entity16.cs +++ b/src/UnitTests/Bug/MapAtRuntime/Entity16.cs @@ -4,13 +4,12 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDatabaseModel3 +namespace OmmitedDatabaseModel3; + +public class Entity16 : BaseEntity { - public class Entity16 : BaseEntity - { - public Guid Entity20Id { get; set; } - public Entity20 Entity20 { get; set; } - public Guid Entity12Id { get; set; } - public Entity12 Entity12 { get; set; } - } + public Guid Entity20Id { get; set; } + public Entity20 Entity20 { get; set; } + public Guid Entity12Id { get; set; } + public Entity12 Entity12 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntime/Entity17.cs b/src/UnitTests/Bug/MapAtRuntime/Entity17.cs index 176e524caa..2e705582d2 100644 --- a/src/UnitTests/Bug/MapAtRuntime/Entity17.cs +++ b/src/UnitTests/Bug/MapAtRuntime/Entity17.cs @@ -4,21 +4,20 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDatabaseModel3 +namespace OmmitedDatabaseModel3; + +public class Entity17 :BaseEntity { - public class Entity17 :BaseEntity + public Entity17() { - public Entity17() - { - //this.Entities20 = new Entity20(); - this.Entities8 = new Entity8(); - this.Entities5 = new Entity5(); - this.Entities18 = new Entity18(); - } - - public Entity20 Entities20 { get; set; } - public Entity8 Entities8 { get; set; } - public Entity5 Entities5 { get; set; } - public Entity18 Entities18 { get; set; } + //this.Entities20 = new Entity20(); + this.Entities8 = new Entity8(); + this.Entities5 = new Entity5(); + this.Entities18 = new Entity18(); } + + public Entity20 Entities20 { get; set; } + public Entity8 Entities8 { get; set; } + public Entity5 Entities5 { get; set; } + public Entity18 Entities18 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntime/Entity18.cs b/src/UnitTests/Bug/MapAtRuntime/Entity18.cs index ca61ff7162..b631d40505 100644 --- a/src/UnitTests/Bug/MapAtRuntime/Entity18.cs +++ b/src/UnitTests/Bug/MapAtRuntime/Entity18.cs @@ -1,12 +1,11 @@ using System; -namespace OmmitedDatabaseModel3 +namespace OmmitedDatabaseModel3; + +public class Entity18 : BaseEntity { - public class Entity18 : BaseEntity - { - public Guid Entity17Id { get; set; } - public Entity17 Entity17 { get; set; } - public Guid Entity20Id { get; set; } - public Entity20 Entity20 { get; set; } - } + public Guid Entity17Id { get; set; } + public Entity17 Entity17 { get; set; } + public Guid Entity20Id { get; set; } + public Entity20 Entity20 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntime/Entity19.cs b/src/UnitTests/Bug/MapAtRuntime/Entity19.cs index 05bcf24345..dd212257c1 100644 --- a/src/UnitTests/Bug/MapAtRuntime/Entity19.cs +++ b/src/UnitTests/Bug/MapAtRuntime/Entity19.cs @@ -1,10 +1,9 @@ using System; -namespace OmmitedDatabaseModel3 +namespace OmmitedDatabaseModel3; + +public class Entity19 : BaseEntity { - public class Entity19 : BaseEntity - { - public Guid Entity25Id { get; set; } - public Entity25 Entity25 { get; set; } - } + public Guid Entity25Id { get; set; } + public Entity25 Entity25 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntime/Entity2.cs b/src/UnitTests/Bug/MapAtRuntime/Entity2.cs index 247108a0f9..debd55e149 100644 --- a/src/UnitTests/Bug/MapAtRuntime/Entity2.cs +++ b/src/UnitTests/Bug/MapAtRuntime/Entity2.cs @@ -1,10 +1,9 @@ using System; -namespace OmmitedDatabaseModel3 +namespace OmmitedDatabaseModel3; + +public class Entity2 : BaseEntity { - public class Entity2 : BaseEntity - { - public Guid Entity1Id { get; set; } - public Entity1 Entity1 { get; set; } - } + public Guid Entity1Id { get; set; } + public Entity1 Entity1 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntime/Entity20.cs b/src/UnitTests/Bug/MapAtRuntime/Entity20.cs index fbb7b4e06d..f309c0c208 100644 --- a/src/UnitTests/Bug/MapAtRuntime/Entity20.cs +++ b/src/UnitTests/Bug/MapAtRuntime/Entity20.cs @@ -4,29 +4,28 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDatabaseModel3 +namespace OmmitedDatabaseModel3; + +public class Entity20 : BaseEntity { - public class Entity20 : BaseEntity + public Entity20() { - public Entity20() - { - //this.Entities8 = new Entity8(); - //this.Entities26 = new Entity26(); - //this.Entities12 = new Entity12(); - //this.Entities17 = new Entity17(); - //this.Entities21 = new Entity21(); - //this.Entities16 = new Entity16(); - } - - public Guid Entity3Id { get; set; } - public Entity3 Entity3 { get; set; } - public Guid Entity22Id { get; set; } - public Entity22 Entity22 { get; set; } - public Entity8 Entities8 { get; set; } - public Entity26 Entities26 { get; set; } - public Entity12 Entities12 { get; set; } - public Entity17 Entities17 { get; set; } - public Entity21 Entities21 { get; set; } - public Entity16 Entities16 { get; set; } + //this.Entities8 = new Entity8(); + //this.Entities26 = new Entity26(); + //this.Entities12 = new Entity12(); + //this.Entities17 = new Entity17(); + //this.Entities21 = new Entity21(); + //this.Entities16 = new Entity16(); } + + public Guid Entity3Id { get; set; } + public Entity3 Entity3 { get; set; } + public Guid Entity22Id { get; set; } + public Entity22 Entity22 { get; set; } + public Entity8 Entities8 { get; set; } + public Entity26 Entities26 { get; set; } + public Entity12 Entities12 { get; set; } + public Entity17 Entities17 { get; set; } + public Entity21 Entities21 { get; set; } + public Entity16 Entities16 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntime/Entity21.cs b/src/UnitTests/Bug/MapAtRuntime/Entity21.cs index 2b28082108..f612924518 100644 --- a/src/UnitTests/Bug/MapAtRuntime/Entity21.cs +++ b/src/UnitTests/Bug/MapAtRuntime/Entity21.cs @@ -1,10 +1,9 @@ using System; -namespace OmmitedDatabaseModel3 +namespace OmmitedDatabaseModel3; + +public class Entity21 : BaseEntity { - public class Entity21 : BaseEntity - { - public Guid Entity20Id { get; set; } - public Entity20 Entity20 { get; set; } - } + public Guid Entity20Id { get; set; } + public Entity20 Entity20 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntime/Entity22.cs b/src/UnitTests/Bug/MapAtRuntime/Entity22.cs index d0f90a2a6b..ea126f326b 100644 --- a/src/UnitTests/Bug/MapAtRuntime/Entity22.cs +++ b/src/UnitTests/Bug/MapAtRuntime/Entity22.cs @@ -4,16 +4,15 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDatabaseModel3 +namespace OmmitedDatabaseModel3; + +public class Entity22 : BaseEntity { - public class Entity22 : BaseEntity + public Entity22() { - public Entity22() - { - this.Entities20 = new Entity20(); - this.Entities24 = new Entity24(); - } - public Entity20 Entities20 { get; set; } - public Entity24 Entities24 { get; set; } + this.Entities20 = new Entity20(); + this.Entities24 = new Entity24(); } + public Entity20 Entities20 { get; set; } + public Entity24 Entities24 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntime/Entity23.cs b/src/UnitTests/Bug/MapAtRuntime/Entity23.cs index 63d004623f..6f37dfe3a6 100644 --- a/src/UnitTests/Bug/MapAtRuntime/Entity23.cs +++ b/src/UnitTests/Bug/MapAtRuntime/Entity23.cs @@ -4,11 +4,10 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDatabaseModel3 +namespace OmmitedDatabaseModel3; + +public class Entity23 : BaseEntity { - public class Entity23 : BaseEntity - { - public Guid Entity5Id { get; set; } - public Entity5 Entity5 { get; set; } - } + public Guid Entity5Id { get; set; } + public Entity5 Entity5 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntime/Entity24.cs b/src/UnitTests/Bug/MapAtRuntime/Entity24.cs index d3072a6912..3ff3b620e7 100644 --- a/src/UnitTests/Bug/MapAtRuntime/Entity24.cs +++ b/src/UnitTests/Bug/MapAtRuntime/Entity24.cs @@ -4,13 +4,12 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDatabaseModel3 +namespace OmmitedDatabaseModel3; + +public class Entity24 : BaseEntity { - public class Entity24 : BaseEntity - { - public Guid Entity3Id { get; set; } - public Entity3 Entity3 { get; set; } - public Guid Entity22Id { get; set; } - public Entity22 Entity22 { get; set; } - } + public Guid Entity3Id { get; set; } + public Entity3 Entity3 { get; set; } + public Guid Entity22Id { get; set; } + public Entity22 Entity22 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntime/Entity25.cs b/src/UnitTests/Bug/MapAtRuntime/Entity25.cs index 8840d2d66a..13ec088fb6 100644 --- a/src/UnitTests/Bug/MapAtRuntime/Entity25.cs +++ b/src/UnitTests/Bug/MapAtRuntime/Entity25.cs @@ -5,19 +5,18 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDatabaseModel3 +namespace OmmitedDatabaseModel3; + +public class Entity25 : BaseEntity { - public class Entity25 : BaseEntity + public Entity25() { - public Entity25() - { - this.Entities19 = new Entity19(); - } - - public Entity19 Entities19 { get; set; } - public Guid? Entity8Id { get; set; } - public Entity8 Entity8 { get; set; } - public Guid? Entity17Id { get; set; } - public Entity17 Entity17 { get; set; } + this.Entities19 = new Entity19(); } + + public Entity19 Entities19 { get; set; } + public Guid? Entity8Id { get; set; } + public Entity8 Entity8 { get; set; } + public Guid? Entity17Id { get; set; } + public Entity17 Entity17 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntime/Entity26.cs b/src/UnitTests/Bug/MapAtRuntime/Entity26.cs index ad2ded07b3..3a3d62f2e4 100644 --- a/src/UnitTests/Bug/MapAtRuntime/Entity26.cs +++ b/src/UnitTests/Bug/MapAtRuntime/Entity26.cs @@ -4,15 +4,14 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDatabaseModel3 +namespace OmmitedDatabaseModel3; + +public class Entity26 : BaseEntity { - public class Entity26 : BaseEntity + public Entity26() { - public Entity26() - { - //this.Entities20 = new Entity20(); - } - - public Entity20 Entities20 { get; set; } + //this.Entities20 = new Entity20(); } + + public Entity20 Entities20 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntime/Entity3.cs b/src/UnitTests/Bug/MapAtRuntime/Entity3.cs index f751a3ee63..7573f40f1e 100644 --- a/src/UnitTests/Bug/MapAtRuntime/Entity3.cs +++ b/src/UnitTests/Bug/MapAtRuntime/Entity3.cs @@ -4,16 +4,15 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDatabaseModel3 +namespace OmmitedDatabaseModel3; + +public class Entity3 : BaseEntity { - public class Entity3 : BaseEntity + public Entity3() { - public Entity3() - { - this.Entities4 = new Entity4(); - this.Entities8 = new Entity8(); - } - public Entity4 Entities4 { get; set; } - public Entity8 Entities8 { get; set; } + this.Entities4 = new Entity4(); + this.Entities8 = new Entity8(); } + public Entity4 Entities4 { get; set; } + public Entity8 Entities8 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntime/Entity4.cs b/src/UnitTests/Bug/MapAtRuntime/Entity4.cs index eb1c8a847e..66d71ff4fa 100644 --- a/src/UnitTests/Bug/MapAtRuntime/Entity4.cs +++ b/src/UnitTests/Bug/MapAtRuntime/Entity4.cs @@ -4,11 +4,10 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDatabaseModel3 +namespace OmmitedDatabaseModel3; + +public class Entity4 : BaseEntity { - public class Entity4 : BaseEntity - { - public Guid Entity3Id { get; set; } - public Entity3 Entity3 { get; set; } - } + public Guid Entity3Id { get; set; } + public Entity3 Entity3 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntime/Entity5.cs b/src/UnitTests/Bug/MapAtRuntime/Entity5.cs index faf98014c5..493febcdfb 100644 --- a/src/UnitTests/Bug/MapAtRuntime/Entity5.cs +++ b/src/UnitTests/Bug/MapAtRuntime/Entity5.cs @@ -4,25 +4,24 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDatabaseModel3 +namespace OmmitedDatabaseModel3; + +public class Entity5 : BaseEntity { - public class Entity5 : BaseEntity + public Entity5() { - public Entity5() - { - //this.Entities6 = new Entity6(); - //this.TimeSlots = new Entity23(); - //this.Entities5 = new Entity5(); - } - - public Guid? Entity8Id { get; set; } - public Entity8 Entity8 { get; set; } - public Guid? Entity17Id { get; set; } - public Entity17 Entity17 { get; set; } - public Guid? Entity5Id { get; set; } - public Entity5 Entity5Exception { get; set; } - public Entity5 Entities5 { get; set; } - public Entity6 Entities6 { get; set; } - public Entity23 TimeSlots { get; set; } + //this.Entities6 = new Entity6(); + //this.TimeSlots = new Entity23(); + //this.Entities5 = new Entity5(); } + + public Guid? Entity8Id { get; set; } + public Entity8 Entity8 { get; set; } + public Guid? Entity17Id { get; set; } + public Entity17 Entity17 { get; set; } + public Guid? Entity5Id { get; set; } + public Entity5 Entity5Exception { get; set; } + public Entity5 Entities5 { get; set; } + public Entity6 Entities6 { get; set; } + public Entity23 TimeSlots { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntime/Entity6.cs b/src/UnitTests/Bug/MapAtRuntime/Entity6.cs index b4fc4dd03c..4c4b383d52 100644 --- a/src/UnitTests/Bug/MapAtRuntime/Entity6.cs +++ b/src/UnitTests/Bug/MapAtRuntime/Entity6.cs @@ -4,19 +4,18 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDatabaseModel3 +namespace OmmitedDatabaseModel3; + +public class Entity6 : BaseEntity { - public class Entity6 : BaseEntity + public Entity6() { - public Entity6() - { - this.Entities12 = new Entity12(); - } - - public Guid Entity5Id { get; set; } - public Entity5 Entity5 { get; set; } - public Guid Entity20Id { get; set; } - public Entity20 Entity20 { get; set; } - public Entity12 Entities12 { get; set; } + this.Entities12 = new Entity12(); } + + public Guid Entity5Id { get; set; } + public Entity5 Entity5 { get; set; } + public Guid Entity20Id { get; set; } + public Entity20 Entity20 { get; set; } + public Entity12 Entities12 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntime/Entity7.cs b/src/UnitTests/Bug/MapAtRuntime/Entity7.cs index 71e035d3bf..208f3627ba 100644 --- a/src/UnitTests/Bug/MapAtRuntime/Entity7.cs +++ b/src/UnitTests/Bug/MapAtRuntime/Entity7.cs @@ -1,12 +1,11 @@ using System; -namespace OmmitedDatabaseModel3 +namespace OmmitedDatabaseModel3; + +public class Entity7 : BaseEntity { - public class Entity7 : BaseEntity - { - public Guid Entity25Id { get; set; } - public Entity25 Entity25 { get; set; } - public Guid? Entity14Id { get; set; } - public Entity14 Entity14 { get; set; } - } + public Guid Entity25Id { get; set; } + public Entity25 Entity25 { get; set; } + public Guid? Entity14Id { get; set; } + public Entity14 Entity14 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntime/Entity8.cs b/src/UnitTests/Bug/MapAtRuntime/Entity8.cs index e047d6e68f..dab0b27ce2 100644 --- a/src/UnitTests/Bug/MapAtRuntime/Entity8.cs +++ b/src/UnitTests/Bug/MapAtRuntime/Entity8.cs @@ -4,23 +4,22 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDatabaseModel3 +namespace OmmitedDatabaseModel3; + +public class Entity8 : BaseEntity { - public class Entity8 : BaseEntity + public Entity8() { - public Entity8() - { - //this.Entities20 = new Entity20(); - //this.Entities22 = new Entity22(); - //this.Entities3 = new Entity3(); - //this.Entities11 = new Entity11(); - //this.Entities17 = new Entity17(); - } - - public Entity20 Entities20 { get; set; } - public Entity17 Entities17 { get; set; } - public Entity22 Entities22 { get; set; } - public Entity3 Entities3 { get; set; } - public Entity11 Entities11 { get; set; } + //this.Entities20 = new Entity20(); + //this.Entities22 = new Entity22(); + //this.Entities3 = new Entity3(); + //this.Entities11 = new Entity11(); + //this.Entities17 = new Entity17(); } + + public Entity20 Entities20 { get; set; } + public Entity17 Entities17 { get; set; } + public Entity22 Entities22 { get; set; } + public Entity3 Entities3 { get; set; } + public Entity11 Entities11 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntime/Entity9.cs b/src/UnitTests/Bug/MapAtRuntime/Entity9.cs index d2f6404df3..ed5f9d7c93 100644 --- a/src/UnitTests/Bug/MapAtRuntime/Entity9.cs +++ b/src/UnitTests/Bug/MapAtRuntime/Entity9.cs @@ -1,10 +1,9 @@ using System; -namespace OmmitedDatabaseModel3 +namespace OmmitedDatabaseModel3; + +public class Entity9 : BaseEntity { - public class Entity9 : BaseEntity - { - public Guid Entity3Id { get; set; } - public Entity3 Entity3 { get; set; } - } + public Guid Entity3Id { get; set; } + public Entity3 Entity3 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntime/EntityDTO1.cs b/src/UnitTests/Bug/MapAtRuntime/EntityDTO1.cs index 74373f4be1..5dae37ac76 100644 --- a/src/UnitTests/Bug/MapAtRuntime/EntityDTO1.cs +++ b/src/UnitTests/Bug/MapAtRuntime/EntityDTO1.cs @@ -4,26 +4,25 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDTOModel3 -{ - public class EntityDTO1 : BaseEntity +namespace OmmitedDTOModel3; + +public class EntityDTO1 : BaseEntity +{ + public EntityDTO1() { - public EntityDTO1() - { - this.Entities2 = new EntityDTO2(); - } - public Guid Entity17Id { get; set; } - public EntityDTO17 Entity17 { get; set; } - public Guid? Entity22Id { get; set; } - public EntityDTO22 Entity22 { get; set; } - public Guid? Entity20Id { get; set; } - public EntityDTO20 Entity20 { get; set; } - public Guid? Entity12Id { get; set; } - public EntityDTO12 Entity12 { get; set; } - public Guid Entity14Id { get; set; } - public EntityDTO14 Entity14 { get; set; } - public Guid Entity8Id { get; set; } - public EntityDTO8 Entity8 { get; set; } - public EntityDTO2 Entities2 { get; set; } + this.Entities2 = new EntityDTO2(); } + public Guid Entity17Id { get; set; } + public EntityDTO17 Entity17 { get; set; } + public Guid? Entity22Id { get; set; } + public EntityDTO22 Entity22 { get; set; } + public Guid? Entity20Id { get; set; } + public EntityDTO20 Entity20 { get; set; } + public Guid? Entity12Id { get; set; } + public EntityDTO12 Entity12 { get; set; } + public Guid Entity14Id { get; set; } + public EntityDTO14 Entity14 { get; set; } + public Guid Entity8Id { get; set; } + public EntityDTO8 Entity8 { get; set; } + public EntityDTO2 Entities2 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntime/EntityDTO10.cs b/src/UnitTests/Bug/MapAtRuntime/EntityDTO10.cs index d88657af4c..b16c61e597 100644 --- a/src/UnitTests/Bug/MapAtRuntime/EntityDTO10.cs +++ b/src/UnitTests/Bug/MapAtRuntime/EntityDTO10.cs @@ -1,13 +1,12 @@ using System.Collections.Generic; -namespace OmmitedDTOModel3 +namespace OmmitedDTOModel3; + +public class EntityDTO10 : BaseEntity { - public class EntityDTO10 : BaseEntity + public EntityDTO10() { - public EntityDTO10() - { - this.Entities11 = new EntityDTO11(); - } - public EntityDTO11 Entities11 { get; set; } + this.Entities11 = new EntityDTO11(); } + public EntityDTO11 Entities11 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntime/EntityDTO11.cs b/src/UnitTests/Bug/MapAtRuntime/EntityDTO11.cs index 5aa07559e9..8073590d7b 100644 --- a/src/UnitTests/Bug/MapAtRuntime/EntityDTO11.cs +++ b/src/UnitTests/Bug/MapAtRuntime/EntityDTO11.cs @@ -4,16 +4,15 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDTOModel3 +namespace OmmitedDTOModel3; + +public class EntityDTO11 : BaseEntity { - public class EntityDTO11 : BaseEntity + public EntityDTO11() { - public EntityDTO11() - { - //this.Entities10 = new EntityDTO10(); - //this.Entities8 = new EntityDTO8(); - } - public EntityDTO10 Entities10 { get; set; } - public EntityDTO8 Entities8 { get; set; } + //this.Entities10 = new EntityDTO10(); + //this.Entities8 = new EntityDTO8(); } + public EntityDTO10 Entities10 { get; set; } + public EntityDTO8 Entities8 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntime/EntityDTO12.cs b/src/UnitTests/Bug/MapAtRuntime/EntityDTO12.cs index 94c6cea25a..6d9b1f72e5 100644 --- a/src/UnitTests/Bug/MapAtRuntime/EntityDTO12.cs +++ b/src/UnitTests/Bug/MapAtRuntime/EntityDTO12.cs @@ -4,18 +4,17 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDTOModel3 +namespace OmmitedDTOModel3; + +public class EntityDTO12 : BaseEntity { - public class EntityDTO12 : BaseEntity + public EntityDTO12() { - public EntityDTO12() - { - //this.Entities20 = new EntityDTO20(); - //this.Entities14 = new EntityDTO14(); - //Entities16 = new EntityDTO16(); - } - public EntityDTO20 Entities20 { get; set; } - public EntityDTO16 Entities16 { get; set; } - public EntityDTO14 Entities14 { get; set; } + //this.Entities20 = new EntityDTO20(); + //this.Entities14 = new EntityDTO14(); + //Entities16 = new EntityDTO16(); } + public EntityDTO20 Entities20 { get; set; } + public EntityDTO16 Entities16 { get; set; } + public EntityDTO14 Entities14 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntime/EntityDTO13.cs b/src/UnitTests/Bug/MapAtRuntime/EntityDTO13.cs index 0072308d9d..e97f1cc60d 100644 --- a/src/UnitTests/Bug/MapAtRuntime/EntityDTO13.cs +++ b/src/UnitTests/Bug/MapAtRuntime/EntityDTO13.cs @@ -4,13 +4,12 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDTOModel3 +namespace OmmitedDTOModel3; + +public class EntityDTO13 : BaseEntity { - public class EntityDTO13 : BaseEntity - { - public Guid Entity17Id { get; set; } - public EntityDTO17 Entity17 { get; set; } - public Guid Entity8Id { get; set; } - public EntityDTO8 Entity8 { get; set; } - } + public Guid Entity17Id { get; set; } + public EntityDTO17 Entity17 { get; set; } + public Guid Entity8Id { get; set; } + public EntityDTO8 Entity8 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntime/EntityDTO14.cs b/src/UnitTests/Bug/MapAtRuntime/EntityDTO14.cs index fb53288042..2c784e5cf2 100644 --- a/src/UnitTests/Bug/MapAtRuntime/EntityDTO14.cs +++ b/src/UnitTests/Bug/MapAtRuntime/EntityDTO14.cs @@ -5,18 +5,17 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDTOModel3 +namespace OmmitedDTOModel3; + +public class EntityDTO14 : BaseEntity { - public class EntityDTO14 : BaseEntity + public EntityDTO14() { - public EntityDTO14() - { - this.Entities12 = new EntityDTO12(); - this.Entities1 = new EntityDTO1(); - } - - //public Address Address { get; set; } - public EntityDTO12 Entities12 { get; set; } - public EntityDTO1 Entities1 { get; set; } + this.Entities12 = new EntityDTO12(); + this.Entities1 = new EntityDTO1(); } + + //public Address Address { get; set; } + public EntityDTO12 Entities12 { get; set; } + public EntityDTO1 Entities1 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntime/EntityDTO15.cs b/src/UnitTests/Bug/MapAtRuntime/EntityDTO15.cs index 6896fcfc76..ee2f109b3e 100644 --- a/src/UnitTests/Bug/MapAtRuntime/EntityDTO15.cs +++ b/src/UnitTests/Bug/MapAtRuntime/EntityDTO15.cs @@ -4,14 +4,13 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDTOModel3 +namespace OmmitedDTOModel3; + +public class EntityDTO15 : BaseEntity { - public class EntityDTO15 : BaseEntity + public EntityDTO15() { - public EntityDTO15() - { - } - public Guid Entity17Id { get; set; } - public EntityDTO17 Entity17 { get; set; } } + public Guid Entity17Id { get; set; } + public EntityDTO17 Entity17 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntime/EntityDTO16.cs b/src/UnitTests/Bug/MapAtRuntime/EntityDTO16.cs index cf4787a7ae..d25960ce7d 100644 --- a/src/UnitTests/Bug/MapAtRuntime/EntityDTO16.cs +++ b/src/UnitTests/Bug/MapAtRuntime/EntityDTO16.cs @@ -4,13 +4,12 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDTOModel3 +namespace OmmitedDTOModel3; + +public class EntityDTO16 : BaseEntity { - public class EntityDTO16 : BaseEntity - { - public Guid Entity20Id { get; set; } - public EntityDTO20 Entity20 { get; set; } - public Guid Entity12Id { get; set; } - public EntityDTO12 Entity12 { get; set; } - } + public Guid Entity20Id { get; set; } + public EntityDTO20 Entity20 { get; set; } + public Guid Entity12Id { get; set; } + public EntityDTO12 Entity12 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntime/EntityDTO17.cs b/src/UnitTests/Bug/MapAtRuntime/EntityDTO17.cs index 40f61205a3..71b2d663c7 100644 --- a/src/UnitTests/Bug/MapAtRuntime/EntityDTO17.cs +++ b/src/UnitTests/Bug/MapAtRuntime/EntityDTO17.cs @@ -4,21 +4,20 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDTOModel3 +namespace OmmitedDTOModel3; + +public class EntityDTO17 :BaseEntity { - public class EntityDTO17 :BaseEntity + public EntityDTO17() { - public EntityDTO17() - { - //this.Entities20 = new EntityDTO20(); - //this.Entities8 = new EntityDTO8(); - //this.Entities5 = new EntityDTO5(); - //this.Entities18 = new EntityDTO18(); - } - - public EntityDTO20 Entities20 { get; set; } - public EntityDTO8 Entities8 { get; set; } - public EntityDTO5 Entities5 { get; set; } - public EntityDTO18 Entities18 { get; set; } + //this.Entities20 = new EntityDTO20(); + //this.Entities8 = new EntityDTO8(); + //this.Entities5 = new EntityDTO5(); + //this.Entities18 = new EntityDTO18(); } + + public EntityDTO20 Entities20 { get; set; } + public EntityDTO8 Entities8 { get; set; } + public EntityDTO5 Entities5 { get; set; } + public EntityDTO18 Entities18 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntime/EntityDTO18.cs b/src/UnitTests/Bug/MapAtRuntime/EntityDTO18.cs index d6937f8c9a..8f46d2c99e 100644 --- a/src/UnitTests/Bug/MapAtRuntime/EntityDTO18.cs +++ b/src/UnitTests/Bug/MapAtRuntime/EntityDTO18.cs @@ -1,12 +1,11 @@ using System; -namespace OmmitedDTOModel3 +namespace OmmitedDTOModel3; + +public class EntityDTO18 : BaseEntity { - public class EntityDTO18 : BaseEntity - { - public Guid Entity17Id { get; set; } - public EntityDTO17 Entity17 { get; set; } - public Guid Entity20Id { get; set; } - public EntityDTO20 Entity20 { get; set; } - } + public Guid Entity17Id { get; set; } + public EntityDTO17 Entity17 { get; set; } + public Guid Entity20Id { get; set; } + public EntityDTO20 Entity20 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntime/EntityDTO19.cs b/src/UnitTests/Bug/MapAtRuntime/EntityDTO19.cs index e31a6c498f..0d6ad28b33 100644 --- a/src/UnitTests/Bug/MapAtRuntime/EntityDTO19.cs +++ b/src/UnitTests/Bug/MapAtRuntime/EntityDTO19.cs @@ -1,10 +1,9 @@ using System; -namespace OmmitedDTOModel3 +namespace OmmitedDTOModel3; + +public class EntityDTO19 : BaseEntity { - public class EntityDTO19 : BaseEntity - { - public Guid Entity25Id { get; set; } - public EntityDTO25 Entity25 { get; set; } - } + public Guid Entity25Id { get; set; } + public EntityDTO25 Entity25 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntime/EntityDTO2.cs b/src/UnitTests/Bug/MapAtRuntime/EntityDTO2.cs index 47eb7917d8..792edf2ced 100644 --- a/src/UnitTests/Bug/MapAtRuntime/EntityDTO2.cs +++ b/src/UnitTests/Bug/MapAtRuntime/EntityDTO2.cs @@ -1,10 +1,9 @@ using System; -namespace OmmitedDTOModel3 +namespace OmmitedDTOModel3; + +public class EntityDTO2 : BaseEntity { - public class EntityDTO2 : BaseEntity - { - public Guid Entity1Id { get; set; } - public EntityDTO1 Entity1 { get; set; } - } + public Guid Entity1Id { get; set; } + public EntityDTO1 Entity1 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntime/EntityDTO20.cs b/src/UnitTests/Bug/MapAtRuntime/EntityDTO20.cs index f91e23f761..73c780841f 100644 --- a/src/UnitTests/Bug/MapAtRuntime/EntityDTO20.cs +++ b/src/UnitTests/Bug/MapAtRuntime/EntityDTO20.cs @@ -4,30 +4,29 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDTOModel3 +namespace OmmitedDTOModel3; + +public class EntityDTO20 : BaseEntity { - public class EntityDTO20 : BaseEntity + //TODO Remove comments + public EntityDTO20() { - //TODO Remove comments - public EntityDTO20() - { - //this.Entities8 = new EntityDTO8(); - //this.Entities26 = new EntityDTO26(); - //this.Entities12 = new EntityDTO12(); - //this.Entities17 = new EntityDTO17(); - //this.Entities21 = new EntityDTO21(); - //this.Entities16 = new EntityDTO16(); - } - - public Guid Entity3Id { get; set; } - public EntityDTO3 Entity3 { get; set; } - public Guid Entity22Id { get; set; } - public EntityDTO22 Entity22 { get; set; } - public EntityDTO8 Entities8 { get; set; } - public EntityDTO26 Entities26 { get; set; } - public EntityDTO12 Entities12 { get; set; } - public EntityDTO17 Entities17 { get; set; } - public EntityDTO21 Entities21 { get; set; } - public EntityDTO16 Entities16 { get; set; } + //this.Entities8 = new EntityDTO8(); + //this.Entities26 = new EntityDTO26(); + //this.Entities12 = new EntityDTO12(); + //this.Entities17 = new EntityDTO17(); + //this.Entities21 = new EntityDTO21(); + //this.Entities16 = new EntityDTO16(); } + + public Guid Entity3Id { get; set; } + public EntityDTO3 Entity3 { get; set; } + public Guid Entity22Id { get; set; } + public EntityDTO22 Entity22 { get; set; } + public EntityDTO8 Entities8 { get; set; } + public EntityDTO26 Entities26 { get; set; } + public EntityDTO12 Entities12 { get; set; } + public EntityDTO17 Entities17 { get; set; } + public EntityDTO21 Entities21 { get; set; } + public EntityDTO16 Entities16 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntime/EntityDTO21.cs b/src/UnitTests/Bug/MapAtRuntime/EntityDTO21.cs index b7b3d8e060..64adb09fcb 100644 --- a/src/UnitTests/Bug/MapAtRuntime/EntityDTO21.cs +++ b/src/UnitTests/Bug/MapAtRuntime/EntityDTO21.cs @@ -1,10 +1,9 @@ using System; -namespace OmmitedDTOModel3 +namespace OmmitedDTOModel3; + +public class EntityDTO21 : BaseEntity { - public class EntityDTO21 : BaseEntity - { - public Guid Entity20Id { get; set; } - public EntityDTO20 Entity20 { get; set; } - } + public Guid Entity20Id { get; set; } + public EntityDTO20 Entity20 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntime/EntityDTO22.cs b/src/UnitTests/Bug/MapAtRuntime/EntityDTO22.cs index 2ece3d7bc3..dfda959791 100644 --- a/src/UnitTests/Bug/MapAtRuntime/EntityDTO22.cs +++ b/src/UnitTests/Bug/MapAtRuntime/EntityDTO22.cs @@ -4,16 +4,15 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDTOModel3 +namespace OmmitedDTOModel3; + +public class EntityDTO22 : BaseEntity { - public class EntityDTO22 : BaseEntity + public EntityDTO22() { - public EntityDTO22() - { - //this.Entities20 = new EntityDTO20(); - //this.Entities24 = new EntityDTO24(); - } - public EntityDTO20 Entities20 { get; set; } - public EntityDTO24 Entities24 { get; set; } + //this.Entities20 = new EntityDTO20(); + //this.Entities24 = new EntityDTO24(); } + public EntityDTO20 Entities20 { get; set; } + public EntityDTO24 Entities24 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntime/EntityDTO23.cs b/src/UnitTests/Bug/MapAtRuntime/EntityDTO23.cs index 42ea51a503..e0a267aba7 100644 --- a/src/UnitTests/Bug/MapAtRuntime/EntityDTO23.cs +++ b/src/UnitTests/Bug/MapAtRuntime/EntityDTO23.cs @@ -4,11 +4,10 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDTOModel3 +namespace OmmitedDTOModel3; + +public class EntityDTO23 : BaseEntity { - public class EntityDTO23 : BaseEntity - { - public Guid Entity5Id { get; set; } - public EntityDTO5 Entity5 { get; set; } - } + public Guid Entity5Id { get; set; } + public EntityDTO5 Entity5 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntime/EntityDTO24.cs b/src/UnitTests/Bug/MapAtRuntime/EntityDTO24.cs index dbc3260516..f2eb19c33b 100644 --- a/src/UnitTests/Bug/MapAtRuntime/EntityDTO24.cs +++ b/src/UnitTests/Bug/MapAtRuntime/EntityDTO24.cs @@ -4,13 +4,12 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDTOModel3 +namespace OmmitedDTOModel3; + +public class EntityDTO24 : BaseEntity { - public class EntityDTO24 : BaseEntity - { - public Guid Entity3Id { get; set; } - public EntityDTO3 Entity3 { get; set; } - public Guid Entity22Id { get; set; } - public EntityDTO22 Entity22 { get; set; } - } + public Guid Entity3Id { get; set; } + public EntityDTO3 Entity3 { get; set; } + public Guid Entity22Id { get; set; } + public EntityDTO22 Entity22 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntime/EntityDTO25.cs b/src/UnitTests/Bug/MapAtRuntime/EntityDTO25.cs index 7621f7e849..93f33568f1 100644 --- a/src/UnitTests/Bug/MapAtRuntime/EntityDTO25.cs +++ b/src/UnitTests/Bug/MapAtRuntime/EntityDTO25.cs @@ -5,19 +5,18 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDTOModel3 +namespace OmmitedDTOModel3; + +public class EntityDTO25 : BaseEntity { - public class EntityDTO25 : BaseEntity + public EntityDTO25() { - public EntityDTO25() - { - this.Entities19 = new EntityDTO19(); - } - - public EntityDTO19 Entities19 { get; set; } - public Guid? Entity8Id { get; set; } - public EntityDTO8 Entity8 { get; set; } - public Guid? Entity17Id { get; set; } - public EntityDTO17 Entity17 { get; set; } + this.Entities19 = new EntityDTO19(); } + + public EntityDTO19 Entities19 { get; set; } + public Guid? Entity8Id { get; set; } + public EntityDTO8 Entity8 { get; set; } + public Guid? Entity17Id { get; set; } + public EntityDTO17 Entity17 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntime/EntityDTO26.cs b/src/UnitTests/Bug/MapAtRuntime/EntityDTO26.cs index 9c4eea101b..de5284b4e6 100644 --- a/src/UnitTests/Bug/MapAtRuntime/EntityDTO26.cs +++ b/src/UnitTests/Bug/MapAtRuntime/EntityDTO26.cs @@ -4,15 +4,14 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDTOModel3 +namespace OmmitedDTOModel3; + +public class EntityDTO26 : BaseEntity { - public class EntityDTO26 : BaseEntity + public EntityDTO26() { - public EntityDTO26() - { - this.Entities20 = new EntityDTO20(); - } - - public EntityDTO20 Entities20 { get; set; } + this.Entities20 = new EntityDTO20(); } + + public EntityDTO20 Entities20 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntime/EntityDTO3.cs b/src/UnitTests/Bug/MapAtRuntime/EntityDTO3.cs index 6c5784042c..4b454d1b97 100644 --- a/src/UnitTests/Bug/MapAtRuntime/EntityDTO3.cs +++ b/src/UnitTests/Bug/MapAtRuntime/EntityDTO3.cs @@ -4,16 +4,15 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDTOModel3 +namespace OmmitedDTOModel3; + +public class EntityDTO3 : BaseEntity { - public class EntityDTO3 : BaseEntity + public EntityDTO3() { - public EntityDTO3() - { - //this.Entities4 = new EntityDTO4(); - //this.Entities8 = new EntityDTO8(); - } - public EntityDTO4 Entities4 { get; set; } - public EntityDTO8 Entities8 { get; set; } + //this.Entities4 = new EntityDTO4(); + //this.Entities8 = new EntityDTO8(); } + public EntityDTO4 Entities4 { get; set; } + public EntityDTO8 Entities8 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntime/EntityDTO4.cs b/src/UnitTests/Bug/MapAtRuntime/EntityDTO4.cs index 34ab48fb66..3e94ad513c 100644 --- a/src/UnitTests/Bug/MapAtRuntime/EntityDTO4.cs +++ b/src/UnitTests/Bug/MapAtRuntime/EntityDTO4.cs @@ -4,11 +4,10 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDTOModel3 +namespace OmmitedDTOModel3; + +public class EntityDTO4 : BaseEntity { - public class EntityDTO4 : BaseEntity - { - public Guid Entity3Id { get; set; } - public EntityDTO3 Entity3 { get; set; } - } + public Guid Entity3Id { get; set; } + public EntityDTO3 Entity3 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntime/EntityDTO5.cs b/src/UnitTests/Bug/MapAtRuntime/EntityDTO5.cs index 7af45e23f8..719de1c67a 100644 --- a/src/UnitTests/Bug/MapAtRuntime/EntityDTO5.cs +++ b/src/UnitTests/Bug/MapAtRuntime/EntityDTO5.cs @@ -4,25 +4,24 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDTOModel3 +namespace OmmitedDTOModel3; + +public class EntityDTO5 : BaseEntity { - public class EntityDTO5 : BaseEntity + public EntityDTO5() { - public EntityDTO5() - { - //this.Entities6 = new EntityDTO6(); - //this.TimeSlots = new EntityDTO23(); - //this.Entities5 = new EntityDTO5(); - } - - public Guid? Entity8Id { get; set; } - public EntityDTO8 Entity8 { get; set; } - public Guid? Entity17Id { get; set; } - public EntityDTO17 Entity17 { get; set; } - public Guid? Entity5Id { get; set; } - public EntityDTO5 Entity5Exception { get; set; } - public EntityDTO5 Entities5 { get; set; } - public EntityDTO6 Entities6 { get; set; } - public EntityDTO23 TimeSlots { get; set; } + //this.Entities6 = new EntityDTO6(); + //this.TimeSlots = new EntityDTO23(); + //this.Entities5 = new EntityDTO5(); } + + public Guid? Entity8Id { get; set; } + public EntityDTO8 Entity8 { get; set; } + public Guid? Entity17Id { get; set; } + public EntityDTO17 Entity17 { get; set; } + public Guid? Entity5Id { get; set; } + public EntityDTO5 Entity5Exception { get; set; } + public EntityDTO5 Entities5 { get; set; } + public EntityDTO6 Entities6 { get; set; } + public EntityDTO23 TimeSlots { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntime/EntityDTO6.cs b/src/UnitTests/Bug/MapAtRuntime/EntityDTO6.cs index ab46c495ca..9f9f5c8917 100644 --- a/src/UnitTests/Bug/MapAtRuntime/EntityDTO6.cs +++ b/src/UnitTests/Bug/MapAtRuntime/EntityDTO6.cs @@ -4,19 +4,18 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDTOModel3 +namespace OmmitedDTOModel3; + +public class EntityDTO6 : BaseEntity { - public class EntityDTO6 : BaseEntity + public EntityDTO6() { - public EntityDTO6() - { - //this.Entities12 = new EntityDTO12(); - } - - public Guid Entity5Id { get; set; } - public EntityDTO5 Entity5 { get; set; } - public Guid Entity20Id { get; set; } - public EntityDTO20 Entity20 { get; set; } - public EntityDTO12 Entities12 { get; set; } + //this.Entities12 = new EntityDTO12(); } + + public Guid Entity5Id { get; set; } + public EntityDTO5 Entity5 { get; set; } + public Guid Entity20Id { get; set; } + public EntityDTO20 Entity20 { get; set; } + public EntityDTO12 Entities12 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntime/EntityDTO7.cs b/src/UnitTests/Bug/MapAtRuntime/EntityDTO7.cs index bbc5a68c10..05b32e4af8 100644 --- a/src/UnitTests/Bug/MapAtRuntime/EntityDTO7.cs +++ b/src/UnitTests/Bug/MapAtRuntime/EntityDTO7.cs @@ -1,12 +1,11 @@ using System; -namespace OmmitedDTOModel3 +namespace OmmitedDTOModel3; + +public class EntityDTO7 : BaseEntity { - public class EntityDTO7 : BaseEntity - { - public Guid Entity25Id { get; set; } - public EntityDTO25 Entity25 { get; set; } - public Guid? Entity14Id { get; set; } - public EntityDTO14 Entity14 { get; set; } - } + public Guid Entity25Id { get; set; } + public EntityDTO25 Entity25 { get; set; } + public Guid? Entity14Id { get; set; } + public EntityDTO14 Entity14 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntime/EntityDTO8.cs b/src/UnitTests/Bug/MapAtRuntime/EntityDTO8.cs index e9e52de419..0bafd01b31 100644 --- a/src/UnitTests/Bug/MapAtRuntime/EntityDTO8.cs +++ b/src/UnitTests/Bug/MapAtRuntime/EntityDTO8.cs @@ -4,23 +4,22 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDTOModel3 +namespace OmmitedDTOModel3; + +public class EntityDTO8 : BaseEntity { - public class EntityDTO8 : BaseEntity + public EntityDTO8() { - public EntityDTO8() - { - this.Entities20 = new EntityDTO20(); - this.Entities22 = new EntityDTO22(); - this.Entities3 = new EntityDTO3(); - this.Entities11 = new EntityDTO11(); - this.Entities17 = new EntityDTO17(); - } - - public EntityDTO20 Entities20 { get; set; } - public EntityDTO17 Entities17 { get; set; } - public EntityDTO22 Entities22 { get; set; } - public EntityDTO3 Entities3 { get; set; } - public EntityDTO11 Entities11 { get; set; } + this.Entities20 = new EntityDTO20(); + this.Entities22 = new EntityDTO22(); + this.Entities3 = new EntityDTO3(); + this.Entities11 = new EntityDTO11(); + this.Entities17 = new EntityDTO17(); } + + public EntityDTO20 Entities20 { get; set; } + public EntityDTO17 Entities17 { get; set; } + public EntityDTO22 Entities22 { get; set; } + public EntityDTO3 Entities3 { get; set; } + public EntityDTO11 Entities11 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntime/EntityDTO9.cs b/src/UnitTests/Bug/MapAtRuntime/EntityDTO9.cs index 1eadd471d8..804aa77754 100644 --- a/src/UnitTests/Bug/MapAtRuntime/EntityDTO9.cs +++ b/src/UnitTests/Bug/MapAtRuntime/EntityDTO9.cs @@ -1,10 +1,9 @@ using System; -namespace OmmitedDTOModel3 +namespace OmmitedDTOModel3; + +public class EntityDTO9 : BaseEntity { - public class EntityDTO9 : BaseEntity - { - public Guid Entity3Id { get; set; } - public EntityDTO3 Entity3 { get; set; } - } + public Guid Entity3Id { get; set; } + public EntityDTO3 Entity3 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntime/MapAtRuntime.cs b/src/UnitTests/Bug/MapAtRuntime/MapAtRuntime.cs index 068994a516..9371e1ce46 100644 --- a/src/UnitTests/Bug/MapAtRuntime/MapAtRuntime.cs +++ b/src/UnitTests/Bug/MapAtRuntime/MapAtRuntime.cs @@ -4,116 +4,115 @@ using OmmitedDTOModel3; using Xunit; -namespace AutoMapper.UnitTests +namespace AutoMapper.UnitTests; + +public class MapAtRuntime : AutoMapperSpecBase { - public class MapAtRuntime : AutoMapperSpecBase + protected override MapperConfiguration CreateConfiguration() => new(cfg => { - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().ReverseMap(); - cfg.CreateMap().ReverseMap(); - cfg.CreateMap().ReverseMap(); - cfg.CreateMap().ReverseMap(); - cfg.CreateMap().ReverseMap(); - cfg.CreateMap().ReverseMap(); - cfg.CreateMap().ReverseMap(); - cfg.CreateMap().ReverseMap(); - cfg.CreateMap().ReverseMap(); - cfg.CreateMap().ReverseMap(); - cfg.CreateMap().ReverseMap(); - cfg.CreateMap().ReverseMap(); - cfg.CreateMap().ReverseMap(); - cfg.CreateMap().ReverseMap(); - cfg.CreateMap().ReverseMap(); - cfg.CreateMap().ReverseMap(); - cfg.CreateMap().ReverseMap(); - cfg.CreateMap().ReverseMap(); - cfg.CreateMap().ReverseMap(); - cfg.CreateMap().ReverseMap(); - cfg.CreateMap().ReverseMap(); - cfg.CreateMap().ReverseMap(); - cfg.CreateMap().ReverseMap(); - cfg.CreateMap().ReverseMap(); - cfg.CreateMap().ReverseMap(); - cfg.CreateMap().ReverseMap(); - //cfg.ForAllPropertyMaps(p => !p.SourceType.IsValueType, (pm, o) => o.MapAtRuntime()); - }); - - public class Initialize - { - Entity2 appointmentStatusHistory1; - Entity8 center1; - Entity12 insurance1; - Entity14 patient1; - Entity17 resource1; - Entity20 service1; - Entity22 speciality1; + cfg.CreateMap().ReverseMap(); + cfg.CreateMap().ReverseMap(); + cfg.CreateMap().ReverseMap(); + cfg.CreateMap().ReverseMap(); + cfg.CreateMap().ReverseMap(); + cfg.CreateMap().ReverseMap(); + cfg.CreateMap().ReverseMap(); + cfg.CreateMap().ReverseMap(); + cfg.CreateMap().ReverseMap(); + cfg.CreateMap().ReverseMap(); + cfg.CreateMap().ReverseMap(); + cfg.CreateMap().ReverseMap(); + cfg.CreateMap().ReverseMap(); + cfg.CreateMap().ReverseMap(); + cfg.CreateMap().ReverseMap(); + cfg.CreateMap().ReverseMap(); + cfg.CreateMap().ReverseMap(); + cfg.CreateMap().ReverseMap(); + cfg.CreateMap().ReverseMap(); + cfg.CreateMap().ReverseMap(); + cfg.CreateMap().ReverseMap(); + cfg.CreateMap().ReverseMap(); + cfg.CreateMap().ReverseMap(); + cfg.CreateMap().ReverseMap(); + cfg.CreateMap().ReverseMap(); + cfg.CreateMap().ReverseMap(); + //cfg.ForAllPropertyMaps(p => !p.SourceType.IsValueType, (pm, o) => o.MapAtRuntime()); + }); - public Initialize() - { - appointmentStatusHistory1 = new Entity2 { Id = Guid.NewGuid() }; - center1 = new Entity8 { Id = Guid.NewGuid() }; - insurance1 = new Entity12 { Id = Guid.NewGuid() }; - patient1 = new Entity14 { Id = Guid.NewGuid() }; - resource1 = new Entity17 { Id = Guid.NewGuid() }; - service1 = new Entity20 { Id = Guid.NewGuid() }; - speciality1 = new Entity22 { Id = Guid.NewGuid() }; + public class Initialize + { + Entity2 appointmentStatusHistory1; + Entity8 center1; + Entity12 insurance1; + Entity14 patient1; + Entity17 resource1; + Entity20 service1; + Entity22 speciality1; - service1.Entity22 = speciality1; - service1.Entity22Id = speciality1.Id; - } + public Initialize() + { + appointmentStatusHistory1 = new Entity2 { Id = Guid.NewGuid() }; + center1 = new Entity8 { Id = Guid.NewGuid() }; + insurance1 = new Entity12 { Id = Guid.NewGuid() }; + patient1 = new Entity14 { Id = Guid.NewGuid() }; + resource1 = new Entity17 { Id = Guid.NewGuid() }; + service1 = new Entity20 { Id = Guid.NewGuid() }; + speciality1 = new Entity22 { Id = Guid.NewGuid() }; - public Entity1 GenerateAppointment() - { - var appointment1 = new Entity1 { Id = Guid.NewGuid() }; - appointmentStatusHistory1.Entity1 = appointment1; - appointmentStatusHistory1.Entity1Id = appointment1.Id; - appointment1.Entity8 = center1; - appointment1.Entity8Id = center1.Id; - appointment1.Entity12 = insurance1; - appointment1.Entity12Id = insurance1.Id; - appointment1.Entity14 = patient1; - appointment1.Entity14Id = patient1.Id; - appointment1.Entity17 = resource1; - appointment1.Entity17Id = resource1.Id; - appointment1.Entity20 = service1; - appointment1.Entity20Id = service1.Id; - appointment1.Entity22 = speciality1; - appointment1.Entity22Id = speciality1.Id; - return appointment1; - } - } + service1.Entity22 = speciality1; + service1.Entity22Id = speciality1.Id; + } - [Fact] - public void ShouldNotBeSlow() + public Entity1 GenerateAppointment() { - //List of objects performing slow - //Entity1 - //Entity17 - //Entity25 - //Entity19 - //Entity15 - //Entity13 - //Entity7 - //Entity5 - //Entity2 - - var list = new List(); - var initialize = new Initialize(); - list.Add(initialize.GenerateAppointment()); - var appointmentsDTO = Mapper.Map>(list); - var list2 = new List(); - var entity = new Entity1(); - list2.Add(entity); - var DTOs = Mapper.Map>(list2); - var list3 = new List(); - var entity17 = new Entity17(); - list3.Add(entity17); - var DTOs17 = Mapper.Map>(list3); - var list4 = new List(); - var entity25 = new Entity25(); - list4.Add(entity25); - var DTOs25 = Mapper.Map>(list4); + var appointment1 = new Entity1 { Id = Guid.NewGuid() }; + appointmentStatusHistory1.Entity1 = appointment1; + appointmentStatusHistory1.Entity1Id = appointment1.Id; + appointment1.Entity8 = center1; + appointment1.Entity8Id = center1.Id; + appointment1.Entity12 = insurance1; + appointment1.Entity12Id = insurance1.Id; + appointment1.Entity14 = patient1; + appointment1.Entity14Id = patient1.Id; + appointment1.Entity17 = resource1; + appointment1.Entity17Id = resource1.Id; + appointment1.Entity20 = service1; + appointment1.Entity20Id = service1.Id; + appointment1.Entity22 = speciality1; + appointment1.Entity22Id = speciality1.Id; + return appointment1; } + } + + [Fact] + public void ShouldNotBeSlow() + { + //List of objects performing slow + //Entity1 + //Entity17 + //Entity25 + //Entity19 + //Entity15 + //Entity13 + //Entity7 + //Entity5 + //Entity2 + + var list = new List(); + var initialize = new Initialize(); + list.Add(initialize.GenerateAppointment()); + var appointmentsDTO = Mapper.Map>(list); + var list2 = new List(); + var entity = new Entity1(); + list2.Add(entity); + var DTOs = Mapper.Map>(list2); + var list3 = new List(); + var entity17 = new Entity17(); + list3.Add(entity17); + var DTOs17 = Mapper.Map>(list3); + var list4 = new List(); + var entity25 = new Entity25(); + list4.Add(entity25); + var DTOs25 = Mapper.Map>(list4); } } \ No newline at end of file diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/BaseEntity.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/BaseEntity.cs index 2b7847d662..c8336aa155 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/BaseEntity.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/BaseEntity.cs @@ -4,10 +4,9 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDatabaseModel3WithCollections +namespace OmmitedDatabaseModel3WithCollections; + +public class BaseEntity { - public class BaseEntity - { - public Guid Id { get; set; } - } + public Guid Id { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/BaseEntityDTO.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/BaseEntityDTO.cs index 614ef7bf79..1d66765d10 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/BaseEntityDTO.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/BaseEntityDTO.cs @@ -4,10 +4,9 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDTOModel3WithCollections +namespace OmmitedDTOModel3WithCollections; + +public class BaseEntity { - public class BaseEntity - { - public Guid Id { get; set; } - } + public Guid Id { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity1.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity1.cs index e0325f9a7b..b0324ddb29 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity1.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity1.cs @@ -4,27 +4,26 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDatabaseModel3WithCollections -{ - public class Entity1 : BaseEntity +namespace OmmitedDatabaseModel3WithCollections; + +public class Entity1 : BaseEntity +{ + public Entity1() { - public Entity1() - { - this.Entities2 = new List(); - } - public Guid Entity17Id { get; set; } - public Entity17 Entity17 { get; set; } - public Guid? Entity22Id { get; set; } - public Entity22 Entity22 { get; set; } - public Guid? Entity20Id { get; set; } - public Entity20 Entity20 { get; set; } - public Guid? Entity12Id { get; set; } - public Entity12 Entity12 { get; set; } - public Guid Entity14Id { get; set; } - public Entity14 Entity14 { get; set; } - public Guid Entity8Id { get; set; } - public Entity8 Entity8 { get; set; } - public ICollection Entities2 { get; set; } - public Entity2 Entity2 { get; set; } + this.Entities2 = new List(); } + public Guid Entity17Id { get; set; } + public Entity17 Entity17 { get; set; } + public Guid? Entity22Id { get; set; } + public Entity22 Entity22 { get; set; } + public Guid? Entity20Id { get; set; } + public Entity20 Entity20 { get; set; } + public Guid? Entity12Id { get; set; } + public Entity12 Entity12 { get; set; } + public Guid Entity14Id { get; set; } + public Entity14 Entity14 { get; set; } + public Guid Entity8Id { get; set; } + public Entity8 Entity8 { get; set; } + public ICollection Entities2 { get; set; } + public Entity2 Entity2 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity10.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity10.cs index 0443f6e559..6f864c6521 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity10.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity10.cs @@ -1,13 +1,12 @@ using System.Collections.Generic; -namespace OmmitedDatabaseModel3WithCollections +namespace OmmitedDatabaseModel3WithCollections; + +public class Entity10 : BaseEntity { - public class Entity10 : BaseEntity + public Entity10() { - public Entity10() - { - this.Entities11 = new List(); - } - public ICollection Entities11 { get; set; } + this.Entities11 = new List(); } + public ICollection Entities11 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity11.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity11.cs index aa48befff5..390512ff61 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity11.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity11.cs @@ -4,17 +4,16 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDatabaseModel3WithCollections +namespace OmmitedDatabaseModel3WithCollections; + +public class Entity11 : BaseEntity { - public class Entity11 : BaseEntity + public Entity11() { - public Entity11() - { - this.Entities10 = new List(); - this.Entities8 = new List(); - } - public ICollection Entities10 { get; set; } - public ICollection Entities8 { get; set; } - public Entity8 Entity8 { get; set; } + this.Entities10 = new List(); + this.Entities8 = new List(); } + public ICollection Entities10 { get; set; } + public ICollection Entities8 { get; set; } + public Entity8 Entity8 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity12.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity12.cs index 60df85d8df..d490c80c3c 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity12.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity12.cs @@ -4,18 +4,17 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDatabaseModel3WithCollections +namespace OmmitedDatabaseModel3WithCollections; + +public class Entity12 : BaseEntity { - public class Entity12 : BaseEntity + public Entity12() { - public Entity12() - { - this.Entities20 = new List(); - this.Entities14 = new List(); - this.Entities16 = new List(); - } - public ICollection Entities20 { get; set; } - public ICollection Entities16 { get; set; } - public ICollection Entities14 { get; set; } + this.Entities20 = new List(); + this.Entities14 = new List(); + this.Entities16 = new List(); } + public ICollection Entities20 { get; set; } + public ICollection Entities16 { get; set; } + public ICollection Entities14 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity13.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity13.cs index 732f76d7a4..6843010126 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity13.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity13.cs @@ -4,13 +4,12 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDatabaseModel3WithCollections +namespace OmmitedDatabaseModel3WithCollections; + +public class Entity13 : BaseEntity { - public class Entity13 : BaseEntity - { - public Guid Entity17Id { get; set; } - public Entity17 Entity17 { get; set; } - public Guid Entity8Id { get; set; } - public Entity8 Entity8 { get; set; } - } + public Guid Entity17Id { get; set; } + public Entity17 Entity17 { get; set; } + public Guid Entity8Id { get; set; } + public Entity8 Entity8 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity14.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity14.cs index 5d358c9637..34404f3ac8 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity14.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity14.cs @@ -5,17 +5,16 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDatabaseModel3WithCollections +namespace OmmitedDatabaseModel3WithCollections; + +public class Entity14 : BaseEntity { - public class Entity14 : BaseEntity + public Entity14() { - public Entity14() - { - this.Entities12 = new List(); - this.Entities1 = new List(); - } - - public ICollection Entities12 { get; set; } - public ICollection Entities1 { get; set; } + this.Entities12 = new List(); + this.Entities1 = new List(); } + + public ICollection Entities12 { get; set; } + public ICollection Entities1 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity15.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity15.cs index 7ef998a1cc..853f0aae06 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity15.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity15.cs @@ -4,11 +4,10 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDatabaseModel3WithCollections +namespace OmmitedDatabaseModel3WithCollections; + +public class Entity15 : BaseEntity { - public class Entity15 : BaseEntity - { - public Guid Entity17Id { get; set; } - public Entity17 Entity17 { get; set; } - } + public Guid Entity17Id { get; set; } + public Entity17 Entity17 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity16.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity16.cs index 1385b6f515..f4a7ae97c5 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity16.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity16.cs @@ -4,13 +4,12 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDatabaseModel3WithCollections +namespace OmmitedDatabaseModel3WithCollections; + +public class Entity16 : BaseEntity { - public class Entity16 : BaseEntity - { - public Guid Entity20Id { get; set; } - public Entity20 Entity20 { get; set; } - public Guid Entity12Id { get; set; } - public Entity12 Entity12 { get; set; } - } + public Guid Entity20Id { get; set; } + public Entity20 Entity20 { get; set; } + public Guid Entity12Id { get; set; } + public Entity12 Entity12 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity17.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity17.cs index fb1e9d3f26..a1fdd87b27 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity17.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity17.cs @@ -4,21 +4,20 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDatabaseModel3WithCollections +namespace OmmitedDatabaseModel3WithCollections; + +public class Entity17 :BaseEntity { - public class Entity17 :BaseEntity + public Entity17() { - public Entity17() - { - this.Entities20 = new List(); - this.Entities8 = new List(); - this.Entities5 = new List(); - this.Entities18 = new List(); - } - - public ICollection Entities20 { get; set; } - public ICollection Entities8 { get; set; } - public ICollection Entities5 { get; set; } - public ICollection Entities18 { get; set; } + this.Entities20 = new List(); + this.Entities8 = new List(); + this.Entities5 = new List(); + this.Entities18 = new List(); } + + public ICollection Entities20 { get; set; } + public ICollection Entities8 { get; set; } + public ICollection Entities5 { get; set; } + public ICollection Entities18 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity18.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity18.cs index 22b6de7d54..457b4864cb 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity18.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity18.cs @@ -1,12 +1,11 @@ using System; -namespace OmmitedDatabaseModel3WithCollections +namespace OmmitedDatabaseModel3WithCollections; + +public class Entity18 : BaseEntity { - public class Entity18 : BaseEntity - { - public Guid Entity17Id { get; set; } - public Entity17 Entity17 { get; set; } - public Guid Entity20Id { get; set; } - public Entity20 Entity20 { get; set; } - } + public Guid Entity17Id { get; set; } + public Entity17 Entity17 { get; set; } + public Guid Entity20Id { get; set; } + public Entity20 Entity20 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity19.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity19.cs index e0f45d1c64..77a91678f0 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity19.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity19.cs @@ -1,10 +1,9 @@ using System; -namespace OmmitedDatabaseModel3WithCollections +namespace OmmitedDatabaseModel3WithCollections; + +public class Entity19 : BaseEntity { - public class Entity19 : BaseEntity - { - public Guid Entity25Id { get; set; } - public Entity25 Entity25 { get; set; } - } + public Guid Entity25Id { get; set; } + public Entity25 Entity25 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity2.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity2.cs index 9f1b548773..4f613d2685 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity2.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity2.cs @@ -1,10 +1,9 @@ using System; -namespace OmmitedDatabaseModel3WithCollections +namespace OmmitedDatabaseModel3WithCollections; + +public class Entity2 : BaseEntity { - public class Entity2 : BaseEntity - { - public Guid Entity1Id { get; set; } - public Entity1 Entity1 { get; set; } - } + public Guid Entity1Id { get; set; } + public Entity1 Entity1 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity20.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity20.cs index ce523b0145..5d75810f16 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity20.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity20.cs @@ -4,31 +4,30 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDatabaseModel3WithCollections +namespace OmmitedDatabaseModel3WithCollections; + +public class Entity20 : BaseEntity { - public class Entity20 : BaseEntity + public Entity20() { - public Entity20() - { - this.Entities8 = new List(); - this.Entities26 = new List(); - this.Entities12 = new List(); - this.Entities17 = new List(); - this.Entities21 = new List(); - this.Entities16 = new List(); - } - - public Guid Entity3Id { get; set; } - public Entity3 Entity3 { get; set; } - public Guid Entity22Id { get; set; } - public Entity22 Entity22 { get; set; } - public ICollection Entities8 { get; set; } - public Entity8 Entity8 { get; set; } - public ICollection Entities26 { get; set; } - public ICollection Entities12 { get; set; } - public ICollection Entities17 { get; set; } - public Entity17 Entitys17 { get; set; } - public ICollection Entities21 { get; set; } - public ICollection Entities16 { get; set; } + this.Entities8 = new List(); + this.Entities26 = new List(); + this.Entities12 = new List(); + this.Entities17 = new List(); + this.Entities21 = new List(); + this.Entities16 = new List(); } + + public Guid Entity3Id { get; set; } + public Entity3 Entity3 { get; set; } + public Guid Entity22Id { get; set; } + public Entity22 Entity22 { get; set; } + public ICollection Entities8 { get; set; } + public Entity8 Entity8 { get; set; } + public ICollection Entities26 { get; set; } + public ICollection Entities12 { get; set; } + public ICollection Entities17 { get; set; } + public Entity17 Entitys17 { get; set; } + public ICollection Entities21 { get; set; } + public ICollection Entities16 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity21.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity21.cs index dea88ef68c..c014799a43 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity21.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity21.cs @@ -1,10 +1,9 @@ using System; -namespace OmmitedDatabaseModel3WithCollections +namespace OmmitedDatabaseModel3WithCollections; + +public class Entity21 : BaseEntity { - public class Entity21 : BaseEntity - { - public Guid Entity20Id { get; set; } - public Entity20 Entity20 { get; set; } - } + public Guid Entity20Id { get; set; } + public Entity20 Entity20 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity22.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity22.cs index d3c8243c85..8fa7ebe109 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity22.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity22.cs @@ -4,16 +4,15 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDatabaseModel3WithCollections +namespace OmmitedDatabaseModel3WithCollections; + +public class Entity22 : BaseEntity { - public class Entity22 : BaseEntity + public Entity22() { - public Entity22() - { - this.Entities20 = new List(); - this.Entities24 = new List(); - } - public ICollection Entities20 { get; set; } - public ICollection Entities24 { get; set; } + this.Entities20 = new List(); + this.Entities24 = new List(); } + public ICollection Entities20 { get; set; } + public ICollection Entities24 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity23.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity23.cs index 065a63f7be..0247fcda7f 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity23.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity23.cs @@ -4,11 +4,10 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDatabaseModel3WithCollections +namespace OmmitedDatabaseModel3WithCollections; + +public class Entity23 : BaseEntity { - public class Entity23 : BaseEntity - { - public Guid Entity5Id { get; set; } - public Entity5 Entity5 { get; set; } - } + public Guid Entity5Id { get; set; } + public Entity5 Entity5 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity24.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity24.cs index 2a3cdfae8a..0450397785 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity24.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity24.cs @@ -4,13 +4,12 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDatabaseModel3WithCollections +namespace OmmitedDatabaseModel3WithCollections; + +public class Entity24 : BaseEntity { - public class Entity24 : BaseEntity - { - public Guid Entity3Id { get; set; } - public Entity3 Entity3 { get; set; } - public Guid Entity22Id { get; set; } - public Entity22 Entity22 { get; set; } - } + public Guid Entity3Id { get; set; } + public Entity3 Entity3 { get; set; } + public Guid Entity22Id { get; set; } + public Entity22 Entity22 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity25.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity25.cs index da1fe61249..f14c91ec7a 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity25.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity25.cs @@ -5,19 +5,18 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDatabaseModel3WithCollections +namespace OmmitedDatabaseModel3WithCollections; + +public class Entity25 : BaseEntity { - public class Entity25 : BaseEntity + public Entity25() { - public Entity25() - { - this.Entities19 = new List(); - } - - public ICollection Entities19 { get; set; } - public Guid? Entity8Id { get; set; } - public Entity8 Entity8 { get; set; } - public Guid? Entity17Id { get; set; } - public Entity17 Entity17 { get; set; } + this.Entities19 = new List(); } + + public ICollection Entities19 { get; set; } + public Guid? Entity8Id { get; set; } + public Entity8 Entity8 { get; set; } + public Guid? Entity17Id { get; set; } + public Entity17 Entity17 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity26.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity26.cs index cf0532a1b1..217d6a2ac4 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity26.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity26.cs @@ -4,15 +4,14 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDatabaseModel3WithCollections +namespace OmmitedDatabaseModel3WithCollections; + +public class Entity26 : BaseEntity { - public class Entity26 : BaseEntity + public Entity26() { - public Entity26() - { - this.Entities20 = new List(); - } - - public ICollection Entities20 { get; set; } + this.Entities20 = new List(); } + + public ICollection Entities20 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity3.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity3.cs index 1e3b2192ac..8928c7edcf 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity3.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity3.cs @@ -4,16 +4,15 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDatabaseModel3WithCollections +namespace OmmitedDatabaseModel3WithCollections; + +public class Entity3 : BaseEntity { - public class Entity3 : BaseEntity + public Entity3() { - public Entity3() - { - this.Entities4 = new List(); - this.Entities8 = new List(); - } - public ICollection Entities4 { get; set; } - public ICollection Entities8 { get; set; } + this.Entities4 = new List(); + this.Entities8 = new List(); } + public ICollection Entities4 { get; set; } + public ICollection Entities8 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity4.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity4.cs index 250c6d5eeb..4461c11380 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity4.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity4.cs @@ -4,11 +4,10 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDatabaseModel3WithCollections +namespace OmmitedDatabaseModel3WithCollections; + +public class Entity4 : BaseEntity { - public class Entity4 : BaseEntity - { - public Guid Entity3Id { get; set; } - public Entity3 Entity3 { get; set; } - } + public Guid Entity3Id { get; set; } + public Entity3 Entity3 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity5.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity5.cs index c3f9a3c7c7..61fb742a7a 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity5.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity5.cs @@ -4,25 +4,24 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDatabaseModel3WithCollections +namespace OmmitedDatabaseModel3WithCollections; + +public class Entity5 : BaseEntity { - public class Entity5 : BaseEntity + public Entity5() { - public Entity5() - { - this.Entities6 = new List(); - this.TimeSlots = new List(); - this.Entities5 = new List(); - } - - public Guid? Entity8Id { get; set; } - public Entity8 Entity8 { get; set; } - public Guid? Entity17Id { get; set; } - public Entity17 Entity17 { get; set; } - public Guid? Entity5Id { get; set; } - public Entity5 Entity5Exception { get; set; } - public ICollection Entities5 { get; set; } - public List Entities6 { get; set; } - public ICollection TimeSlots { get; set; } + this.Entities6 = new List(); + this.TimeSlots = new List(); + this.Entities5 = new List(); } + + public Guid? Entity8Id { get; set; } + public Entity8 Entity8 { get; set; } + public Guid? Entity17Id { get; set; } + public Entity17 Entity17 { get; set; } + public Guid? Entity5Id { get; set; } + public Entity5 Entity5Exception { get; set; } + public ICollection Entities5 { get; set; } + public List Entities6 { get; set; } + public ICollection TimeSlots { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity6.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity6.cs index 63f485bcaf..2243e199a1 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity6.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity6.cs @@ -4,19 +4,18 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDatabaseModel3WithCollections +namespace OmmitedDatabaseModel3WithCollections; + +public class Entity6 : BaseEntity { - public class Entity6 : BaseEntity + public Entity6() { - public Entity6() - { - this.Entities12 = new List(); - } - - public Guid Entity5Id { get; set; } - public Entity5 Entity5 { get; set; } - public Guid Entity20Id { get; set; } - public Entity20 Entity20 { get; set; } - public ICollection Entities12 { get; set; } + this.Entities12 = new List(); } + + public Guid Entity5Id { get; set; } + public Entity5 Entity5 { get; set; } + public Guid Entity20Id { get; set; } + public Entity20 Entity20 { get; set; } + public ICollection Entities12 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity7.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity7.cs index cb485cfe2e..b202c329a6 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity7.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity7.cs @@ -1,12 +1,11 @@ using System; -namespace OmmitedDatabaseModel3WithCollections +namespace OmmitedDatabaseModel3WithCollections; + +public class Entity7 : BaseEntity { - public class Entity7 : BaseEntity - { - public Guid Entity25Id { get; set; } - public Entity25 Entity25 { get; set; } - public Guid? Entity14Id { get; set; } - public Entity14 Entity14 { get; set; } - } + public Guid Entity25Id { get; set; } + public Entity25 Entity25 { get; set; } + public Guid? Entity14Id { get; set; } + public Entity14 Entity14 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity8.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity8.cs index 939b751447..7821a568e8 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity8.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity8.cs @@ -4,26 +4,25 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDatabaseModel3WithCollections +namespace OmmitedDatabaseModel3WithCollections; + +public class Entity8 : BaseEntity { - public class Entity8 : BaseEntity + public Entity8() { - public Entity8() - { - this.Entities20 = new List(); - this.Entities22 = new List(); - this.Entities3 = new List(); - this.Entities11 = new List(); - this.Entities17 = new List(); - } - - public ICollection Entities20 { get; set; } - public ICollection Entities17 { get; set; } - public Entity17 Entity17 { get; set; } - public ICollection Entities22 { get; set; } - public Entity22 Entity22 { get; set; } - public ICollection Entities3 { get; set; } - public ICollection Entities11 { get; set; } - public Entity11 Entity11 { get; set; } + this.Entities20 = new List(); + this.Entities22 = new List(); + this.Entities3 = new List(); + this.Entities11 = new List(); + this.Entities17 = new List(); } + + public ICollection Entities20 { get; set; } + public ICollection Entities17 { get; set; } + public Entity17 Entity17 { get; set; } + public ICollection Entities22 { get; set; } + public Entity22 Entity22 { get; set; } + public ICollection Entities3 { get; set; } + public ICollection Entities11 { get; set; } + public Entity11 Entity11 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity9.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity9.cs index 1a29282e7f..dcae61ea4e 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity9.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity9.cs @@ -1,10 +1,9 @@ using System; -namespace OmmitedDatabaseModel3WithCollections +namespace OmmitedDatabaseModel3WithCollections; + +public class Entity9 : BaseEntity { - public class Entity9 : BaseEntity - { - public Guid Entity3Id { get; set; } - public Entity3 Entity3 { get; set; } - } + public Guid Entity3Id { get; set; } + public Entity3 Entity3 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO1.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO1.cs index 7e3718421f..f09571b68e 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO1.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO1.cs @@ -4,26 +4,25 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDTOModel3WithCollections -{ - public class EntityDTO1 : BaseEntity +namespace OmmitedDTOModel3WithCollections; + +public class EntityDTO1 : BaseEntity +{ + public EntityDTO1() { - public EntityDTO1() - { - this.Entities2 = new List(); - } - public Guid Entity17Id { get; set; } - public EntityDTO17 Entity17 { get; set; } - public Guid? Entity22Id { get; set; } - public EntityDTO22 Entity22 { get; set; } - public Guid? Entity20Id { get; set; } - public EntityDTO20 Entity20 { get; set; } - public Guid? Entity12Id { get; set; } - public EntityDTO12 Entity12 { get; set; } - public Guid Entity14Id { get; set; } - public EntityDTO14 Entity14 { get; set; } - public Guid Entity8Id { get; set; } - public EntityDTO8 Entity8 { get; set; } - public ICollection Entities2 { get; set; } + this.Entities2 = new List(); } + public Guid Entity17Id { get; set; } + public EntityDTO17 Entity17 { get; set; } + public Guid? Entity22Id { get; set; } + public EntityDTO22 Entity22 { get; set; } + public Guid? Entity20Id { get; set; } + public EntityDTO20 Entity20 { get; set; } + public Guid? Entity12Id { get; set; } + public EntityDTO12 Entity12 { get; set; } + public Guid Entity14Id { get; set; } + public EntityDTO14 Entity14 { get; set; } + public Guid Entity8Id { get; set; } + public EntityDTO8 Entity8 { get; set; } + public ICollection Entities2 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO10.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO10.cs index aa7235c145..44244cc43a 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO10.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO10.cs @@ -1,13 +1,12 @@ using System.Collections.Generic; -namespace OmmitedDTOModel3WithCollections +namespace OmmitedDTOModel3WithCollections; + +public class EntityDTO10 : BaseEntity { - public class EntityDTO10 : BaseEntity + public EntityDTO10() { - public EntityDTO10() - { - this.Entities11 = new List(); - } - public ICollection Entities11 { get; set; } + this.Entities11 = new List(); } + public ICollection Entities11 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO11.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO11.cs index 7c157eeb6f..f6c5555bd9 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO11.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO11.cs @@ -4,16 +4,15 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDTOModel3WithCollections +namespace OmmitedDTOModel3WithCollections; + +public class EntityDTO11 : BaseEntity { - public class EntityDTO11 : BaseEntity + public EntityDTO11() { - public EntityDTO11() - { - this.Entities10 = new List(); - this.Entities8 = new List(); - } - public ICollection Entities10 { get; set; } - public ICollection Entities8 { get; set; } + this.Entities10 = new List(); + this.Entities8 = new List(); } + public ICollection Entities10 { get; set; } + public ICollection Entities8 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO12.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO12.cs index d740892fa6..c246cd0e07 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO12.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO12.cs @@ -4,18 +4,17 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDTOModel3WithCollections +namespace OmmitedDTOModel3WithCollections; + +public class EntityDTO12 : BaseEntity { - public class EntityDTO12 : BaseEntity + public EntityDTO12() { - public EntityDTO12() - { - this.Entities20 = new List(); - this.Entities14 = new List(); - Entities16 = new List(); - } - public ICollection Entities20 { get; set; } - public ICollection Entities16 { get; set; } - public ICollection Entities14 { get; set; } + this.Entities20 = new List(); + this.Entities14 = new List(); + Entities16 = new List(); } + public ICollection Entities20 { get; set; } + public ICollection Entities16 { get; set; } + public ICollection Entities14 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO13.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO13.cs index b1926690dd..cbebb5abf6 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO13.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO13.cs @@ -4,13 +4,12 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDTOModel3WithCollections +namespace OmmitedDTOModel3WithCollections; + +public class EntityDTO13 : BaseEntity { - public class EntityDTO13 : BaseEntity - { - public Guid Entity17Id { get; set; } - public EntityDTO17 Entity17 { get; set; } - public Guid Entity8Id { get; set; } - public EntityDTO8 Entity8 { get; set; } - } + public Guid Entity17Id { get; set; } + public EntityDTO17 Entity17 { get; set; } + public Guid Entity8Id { get; set; } + public EntityDTO8 Entity8 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO14.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO14.cs index 16aebbad2d..6bfe3d4c18 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO14.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO14.cs @@ -5,18 +5,17 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDTOModel3WithCollections +namespace OmmitedDTOModel3WithCollections; + +public class EntityDTO14 : BaseEntity { - public class EntityDTO14 : BaseEntity + public EntityDTO14() { - public EntityDTO14() - { - this.Entities12 = new List(); - this.Entities1 = new List(); - } - - //public Address Address { get; set; } - public ICollection Entities12 { get; set; } - public ICollection Entities1 { get; set; } + this.Entities12 = new List(); + this.Entities1 = new List(); } + + //public Address Address { get; set; } + public ICollection Entities12 { get; set; } + public ICollection Entities1 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO15.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO15.cs index 757572536e..08df8bd252 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO15.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO15.cs @@ -4,14 +4,13 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDTOModel3WithCollections +namespace OmmitedDTOModel3WithCollections; + +public class EntityDTO15 : BaseEntity { - public class EntityDTO15 : BaseEntity + public EntityDTO15() { - public EntityDTO15() - { - } - public Guid Entity17Id { get; set; } - public EntityDTO17 Entity17 { get; set; } } + public Guid Entity17Id { get; set; } + public EntityDTO17 Entity17 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO16.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO16.cs index db5045a37c..c0b1329728 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO16.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO16.cs @@ -4,13 +4,12 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDTOModel3WithCollections +namespace OmmitedDTOModel3WithCollections; + +public class EntityDTO16 : BaseEntity { - public class EntityDTO16 : BaseEntity - { - public Guid Entity20Id { get; set; } - public EntityDTO20 Entity20 { get; set; } - public Guid Entity12Id { get; set; } - public EntityDTO12 Entity12 { get; set; } - } + public Guid Entity20Id { get; set; } + public EntityDTO20 Entity20 { get; set; } + public Guid Entity12Id { get; set; } + public EntityDTO12 Entity12 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO17.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO17.cs index c60894a015..2d4758121b 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO17.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO17.cs @@ -4,21 +4,20 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDTOModel3WithCollections +namespace OmmitedDTOModel3WithCollections; + +public class EntityDTO17 :BaseEntity { - public class EntityDTO17 :BaseEntity + public EntityDTO17() { - public EntityDTO17() - { - this.Entities20 = new List(); - this.Entities8 = new List(); - this.Entities5 = new List(); - this.Entities18 = new List(); - } - - public ICollection Entities20 { get; set; } - public ICollection Entities8 { get; set; } - public ICollection Entities5 { get; set; } - public ICollection Entities18 { get; set; } + this.Entities20 = new List(); + this.Entities8 = new List(); + this.Entities5 = new List(); + this.Entities18 = new List(); } + + public ICollection Entities20 { get; set; } + public ICollection Entities8 { get; set; } + public ICollection Entities5 { get; set; } + public ICollection Entities18 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO18.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO18.cs index ee7bac155e..9b2c875b1b 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO18.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO18.cs @@ -1,12 +1,11 @@ using System; -namespace OmmitedDTOModel3WithCollections +namespace OmmitedDTOModel3WithCollections; + +public class EntityDTO18 : BaseEntity { - public class EntityDTO18 : BaseEntity - { - public Guid Entity17Id { get; set; } - public EntityDTO17 Entity17 { get; set; } - public Guid Entity20Id { get; set; } - public EntityDTO20 Entity20 { get; set; } - } + public Guid Entity17Id { get; set; } + public EntityDTO17 Entity17 { get; set; } + public Guid Entity20Id { get; set; } + public EntityDTO20 Entity20 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO19.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO19.cs index 18e2bf014f..62452e666e 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO19.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO19.cs @@ -1,10 +1,9 @@ using System; -namespace OmmitedDTOModel3WithCollections +namespace OmmitedDTOModel3WithCollections; + +public class EntityDTO19 : BaseEntity { - public class EntityDTO19 : BaseEntity - { - public Guid Entity25Id { get; set; } - public EntityDTO25 Entity25 { get; set; } - } + public Guid Entity25Id { get; set; } + public EntityDTO25 Entity25 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO2.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO2.cs index dd772d9b27..c8353a33f7 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO2.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO2.cs @@ -1,10 +1,9 @@ using System; -namespace OmmitedDTOModel3WithCollections +namespace OmmitedDTOModel3WithCollections; + +public class EntityDTO2 : BaseEntity { - public class EntityDTO2 : BaseEntity - { - public Guid Entity1Id { get; set; } - public EntityDTO1 Entity1 { get; set; } - } + public Guid Entity1Id { get; set; } + public EntityDTO1 Entity1 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO20.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO20.cs index f6a3682e26..e5f0989991 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO20.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO20.cs @@ -4,29 +4,28 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDTOModel3WithCollections +namespace OmmitedDTOModel3WithCollections; + +public class EntityDTO20 : BaseEntity { - public class EntityDTO20 : BaseEntity + public EntityDTO20() { - public EntityDTO20() - { - this.Entities8 = new List(); - this.Entities26 = new List(); - this.Entities12 = new List(); - this.Entities17 = new List(); - this.Entities21 = new List(); - this.Entities16 = new List(); - } - - public Guid Entity3Id { get; set; } - public EntityDTO3 Entity3 { get; set; } - public Guid Entity22Id { get; set; } - public EntityDTO22 Entity22 { get; set; } - public ICollection Entities8 { get; set; } - public ICollection Entities26 { get; set; } - public ICollection Entities12 { get; set; } - public ICollection Entities17 { get; set; } - public ICollection Entities21 { get; set; } - public ICollection Entities16 { get; set; } + this.Entities8 = new List(); + this.Entities26 = new List(); + this.Entities12 = new List(); + this.Entities17 = new List(); + this.Entities21 = new List(); + this.Entities16 = new List(); } + + public Guid Entity3Id { get; set; } + public EntityDTO3 Entity3 { get; set; } + public Guid Entity22Id { get; set; } + public EntityDTO22 Entity22 { get; set; } + public ICollection Entities8 { get; set; } + public ICollection Entities26 { get; set; } + public ICollection Entities12 { get; set; } + public ICollection Entities17 { get; set; } + public ICollection Entities21 { get; set; } + public ICollection Entities16 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO21.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO21.cs index ae0b6d5a91..039b512cd8 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO21.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO21.cs @@ -1,10 +1,9 @@ using System; -namespace OmmitedDTOModel3WithCollections +namespace OmmitedDTOModel3WithCollections; + +public class EntityDTO21 : BaseEntity { - public class EntityDTO21 : BaseEntity - { - public Guid Entity20Id { get; set; } - public EntityDTO20 Entity20 { get; set; } - } + public Guid Entity20Id { get; set; } + public EntityDTO20 Entity20 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO22.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO22.cs index 33b2382745..1864ae00fb 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO22.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO22.cs @@ -4,16 +4,15 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDTOModel3WithCollections +namespace OmmitedDTOModel3WithCollections; + +public class EntityDTO22 : BaseEntity { - public class EntityDTO22 : BaseEntity + public EntityDTO22() { - public EntityDTO22() - { - this.Entities20 = new List(); - this.Entities24 = new List(); - } - public ICollection Entities20 { get; set; } - public ICollection Entities24 { get; set; } + this.Entities20 = new List(); + this.Entities24 = new List(); } + public ICollection Entities20 { get; set; } + public ICollection Entities24 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO23.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO23.cs index b6b10ab4f6..4747db899b 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO23.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO23.cs @@ -4,11 +4,10 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDTOModel3WithCollections +namespace OmmitedDTOModel3WithCollections; + +public class EntityDTO23 : BaseEntity { - public class EntityDTO23 : BaseEntity - { - public Guid Entity5Id { get; set; } - public EntityDTO5 Entity5 { get; set; } - } + public Guid Entity5Id { get; set; } + public EntityDTO5 Entity5 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO24.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO24.cs index ab7b48c61e..f890f92c28 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO24.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO24.cs @@ -4,13 +4,12 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDTOModel3WithCollections +namespace OmmitedDTOModel3WithCollections; + +public class EntityDTO24 : BaseEntity { - public class EntityDTO24 : BaseEntity - { - public Guid Entity3Id { get; set; } - public EntityDTO3 Entity3 { get; set; } - public Guid Entity22Id { get; set; } - public EntityDTO22 Entity22 { get; set; } - } + public Guid Entity3Id { get; set; } + public EntityDTO3 Entity3 { get; set; } + public Guid Entity22Id { get; set; } + public EntityDTO22 Entity22 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO25.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO25.cs index 1961eb36c4..01f1708fa2 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO25.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO25.cs @@ -5,19 +5,18 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDTOModel3WithCollections +namespace OmmitedDTOModel3WithCollections; + +public class EntityDTO25 : BaseEntity { - public class EntityDTO25 : BaseEntity + public EntityDTO25() { - public EntityDTO25() - { - this.Entities19 = new List(); - } - - public ICollection Entities19 { get; set; } - public Guid? Entity8Id { get; set; } - public EntityDTO8 Entity8 { get; set; } - public Guid? Entity17Id { get; set; } - public EntityDTO17 Entity17 { get; set; } + this.Entities19 = new List(); } + + public ICollection Entities19 { get; set; } + public Guid? Entity8Id { get; set; } + public EntityDTO8 Entity8 { get; set; } + public Guid? Entity17Id { get; set; } + public EntityDTO17 Entity17 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO26.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO26.cs index e1d68f19f3..f96868a675 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO26.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO26.cs @@ -4,15 +4,14 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDTOModel3WithCollections +namespace OmmitedDTOModel3WithCollections; + +public class EntityDTO26 : BaseEntity { - public class EntityDTO26 : BaseEntity + public EntityDTO26() { - public EntityDTO26() - { - this.Entities20 = new List(); - } - - public ICollection Entities20 { get; set; } + this.Entities20 = new List(); } + + public ICollection Entities20 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO3.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO3.cs index 01bc26f28b..dbb77257c9 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO3.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO3.cs @@ -4,16 +4,15 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDTOModel3WithCollections +namespace OmmitedDTOModel3WithCollections; + +public class EntityDTO3 : BaseEntity { - public class EntityDTO3 : BaseEntity + public EntityDTO3() { - public EntityDTO3() - { - this.Entities4 = new List(); - this.Entities8 = new List(); - } - public ICollection Entities4 { get; set; } - public ICollection Entities8 { get; set; } + this.Entities4 = new List(); + this.Entities8 = new List(); } + public ICollection Entities4 { get; set; } + public ICollection Entities8 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO4.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO4.cs index 6c8f4bd249..8fb3dc9a54 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO4.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO4.cs @@ -4,11 +4,10 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDTOModel3WithCollections +namespace OmmitedDTOModel3WithCollections; + +public class EntityDTO4 : BaseEntity { - public class EntityDTO4 : BaseEntity - { - public Guid Entity3Id { get; set; } - public EntityDTO3 Entity3 { get; set; } - } + public Guid Entity3Id { get; set; } + public EntityDTO3 Entity3 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO5.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO5.cs index 9a1421a0df..900004b725 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO5.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO5.cs @@ -4,25 +4,24 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDTOModel3WithCollections +namespace OmmitedDTOModel3WithCollections; + +public class EntityDTO5 : BaseEntity { - public class EntityDTO5 : BaseEntity + public EntityDTO5() { - public EntityDTO5() - { - this.Entities6 = new List(); - this.TimeSlots = new List(); - this.Entities5 = new List(); - } - - public Guid? Entity8Id { get; set; } - public EntityDTO8 Entity8 { get; set; } - public Guid? Entity17Id { get; set; } - public EntityDTO17 Entity17 { get; set; } - public Guid? Entity5Id { get; set; } - public EntityDTO5 Entity5Exception { get; set; } - public ICollection Entities5 { get; set; } - public List Entities6 { get; set; } - public ICollection TimeSlots { get; set; } + this.Entities6 = new List(); + this.TimeSlots = new List(); + this.Entities5 = new List(); } + + public Guid? Entity8Id { get; set; } + public EntityDTO8 Entity8 { get; set; } + public Guid? Entity17Id { get; set; } + public EntityDTO17 Entity17 { get; set; } + public Guid? Entity5Id { get; set; } + public EntityDTO5 Entity5Exception { get; set; } + public ICollection Entities5 { get; set; } + public List Entities6 { get; set; } + public ICollection TimeSlots { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO6.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO6.cs index 5cca04c88e..7eb43f7d8f 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO6.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO6.cs @@ -4,19 +4,18 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDTOModel3WithCollections +namespace OmmitedDTOModel3WithCollections; + +public class EntityDTO6 : BaseEntity { - public class EntityDTO6 : BaseEntity + public EntityDTO6() { - public EntityDTO6() - { - this.Entities12 = new List(); - } - - public Guid Entity5Id { get; set; } - public EntityDTO5 Entity5 { get; set; } - public Guid Entity20Id { get; set; } - public EntityDTO20 Entity20 { get; set; } - public ICollection Entities12 { get; set; } + this.Entities12 = new List(); } + + public Guid Entity5Id { get; set; } + public EntityDTO5 Entity5 { get; set; } + public Guid Entity20Id { get; set; } + public EntityDTO20 Entity20 { get; set; } + public ICollection Entities12 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO7.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO7.cs index 24697bebe3..82b35bc0cc 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO7.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO7.cs @@ -1,12 +1,11 @@ using System; -namespace OmmitedDTOModel3WithCollections +namespace OmmitedDTOModel3WithCollections; + +public class EntityDTO7 : BaseEntity { - public class EntityDTO7 : BaseEntity - { - public Guid Entity25Id { get; set; } - public EntityDTO25 Entity25 { get; set; } - public Guid? Entity14Id { get; set; } - public EntityDTO14 Entity14 { get; set; } - } + public Guid Entity25Id { get; set; } + public EntityDTO25 Entity25 { get; set; } + public Guid? Entity14Id { get; set; } + public EntityDTO14 Entity14 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO8.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO8.cs index 3b122d75f2..05f5249fa1 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO8.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO8.cs @@ -4,24 +4,23 @@ using System.Text; using System.Threading.Tasks; -namespace OmmitedDTOModel3WithCollections +namespace OmmitedDTOModel3WithCollections; + +public class EntityDTO8 : BaseEntity { - public class EntityDTO8 : BaseEntity + public EntityDTO8() { - public EntityDTO8() - { - this.Entities20 = new List(); - this.Entities22 = new List(); - this.Entities3 = new List(); - this.Entities11 = new List(); - this.Entities17 = new List(); - } - - public ICollection Entities20 { get; set; } - public ICollection Entities17 { get; set; } - public ICollection Entities22 { get; set; } - public ICollection Entities3 { get; set; } - public ICollection Entities11 { get; set; } - public EntityDTO11 Entity11 { get; set; } + this.Entities20 = new List(); + this.Entities22 = new List(); + this.Entities3 = new List(); + this.Entities11 = new List(); + this.Entities17 = new List(); } + + public ICollection Entities20 { get; set; } + public ICollection Entities17 { get; set; } + public ICollection Entities22 { get; set; } + public ICollection Entities3 { get; set; } + public ICollection Entities11 { get; set; } + public EntityDTO11 Entity11 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO9.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO9.cs index 2384e7bb78..1d081bc0c5 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO9.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO9.cs @@ -1,10 +1,9 @@ using System; -namespace OmmitedDTOModel3WithCollections +namespace OmmitedDTOModel3WithCollections; + +public class EntityDTO9 : BaseEntity { - public class EntityDTO9 : BaseEntity - { - public Guid Entity3Id { get; set; } - public EntityDTO3 Entity3 { get; set; } - } + public Guid Entity3Id { get; set; } + public EntityDTO3 Entity3 { get; set; } } diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/MapAtRuntimeWithCollections.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/MapAtRuntimeWithCollections.cs index 0c29eb2298..4facd6bf96 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/MapAtRuntimeWithCollections.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/MapAtRuntimeWithCollections.cs @@ -5,137 +5,136 @@ using OmmitedDTOModel3WithCollections; using Xunit; -namespace AutoMapper.UnitTests +namespace AutoMapper.UnitTests; + +public class MapAtRuntimeWithCollections : AutoMapperSpecBase { - public class MapAtRuntimeWithCollections : AutoMapperSpecBase + protected override MapperConfiguration CreateConfiguration() => new(cfg => { - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().ReverseMap(); - cfg.CreateMap().ReverseMap(); - cfg.CreateMap().ReverseMap(); - cfg.CreateMap().ReverseMap(); - cfg.CreateMap().ReverseMap(); - cfg.CreateMap().ReverseMap(); - cfg.CreateMap().ReverseMap(); - cfg.CreateMap().ReverseMap(); - cfg.CreateMap().ReverseMap(); - cfg.CreateMap().ReverseMap(); - cfg.CreateMap().ReverseMap(); - cfg.CreateMap().ReverseMap(); - cfg.CreateMap().ReverseMap(); - cfg.CreateMap().ReverseMap(); - cfg.CreateMap().ReverseMap(); - cfg.CreateMap().ReverseMap(); - cfg.CreateMap().ReverseMap(); - cfg.CreateMap().ReverseMap(); - cfg.CreateMap().ReverseMap(); - cfg.CreateMap().ReverseMap(); - cfg.CreateMap().ReverseMap(); - cfg.CreateMap().ReverseMap(); - cfg.CreateMap().ReverseMap(); - cfg.CreateMap().ReverseMap(); - cfg.CreateMap().ReverseMap(); - cfg.CreateMap().ReverseMap(); - //cfg.ForAllPropertyMaps(p => !p.SourceType.IsValueType, (pm, o) => o.MapAtRuntime()); - }); + cfg.CreateMap().ReverseMap(); + cfg.CreateMap().ReverseMap(); + cfg.CreateMap().ReverseMap(); + cfg.CreateMap().ReverseMap(); + cfg.CreateMap().ReverseMap(); + cfg.CreateMap().ReverseMap(); + cfg.CreateMap().ReverseMap(); + cfg.CreateMap().ReverseMap(); + cfg.CreateMap().ReverseMap(); + cfg.CreateMap().ReverseMap(); + cfg.CreateMap().ReverseMap(); + cfg.CreateMap().ReverseMap(); + cfg.CreateMap().ReverseMap(); + cfg.CreateMap().ReverseMap(); + cfg.CreateMap().ReverseMap(); + cfg.CreateMap().ReverseMap(); + cfg.CreateMap().ReverseMap(); + cfg.CreateMap().ReverseMap(); + cfg.CreateMap().ReverseMap(); + cfg.CreateMap().ReverseMap(); + cfg.CreateMap().ReverseMap(); + cfg.CreateMap().ReverseMap(); + cfg.CreateMap().ReverseMap(); + cfg.CreateMap().ReverseMap(); + cfg.CreateMap().ReverseMap(); + cfg.CreateMap().ReverseMap(); + //cfg.ForAllPropertyMaps(p => !p.SourceType.IsValueType, (pm, o) => o.MapAtRuntime()); + }); - public class Initialize - { - Entity2 appointmentStatusHistory1; - Entity8 center1; - Entity12 insurance1; - Entity14 patient1; - Entity17 resource1; - Entity20 service1; - Entity22 speciality1; + public class Initialize + { + Entity2 appointmentStatusHistory1; + Entity8 center1; + Entity12 insurance1; + Entity14 patient1; + Entity17 resource1; + Entity20 service1; + Entity22 speciality1; - public Initialize() - { - appointmentStatusHistory1 = new Entity2 { Id = Guid.NewGuid() }; - center1 = new Entity8 { Id = Guid.NewGuid() }; - insurance1 = new Entity12 { Id = Guid.NewGuid() }; - patient1 = new Entity14 { Id = Guid.NewGuid() }; - resource1 = new Entity17 { Id = Guid.NewGuid() }; - service1 = new Entity20 { Id = Guid.NewGuid() }; - speciality1 = new Entity22 { Id = Guid.NewGuid() }; + public Initialize() + { + appointmentStatusHistory1 = new Entity2 { Id = Guid.NewGuid() }; + center1 = new Entity8 { Id = Guid.NewGuid() }; + insurance1 = new Entity12 { Id = Guid.NewGuid() }; + patient1 = new Entity14 { Id = Guid.NewGuid() }; + resource1 = new Entity17 { Id = Guid.NewGuid() }; + service1 = new Entity20 { Id = Guid.NewGuid() }; + speciality1 = new Entity22 { Id = Guid.NewGuid() }; - speciality1.Entities20.Add(service1); + speciality1.Entities20.Add(service1); - service1.Entities8.Add(center1); - service1.Entities12.Add(insurance1); - service1.Entities17.Add(resource1); - service1.Entity22 = speciality1; - service1.Entity22Id = speciality1.Id; + service1.Entities8.Add(center1); + service1.Entities12.Add(insurance1); + service1.Entities17.Add(resource1); + service1.Entity22 = speciality1; + service1.Entity22Id = speciality1.Id; - resource1.Entities8.Add(center1); - resource1.Entities20.Add(service1); + resource1.Entities8.Add(center1); + resource1.Entities20.Add(service1); - patient1.Entities12.Add(insurance1); + patient1.Entities12.Add(insurance1); - insurance1.Entities14.Add(patient1); - insurance1.Entities20.Add(service1); + insurance1.Entities14.Add(patient1); + insurance1.Entities20.Add(service1); - center1.Entities17.Add(resource1); - center1.Entities20.Add(service1); - center1.Entities22.Add(speciality1); - } + center1.Entities17.Add(resource1); + center1.Entities20.Add(service1); + center1.Entities22.Add(speciality1); + } - public Entity1 GenerateAppointment() - { - var appointment1 = new Entity1 { Id = Guid.NewGuid() }; - appointmentStatusHistory1.Entity1 = appointment1; - appointmentStatusHistory1.Entity1Id = appointment1.Id; - appointment1.Entities2.Add(appointmentStatusHistory1); - appointment1.Entity8 = center1; - appointment1.Entity8Id = center1.Id; - appointment1.Entity12 = insurance1; - appointment1.Entity12Id = insurance1.Id; - appointment1.Entity14 = patient1; - appointment1.Entity14Id = patient1.Id; - appointment1.Entity17 = resource1; - appointment1.Entity17Id = resource1.Id; - appointment1.Entity20 = service1; - appointment1.Entity20Id = service1.Id; - appointment1.Entity22 = speciality1; - appointment1.Entity22Id = speciality1.Id; + public Entity1 GenerateAppointment() + { + var appointment1 = new Entity1 { Id = Guid.NewGuid() }; + appointmentStatusHistory1.Entity1 = appointment1; + appointmentStatusHistory1.Entity1Id = appointment1.Id; + appointment1.Entities2.Add(appointmentStatusHistory1); + appointment1.Entity8 = center1; + appointment1.Entity8Id = center1.Id; + appointment1.Entity12 = insurance1; + appointment1.Entity12Id = insurance1.Id; + appointment1.Entity14 = patient1; + appointment1.Entity14Id = patient1.Id; + appointment1.Entity17 = resource1; + appointment1.Entity17Id = resource1.Id; + appointment1.Entity20 = service1; + appointment1.Entity20Id = service1.Id; + appointment1.Entity22 = speciality1; + appointment1.Entity22Id = speciality1.Id; - patient1.Entities1.Add(appointment1); + patient1.Entities1.Add(appointment1); - return appointment1; - } - } + return appointment1; + } + } - [Fact] - public void ShouldNotBeSlow() - { - //List of objects performing slow - //Entity1 - //Entity17 - //Entity25 - //Entity19 - //Entity15 - //Entity13 - //Entity7 - //Entity5 - //Entity2 + [Fact] + public void ShouldNotBeSlow() + { + //List of objects performing slow + //Entity1 + //Entity17 + //Entity25 + //Entity19 + //Entity15 + //Entity13 + //Entity7 + //Entity5 + //Entity2 - var list = new List(); - var initialize = new Initialize(); - list.Add(initialize.GenerateAppointment()); - var appointmentsDTO = Mapper.Map>(list); - var list2 = new List(); - var entity = new Entity1(); - list2.Add(entity); - var DTOs = Mapper.Map>(list2); - var list3 = new List(); - var entity17 = new Entity17(); - list3.Add(entity17); - var DTOs17 = Mapper.Map>(list3); - var list4 = new List(); - var entity25 = new Entity25(); - list4.Add(entity25); - var DTOs25 = Mapper.Map>(list4); - } + var list = new List(); + var initialize = new Initialize(); + list.Add(initialize.GenerateAppointment()); + var appointmentsDTO = Mapper.Map>(list); + var list2 = new List(); + var entity = new Entity1(); + list2.Add(entity); + var DTOs = Mapper.Map>(list2); + var list3 = new List(); + var entity17 = new Entity17(); + list3.Add(entity17); + var DTOs17 = Mapper.Map>(list3); + var list4 = new List(); + var entity25 = new Entity25(); + list4.Add(entity25); + var DTOs25 = Mapper.Map>(list4); } } \ No newline at end of file diff --git a/src/UnitTests/Bug/MapExpandoObjectProperty.cs b/src/UnitTests/Bug/MapExpandoObjectProperty.cs index 93c0db9533..e36abd119f 100644 --- a/src/UnitTests/Bug/MapExpandoObjectProperty.cs +++ b/src/UnitTests/Bug/MapExpandoObjectProperty.cs @@ -1,30 +1,29 @@ using System.Dynamic; using Xunit; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class MapExpandoObjectProperty : AutoMapperSpecBase { - public class MapExpandoObjectProperty : AutoMapperSpecBase - { - class From - { - public ExpandoObject ExpandoObject { get; set; } - } + class From + { + public ExpandoObject ExpandoObject { get; set; } + } - class To - { - public ExpandoObject ExpandoObject { get; set; } - } + class To + { + public ExpandoObject ExpandoObject { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - }); - [Fact] - public void Should_work() - { - dynamic baseSettings = new ExpandoObject(); - var settings = Mapper.Map(new From { ExpandoObject = baseSettings}); - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + }); + [Fact] + public void Should_work() + { + dynamic baseSettings = new ExpandoObject(); + var settings = Mapper.Map(new From { ExpandoObject = baseSettings}); } } \ No newline at end of file diff --git a/src/UnitTests/Bug/MapFromClosureBug.cs b/src/UnitTests/Bug/MapFromClosureBug.cs index 216290bda7..51e3e34038 100644 --- a/src/UnitTests/Bug/MapFromClosureBug.cs +++ b/src/UnitTests/Bug/MapFromClosureBug.cs @@ -1,71 +1,70 @@ -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +using System; +using Shouldly; +using Xunit; + +public class MapFromClosureBug : NonValidatingSpecBase { - using System; - using Shouldly; - using Xunit; + private static readonly IDateProvider _dateProvider = new DateProvider(); - public class MapFromClosureBug : NonValidatingSpecBase + class DateProvider : IDateProvider { - private static readonly IDateProvider _dateProvider = new DateProvider(); + public DateTime CurrentRestaurantTime(Restaurant restaurant) => DateTime.Now; + } - class DateProvider : IDateProvider - { - public DateTime CurrentRestaurantTime(Restaurant restaurant) => DateTime.Now; - } + public interface IDateProvider + { + DateTime CurrentRestaurantTime(Restaurant restaurant); + } - public interface IDateProvider - { - DateTime CurrentRestaurantTime(Restaurant restaurant); - } + public class Result + { + public Booking Booking { get; set; } + } - public class Result - { - public Booking Booking { get; set; } - } + public class Restaurant + { + } - public class Restaurant - { - } + public class Booking + { + public Restaurant Restaurant { get; set; } - public class Booking + public int? CalculateTotal(DateTime currentTime) { - public Restaurant Restaurant { get; set; } - - public int? CalculateTotal(DateTime currentTime) - { - return null; - } + return null; } + } - public class ResultDto - { - public BookingDto Booking { get; set; } - } + public class ResultDto + { + public BookingDto Booking { get; set; } + } - public class BookingDto - { - public int? Total { get; set; } - } - [Fact] - public void Should_map_successfully() + public class BookingDto + { + public int? Total { get; set; } + } + [Fact] + public void Should_map_successfully() + { + var mapperConfiguration = new MapperConfiguration(cfg => { - var mapperConfiguration = new MapperConfiguration(cfg => - { - cfg.CreateMap(); - cfg.CreateMap() - .ForMember(d => d.Total, - o => o.MapFrom(b => b.CalculateTotal(_dateProvider.CurrentRestaurantTime(b.Restaurant)))); - }); + cfg.CreateMap(); + cfg.CreateMap() + .ForMember(d => d.Total, + o => o.MapFrom(b => b.CalculateTotal(_dateProvider.CurrentRestaurantTime(b.Restaurant)))); + }); - var mapper = mapperConfiguration.CreateMapper(); + var mapper = mapperConfiguration.CreateMapper(); - var result = new Result { Booking = new Booking() }; + var result = new Result { Booking = new Booking() }; - // Act - var dto = mapper.Map(result); + // Act + var dto = mapper.Map(result); - // Assert - dto.ShouldNotBeNull(); - } + // Assert + dto.ShouldNotBeNull(); } } \ No newline at end of file diff --git a/src/UnitTests/Bug/MapOverloadsWithDynamic.cs b/src/UnitTests/Bug/MapOverloadsWithDynamic.cs index ff7c013782..c37141b926 100644 --- a/src/UnitTests/Bug/MapOverloadsWithDynamic.cs +++ b/src/UnitTests/Bug/MapOverloadsWithDynamic.cs @@ -3,53 +3,52 @@ using System; using System.Dynamic; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class MapOverloadsWithDynamic : AutoMapperSpecBase { - public class MapOverloadsWithDynamic : AutoMapperSpecBase + Settings _settings; + + class SubSetting + { + public int SubTimeout { get; set; } + public string SubColour { get; set; } + } + + class Settings + { + public int Timeout { get; set; } + public string Colour { get; set; } + public SubSetting SubSettings { get; set; } + } + + protected override MapperConfiguration CreateConfiguration() => new(cfg => {}); + + protected override void Because_of() + { + // The SubSettings property is another ExpandoObject. + dynamic baseSettings = new ExpandoObject(); + baseSettings.Timeout = 1; + baseSettings.Colour = "Red"; + baseSettings.SubSettings = new ExpandoObject(); + baseSettings.SubSettings.SubTimeout = 11; + baseSettings.SubSettings.SubColour = "Green"; + + // Create another object we will map onto the one above. + // Notice that we do not set a Colour or SubColour property. + dynamic overrideSettings = new ExpandoObject(); + overrideSettings.Timeout = 2; + overrideSettings.SubSettings = new ExpandoObject(); + overrideSettings.SubSettings.SubTimeout = 22; + + _settings = Mapper.Map((object)baseSettings); + Mapper.Map((object)overrideSettings, _settings); + } + + [Fact] + public void Should_work() { - Settings _settings; - - class SubSetting - { - public int SubTimeout { get; set; } - public string SubColour { get; set; } - } - - class Settings - { - public int Timeout { get; set; } - public string Colour { get; set; } - public SubSetting SubSettings { get; set; } - } - - protected override MapperConfiguration CreateConfiguration() => new(cfg => {}); - - protected override void Because_of() - { - // The SubSettings property is another ExpandoObject. - dynamic baseSettings = new ExpandoObject(); - baseSettings.Timeout = 1; - baseSettings.Colour = "Red"; - baseSettings.SubSettings = new ExpandoObject(); - baseSettings.SubSettings.SubTimeout = 11; - baseSettings.SubSettings.SubColour = "Green"; - - // Create another object we will map onto the one above. - // Notice that we do not set a Colour or SubColour property. - dynamic overrideSettings = new ExpandoObject(); - overrideSettings.Timeout = 2; - overrideSettings.SubSettings = new ExpandoObject(); - overrideSettings.SubSettings.SubTimeout = 22; - - _settings = Mapper.Map((object)baseSettings); - Mapper.Map((object)overrideSettings, _settings); - } - - [Fact] - public void Should_work() - { - _settings.Timeout.ShouldBe(2); - _settings.SubSettings.SubTimeout.ShouldBe(22); - } + _settings.Timeout.ShouldBe(2); + _settings.SubSettings.SubTimeout.ShouldBe(22); } } \ No newline at end of file diff --git a/src/UnitTests/Bug/MappingInheritance.cs b/src/UnitTests/Bug/MappingInheritance.cs index 7e9b8656be..4ef97ba558 100644 --- a/src/UnitTests/Bug/MappingInheritance.cs +++ b/src/UnitTests/Bug/MappingInheritance.cs @@ -1,102 +1,101 @@  -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +using Shouldly; +using Xunit; + +public class MappingInheritance : AutoMapperSpecBase { - using Shouldly; - using Xunit; + private Entity testEntity; + private EditModel testModel; - public class MappingInheritance : AutoMapperSpecBase + protected override MapperConfiguration CreateConfiguration() => new(cfg => { - private Entity testEntity; - private EditModel testModel; - - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - cfg.CreateMap() - .ForMember(model => model.Value1, mce => mce.MapFrom(entity => entity.Value2)) - .ForMember(model => model.Value2, mce => mce.MapFrom(entity => entity.Value1)) - .Include() - .Include(); - cfg.CreateMap() - .ForMember(model => model.Value3, mce => mce.MapFrom(entity => entity.Value1 + entity.Value2)); - }); + cfg.CreateMap(); + cfg.CreateMap() + .ForMember(model => model.Value1, mce => mce.MapFrom(entity => entity.Value2)) + .ForMember(model => model.Value2, mce => mce.MapFrom(entity => entity.Value1)) + .Include() + .Include(); + cfg.CreateMap() + .ForMember(model => model.Value3, mce => mce.MapFrom(entity => entity.Value1 + entity.Value2)); + }); - protected override void Because_of() - { - testEntity = new Entity - { - Value1 = 1, - Value2 = 2, - }; - testModel = Mapper.Map(testEntity); - } - - [Fact] - public void AutoMapper_should_map_derived_types_properly() + protected override void Because_of() + { + testEntity = new Entity { - testEntity.Value1.ShouldBe(testModel.Value2); - testEntity.Value2.ShouldBe(testModel.Value1); - (testEntity.Value1 + testEntity.Value2).ShouldBe(testModel.Value3); - } + Value1 = 1, + Value2 = 2, + }; + testModel = Mapper.Map(testEntity); + } - public class Entity - { - public int Value1 { get; set; } - public int Value2 { get; set; } - } + [Fact] + public void AutoMapper_should_map_derived_types_properly() + { + testEntity.Value1.ShouldBe(testModel.Value2); + testEntity.Value2.ShouldBe(testModel.Value1); + (testEntity.Value1 + testEntity.Value2).ShouldBe(testModel.Value3); + } - public class BaseModel - { - public int Value1 { get; set; } - public int Value2 { get; set; } - } + public class Entity + { + public int Value1 { get; set; } + public int Value2 { get; set; } + } - public class EditModel : BaseModel - { - public int Value3 { get; set; } - } + public class BaseModel + { + public int Value1 { get; set; } + public int Value2 { get; set; } + } - public class ViewModel : BaseModel { } + public class EditModel : BaseModel + { + public int Value3 { get; set; } } - public class MappingInheritanceBug + public class ViewModel : BaseModel { } +} + +public class MappingInheritanceBug +{ + [Fact] + public void TestMethod1() { - [Fact] - public void TestMethod1() + var config = new MapperConfiguration(cfg => { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap() - .Include() - .Include(); - cfg.CreateMap(); - cfg.CreateMap(); - }); + cfg.CreateMap() + .Include() + .Include(); + cfg.CreateMap(); + cfg.CreateMap(); + }); - var mapper = config.CreateMapper(); + var mapper = config.CreateMapper(); - var mailOrder = new MailOrder() { NewId = 1 }; - var mapped = mapper.Map(mailOrder); + var mailOrder = new MailOrder() { NewId = 1 }; + var mapped = mapper.Map(mailOrder); - mapped.ShouldBeOfType(); - } + mapped.ShouldBeOfType(); + } - public abstract class Base - { - } + public abstract class Base + { + } - public class Order : Base { } - public class OnlineOrder : Order { } - public class MailOrder : Order - { - public int NewId { get; set; } - } + public class Order : Base { } + public class OnlineOrder : Order { } + public class MailOrder : Order + { + public int NewId { get; set; } + } - public class OrderDto { } - public class OnlineOrderDto : OrderDto { } - public class MailOrderDto : OrderDto - { - public int NewId { get; set; } - } + public class OrderDto { } + public class OnlineOrderDto : OrderDto { } + public class MailOrderDto : OrderDto + { + public int NewId { get; set; } } } diff --git a/src/UnitTests/Bug/MappingToAReadOnlyCollection.cs b/src/UnitTests/Bug/MappingToAReadOnlyCollection.cs index 72cb9322b0..ade438a7b3 100644 --- a/src/UnitTests/Bug/MappingToAReadOnlyCollection.cs +++ b/src/UnitTests/Bug/MappingToAReadOnlyCollection.cs @@ -3,53 +3,52 @@ using Shouldly; using Xunit; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class MappingToAReadOnlyCollection : AutoMapperSpecBase { - public class MappingToAReadOnlyCollection : AutoMapperSpecBase + private Destination _destination; + + public class Source + { + public int[] Values { get; set; } + public int[] Values2 { get; set; } + } + + public class Destination + { + public ReadOnlyCollection Values { get; set; } + public ReadOnlyCollection Values2 { get; set; } + } + + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + }); + + protected override void Because_of() { - private Destination _destination; - - public class Source - { - public int[] Values { get; set; } - public int[] Values2 { get; set; } - } - - public class Destination - { - public ReadOnlyCollection Values { get; set; } - public ReadOnlyCollection Values2 { get; set; } - } - - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - }); - - protected override void Because_of() - { - var source = new Source - { - Values = new[] {1, 2, 3, 4}, - Values2 = new[] {5, 6}, - }; - _destination = Mapper.Map(source); - } - - [Fact] - public void Should_map_the_list_of_source_items() - { - _destination.Values.ShouldNotBeNull(); - _destination.Values.ShouldBeOfLength(4); - _destination.Values.ShouldContain(1); - _destination.Values.ShouldContain(2); - _destination.Values.ShouldContain(3); - _destination.Values.ShouldContain(4); - - _destination.Values2.ShouldNotBeNull(); - _destination.Values2.ShouldBeOfLength(2); - _destination.Values2.ShouldContain(5); - _destination.Values2.ShouldContain(6); - } + var source = new Source + { + Values = new[] {1, 2, 3, 4}, + Values2 = new[] {5, 6}, + }; + _destination = Mapper.Map(source); + } + + [Fact] + public void Should_map_the_list_of_source_items() + { + _destination.Values.ShouldNotBeNull(); + _destination.Values.ShouldBeOfLength(4); + _destination.Values.ShouldContain(1); + _destination.Values.ShouldContain(2); + _destination.Values.ShouldContain(3); + _destination.Values.ShouldContain(4); + + _destination.Values2.ShouldNotBeNull(); + _destination.Values2.ShouldBeOfLength(2); + _destination.Values2.ShouldContain(5); + _destination.Values2.ShouldContain(6); } } \ No newline at end of file diff --git a/src/UnitTests/Bug/MemberListSourceAndForPath.cs b/src/UnitTests/Bug/MemberListSourceAndForPath.cs index 488c26e5b1..b55e1f2f01 100644 --- a/src/UnitTests/Bug/MemberListSourceAndForPath.cs +++ b/src/UnitTests/Bug/MemberListSourceAndForPath.cs @@ -1,49 +1,48 @@ using Shouldly; using Xunit; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class MemberListSourceAndForPath : AutoMapperSpecBase { - public class MemberListSourceAndForPath : AutoMapperSpecBase + bool _equal; + + public class TargetOuter + { + public TargetInner Inner { get; set; } + + // The properties below should be ignored, they are not relevant + public int Unrelated { get; set; } + public string AlsoUnrelated { get; set; } + } + + public class TargetInner + { + public string MyProp { get; set; } + } + + public class Input + { + public string Source { get; set; } + } + + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(MemberList.Source) + .ForPath(x => x.Inner.MyProp, opt => opt.MapFrom(x => x.Source)); + }); + + protected override void Because_of() + { + var input = new Input() {Source = "Hello World!"}; + var output = Mapper.Map(input); + + _equal = output.Inner.MyProp == input.Source; + } + + [Fact] + public void Should_ignore_destination_members() { - bool _equal; - - public class TargetOuter - { - public TargetInner Inner { get; set; } - - // The properties below should be ignored, they are not relevant - public int Unrelated { get; set; } - public string AlsoUnrelated { get; set; } - } - - public class TargetInner - { - public string MyProp { get; set; } - } - - public class Input - { - public string Source { get; set; } - } - - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(MemberList.Source) - .ForPath(x => x.Inner.MyProp, opt => opt.MapFrom(x => x.Source)); - }); - - protected override void Because_of() - { - var input = new Input() {Source = "Hello World!"}; - var output = Mapper.Map(input); - - _equal = output.Inner.MyProp == input.Source; - } - - [Fact] - public void Should_ignore_destination_members() - { - _equal.ShouldBeTrue(); - } + _equal.ShouldBeTrue(); } } \ No newline at end of file diff --git a/src/UnitTests/Bug/MemberNamedTypeBug.cs b/src/UnitTests/Bug/MemberNamedTypeBug.cs index 106fd0bf34..6ea0173b3a 100644 --- a/src/UnitTests/Bug/MemberNamedTypeBug.cs +++ b/src/UnitTests/Bug/MemberNamedTypeBug.cs @@ -1,62 +1,61 @@ using Xunit; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +using System; +using Shouldly; + +public class CorrectCtorIsPickedOnDestinationType : NonValidatingSpecBase { - using System; - using Shouldly; + public class SourceClass { } - public class CorrectCtorIsPickedOnDestinationType : NonValidatingSpecBase + public class DestinationClass { - public class SourceClass { } + public DestinationClass() { } - public class DestinationClass + // Since the name of the parameter is 'type', Automapper.TypeMap chooses SourceClass.GetType() + // to fulfill the dependency, causing an InvalidCastException during Mapper.Map() + public DestinationClass(Int32 type) { - public DestinationClass() { } - - // Since the name of the parameter is 'type', Automapper.TypeMap chooses SourceClass.GetType() - // to fulfill the dependency, causing an InvalidCastException during Mapper.Map() - public DestinationClass(Int32 type) - { - Type = type; - } - - public Int32 Type { get; private set; } + Type = type; } - protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.CreateMap()); + public Int32 Type { get; private set; } + } - [Fact] - public void Should_pick_a_ctor_which_best_matches() - { - var source = new SourceClass(); + protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.CreateMap()); - Mapper.Map(source); - } + [Fact] + public void Should_pick_a_ctor_which_best_matches() + { + var source = new SourceClass(); + + Mapper.Map(source); } - public class MemberNamedTypeWrong : AutoMapperSpecBase +} +public class MemberNamedTypeWrong : AutoMapperSpecBase +{ + public class SourceClass { - public class SourceClass - { - public string Type { get; set; } - } + public string Type { get; set; } + } - public class DestinationClass - { - public string Type { get; set; } - } + public class DestinationClass + { + public string Type { get; set; } + } - [Fact] - public void Should_map_correctly() + [Fact] + public void Should_map_correctly() + { + var source = new SourceClass { - var source = new SourceClass - { - Type = "Hello" - }; + Type = "Hello" + }; - var result = Mapper.Map(source); - result.Type.ShouldBe(source.Type); - } - - protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.CreateMap()); + var result = Mapper.Map(source); + result.Type.ShouldBe(source.Type); } + + protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.CreateMap()); } \ No newline at end of file diff --git a/src/UnitTests/Bug/MissingMapping.cs b/src/UnitTests/Bug/MissingMapping.cs index 0bc2968c01..2080cfaef0 100644 --- a/src/UnitTests/Bug/MissingMapping.cs +++ b/src/UnitTests/Bug/MissingMapping.cs @@ -1,29 +1,28 @@ -namespace AutoMapper.UnitTests -{ - using System.Linq; - using Shouldly; - using Xunit; - using QueryableExtensions; - using System; +namespace AutoMapper.UnitTests; + +using System.Linq; +using Shouldly; +using Xunit; +using QueryableExtensions; +using System; - public class MissingMapping : AutoMapperSpecBase +public class MissingMapping : AutoMapperSpecBase +{ + public class Source { - public class Source - { - public int Value { get; set; } - } + public int Value { get; set; } + } - public class Dest - { - public int Value { get; set; } - } + public class Dest + { + public int Value { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(c => { }); + protected override MapperConfiguration CreateConfiguration() => new(c => { }); - [Fact] - public void Can_not_map_unmapped_type() - { - new Action(() => Mapper.Map(new Source())).ShouldThrow(); - } - } + [Fact] + public void Can_not_map_unmapped_type() + { + new Action(() => Mapper.Map(new Source())).ShouldThrow(); + } } \ No newline at end of file diff --git a/src/UnitTests/Bug/MultiThreadingIssues.cs b/src/UnitTests/Bug/MultiThreadingIssues.cs index b361ee49d2..ff9b735f36 100644 --- a/src/UnitTests/Bug/MultiThreadingIssues.cs +++ b/src/UnitTests/Bug/MultiThreadingIssues.cs @@ -7,1190 +7,1189 @@ using AutoMapper.Internal.Mappers; using Xunit; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +using Shouldly; + +public class MultiThreadingIssues { - using Shouldly; + public class Type1 + { + public string FirstName; + public string MiddleName; + public string LastName; + public int Age; + } - public class MultiThreadingIssues + public class Type1Point3 { - public class Type1 - { - public string FirstName; - public string MiddleName; - public string LastName; - public int Age; - } + public string FirstName; + public string MiddleName; + public string LastName; + } - public class Type1Point3 - { - public string FirstName; - public string MiddleName; - public string LastName; - } + public class Type1Point2 + { + public string FirstName; + public string MiddleName; + } - public class Type1Point2 - { - public string FirstName; - public string MiddleName; - } + public class Type1Point1 + { + public string FirstName; + } - public class Type1Point1 - { - public string FirstName; - } + public class DestType + { + public string FirstName; + public string MiddleName; + public string LastName; + public int Age; + } - public class DestType - { - public string FirstName; - public string MiddleName; - public string LastName; - public int Age; - } + static int _done; + readonly ManualResetEvent _allDone = new ManualResetEvent(false); - static int _done; - readonly ManualResetEvent _allDone = new ManualResetEvent(false); + [Fact] + public void ShouldMapToNewISet() + { + const int threadCount = 13; - [Fact] - public void ShouldMapToNewISet() + for(int i = 0; i < threadCount; i++) { - const int threadCount = 13; - - for(int i = 0; i < threadCount; i++) - { - Task.Factory.StartNew(doMapping).ContinueWith( - a => + Task.Factory.StartNew(doMapping).ContinueWith( + a => + { + if(Interlocked.Increment(ref _done) == threadCount) { - if(Interlocked.Increment(ref _done) == threadCount) - { - _allDone.Set(); - } - - }); - } + _allDone.Set(); + } - _allDone.WaitOne(TimeSpan.FromSeconds(10)); + }); } - static void doMapping() - { - var source = createSource(); + _allDone.WaitOne(TimeSpan.FromSeconds(10)); + } - Debug.WriteLine(@"Mapping {0} on thread {1}", source.GetType(), Thread.CurrentThread.ManagedThreadId); + static void doMapping() + { + var source = createSource(); - var config = new MapperConfiguration(cfg => cfg.CreateMap(source.GetType(), typeof(DestType))); + Debug.WriteLine(@"Mapping {0} on thread {1}", source.GetType(), Thread.CurrentThread.ManagedThreadId); - DestType t2 = (DestType)config.CreateMapper().Map(source, source.GetType(), typeof(DestType)); - } + var config = new MapperConfiguration(cfg => cfg.CreateMap(source.GetType(), typeof(DestType))); - static readonly Random _random = new Random(); + DestType t2 = (DestType)config.CreateMapper().Map(source, source.GetType(), typeof(DestType)); + } - static object createSource() - { + static readonly Random _random = new Random(); - int n = _random.Next(0, 4); + static object createSource() + { + + int n = _random.Next(0, 4); - if(n == 0) + if(n == 0) + { + return new Type1 { - return new Type1 - { - Age = 12, - FirstName = @"Fred", - LastName = @"Smith", - MiddleName = @"G" - }; - } - if(n == 1) + Age = 12, + FirstName = @"Fred", + LastName = @"Smith", + MiddleName = @"G" + }; + } + if(n == 1) + { + return new Type1Point1() { - return new Type1Point1() - { - FirstName = @"Fred", - }; + FirstName = @"Fred", + }; - } - if(n == 2) + } + if(n == 2) + { + return new Type1Point2() { - return new Type1Point2() - { - FirstName = @"Fred", - MiddleName = @"G" - }; + FirstName = @"Fred", + MiddleName = @"G" + }; - } - if(n == 3) + } + if(n == 3) + { + return new Type1Point3() { - return new Type1Point3() - { - FirstName = @"Fred", - LastName = @"Smith", - MiddleName = @"G" - }; - - } + FirstName = @"Fred", + LastName = @"Smith", + MiddleName = @"G" + }; - throw new Exception(); } + + throw new Exception(); } +} - public class ResolveWithGenericMap +public class ResolveWithGenericMap +{ + public class SomeDtoA { - public class SomeDtoA - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string PropertyX { get; set; } - } + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string PropertyX { get; set; } + } - public class SomeDtoB - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string PropertyX { get; set; } - } + public class SomeDtoB + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string PropertyX { get; set; } + } - public class SomeDtoC - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string PropertyX { get; set; } - } + public class SomeDtoC + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string PropertyX { get; set; } + } - public class SomeDtoD - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string PropertyX { get; set; } - } + public class SomeDtoD + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string PropertyX { get; set; } + } - public class SomeDtoE - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string PropertyX { get; set; } - } + public class SomeDtoE + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string PropertyX { get; set; } + } - public class SomeDtoF - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string PropertyX { get; set; } - } + public class SomeDtoF + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string PropertyX { get; set; } + } - public class SomeDtoG - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string PropertyX { get; set; } - } + public class SomeDtoG + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string PropertyX { get; set; } + } - public class SomeDtoH - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string PropertyX { get; set; } - } + public class SomeDtoH + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string PropertyX { get; set; } + } - public class SomeDtoI - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string PropertyX { get; set; } - } + public class SomeDtoI + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string PropertyX { get; set; } + } - public class SomeDtoJ - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string PropertyX { get; set; } - } + public class SomeDtoJ + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string PropertyX { get; set; } + } - public class SomeDtoK - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string PropertyX { get; set; } - } + public class SomeDtoK + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string PropertyX { get; set; } + } - public class SomeDtoL - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string PropertyX { get; set; } - } + public class SomeDtoL + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string PropertyX { get; set; } + } - public class SomeDtoM - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string PropertyX { get; set; } - } + public class SomeDtoM + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string PropertyX { get; set; } + } - public class SomeDtoN - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string PropertyX { get; set; } - } + public class SomeDtoN + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string PropertyX { get; set; } + } - public class SomeDtoO - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string PropertyX { get; set; } - } + public class SomeDtoO + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string PropertyX { get; set; } + } - public class SomeDtoP - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string PropertyX { get; set; } - } + public class SomeDtoP + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string PropertyX { get; set; } + } - public class SomeEntityA - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string Property11 { get; set; } - } + public class SomeEntityA + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string Property11 { get; set; } + } - public class SomeEntityB - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string Property11 { get; set; } - } + public class SomeEntityB + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string Property11 { get; set; } + } - public class SomeEntityC - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string Property11 { get; set; } - } + public class SomeEntityC + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string Property11 { get; set; } + } - public class SomeEntityD - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string Property11 { get; set; } - } + public class SomeEntityD + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string Property11 { get; set; } + } - public class SomeEntityE - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string Property11 { get; set; } - } + public class SomeEntityE + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string Property11 { get; set; } + } - public class SomeEntityF - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string Property11 { get; set; } - } + public class SomeEntityF + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string Property11 { get; set; } + } - public class SomeEntityG - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string Property11 { get; set; } - } + public class SomeEntityG + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string Property11 { get; set; } + } - public class SomeEntityH - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string Property11 { get; set; } - } + public class SomeEntityH + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string Property11 { get; set; } + } - public class SomeEntityI - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string Property11 { get; set; } - } + public class SomeEntityI + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string Property11 { get; set; } + } - public class SomeEntityJ - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string Property11 { get; set; } - } + public class SomeEntityJ + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string Property11 { get; set; } + } - public class SomeEntityK - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string Property11 { get; set; } - } + public class SomeEntityK + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string Property11 { get; set; } + } - public class SomeEntityL - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string Property11 { get; set; } - } + public class SomeEntityL + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string Property11 { get; set; } + } - public class SomeEntityM - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string Property11 { get; set; } - } + public class SomeEntityM + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string Property11 { get; set; } + } - public class SomeEntityN - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string Property11 { get; set; } - } + public class SomeEntityN + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string Property11 { get; set; } + } - public class SomeEntityO - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string Property11 { get; set; } - } + public class SomeEntityO + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string Property11 { get; set; } + } - public class SomeEntityP - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string Property11 { get; set; } - } + public class SomeEntityP + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string Property11 { get; set; } + } - public class Entity - { - public T Data { get; set; } - } + public class Entity + { + public T Data { get; set; } + } - public class Dto - { - public T Data { get; set; } - public int Value { get; set; } - } + public class Dto + { + public T Data { get; set; } + public int Value { get; set; } + } - [Fact] - public void Should_work() - { - var sourceType = typeof(Entity<>); - var destinationType = typeof(Dto<>); - var c = new MapperConfiguration(cfg => - { - cfg.CreateMap(sourceType, destinationType).ForMember("Value", o => o.Ignore()); - }); - var types = new[]{ - new[] { typeof(SomeEntityA), typeof(SomeDtoA) }, - new[] { typeof(SomeEntityB), typeof(SomeDtoB) }, - new[] { typeof(SomeEntityC), typeof(SomeDtoC) }, - new[] { typeof(SomeEntityD), typeof(SomeDtoD) }, - new[] { typeof(SomeEntityE), typeof(SomeDtoE) }, - new[] { typeof(SomeEntityF), typeof(SomeDtoF) }, - new[] { typeof(SomeEntityG), typeof(SomeDtoG) }, - new[] { typeof(SomeEntityH), typeof(SomeDtoH) }, - new[] { typeof(SomeEntityI), typeof(SomeDtoI) }, - new[] { typeof(SomeEntityJ), typeof(SomeDtoJ) }, - new[] { typeof(SomeEntityK), typeof(SomeDtoK) }, - new[] { typeof(SomeEntityL), typeof(SomeDtoL) }, - new[] { typeof(SomeEntityM), typeof(SomeDtoM) }, - new[] { typeof(SomeEntityN), typeof(SomeDtoN) }, - new[] { typeof(SomeEntityO), typeof(SomeDtoO) }, - new[] { typeof(SomeEntityP), typeof(SomeDtoP) }, - }; - var tasks = - types - .Concat(types.Select(t => t.Reverse().ToArray())) - .Select(t=>(SourceType: sourceType.MakeGenericType(t[0]), DestinationType: destinationType.MakeGenericType(t[1]))) - .ToArray() - .Select(s => Task.Factory.StartNew(() => c.ResolveTypeMap(s.SourceType, s.DestinationType))) - .ToArray(); - Task.WaitAll(tasks); - } + [Fact] + public void Should_work() + { + var sourceType = typeof(Entity<>); + var destinationType = typeof(Dto<>); + var c = new MapperConfiguration(cfg => + { + cfg.CreateMap(sourceType, destinationType).ForMember("Value", o => o.Ignore()); + }); + var types = new[]{ + new[] { typeof(SomeEntityA), typeof(SomeDtoA) }, + new[] { typeof(SomeEntityB), typeof(SomeDtoB) }, + new[] { typeof(SomeEntityC), typeof(SomeDtoC) }, + new[] { typeof(SomeEntityD), typeof(SomeDtoD) }, + new[] { typeof(SomeEntityE), typeof(SomeDtoE) }, + new[] { typeof(SomeEntityF), typeof(SomeDtoF) }, + new[] { typeof(SomeEntityG), typeof(SomeDtoG) }, + new[] { typeof(SomeEntityH), typeof(SomeDtoH) }, + new[] { typeof(SomeEntityI), typeof(SomeDtoI) }, + new[] { typeof(SomeEntityJ), typeof(SomeDtoJ) }, + new[] { typeof(SomeEntityK), typeof(SomeDtoK) }, + new[] { typeof(SomeEntityL), typeof(SomeDtoL) }, + new[] { typeof(SomeEntityM), typeof(SomeDtoM) }, + new[] { typeof(SomeEntityN), typeof(SomeDtoN) }, + new[] { typeof(SomeEntityO), typeof(SomeDtoO) }, + new[] { typeof(SomeEntityP), typeof(SomeDtoP) }, + }; + var tasks = + types + .Concat(types.Select(t => t.Reverse().ToArray())) + .Select(t=>(SourceType: sourceType.MakeGenericType(t[0]), DestinationType: destinationType.MakeGenericType(t[1]))) + .ToArray() + .Select(s => Task.Factory.StartNew(() => c.ResolveTypeMap(s.SourceType, s.DestinationType))) + .ToArray(); + Task.WaitAll(tasks); } +} - public class ResolveGenericTypeMapThreadingIssues +public class ResolveGenericTypeMapThreadingIssues +{ + public class SomeDtoA { - public class SomeDtoA - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string PropertyX { get; set; } - } + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string PropertyX { get; set; } + } - public class SomeDtoB - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string PropertyX { get; set; } - } + public class SomeDtoB + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string PropertyX { get; set; } + } - public class SomeDtoC - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string PropertyX { get; set; } - } + public class SomeDtoC + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string PropertyX { get; set; } + } - public class SomeDtoD - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string PropertyX { get; set; } - } + public class SomeDtoD + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string PropertyX { get; set; } + } - public class SomeDtoE - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string PropertyX { get; set; } - } + public class SomeDtoE + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string PropertyX { get; set; } + } - public class SomeDtoF - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string PropertyX { get; set; } - } + public class SomeDtoF + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string PropertyX { get; set; } + } - public class SomeDtoG - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string PropertyX { get; set; } - } + public class SomeDtoG + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string PropertyX { get; set; } + } - public class SomeDtoH - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string PropertyX { get; set; } - } + public class SomeDtoH + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string PropertyX { get; set; } + } - public class SomeDtoI - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string PropertyX { get; set; } - } + public class SomeDtoI + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string PropertyX { get; set; } + } - public class SomeDtoJ - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string PropertyX { get; set; } - } + public class SomeDtoJ + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string PropertyX { get; set; } + } - public class SomeDtoK - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string PropertyX { get; set; } - } + public class SomeDtoK + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string PropertyX { get; set; } + } - public class SomeDtoL - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string PropertyX { get; set; } - } + public class SomeDtoL + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string PropertyX { get; set; } + } - public class SomeDtoM - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string PropertyX { get; set; } - } + public class SomeDtoM + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string PropertyX { get; set; } + } - public class SomeDtoN - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string PropertyX { get; set; } - } + public class SomeDtoN + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string PropertyX { get; set; } + } - public class SomeDtoO - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string PropertyX { get; set; } - } + public class SomeDtoO + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string PropertyX { get; set; } + } - public class SomeDtoP - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string PropertyX { get; set; } - } + public class SomeDtoP + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string PropertyX { get; set; } + } - public class SomeEntityA - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string Property11 { get; set; } - } + public class SomeEntityA + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string Property11 { get; set; } + } - public class SomeEntityB - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string Property11 { get; set; } - } + public class SomeEntityB + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string Property11 { get; set; } + } - public class SomeEntityC - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string Property11 { get; set; } - } + public class SomeEntityC + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string Property11 { get; set; } + } - public class SomeEntityD - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string Property11 { get; set; } - } + public class SomeEntityD + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string Property11 { get; set; } + } - public class SomeEntityE - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string Property11 { get; set; } - } + public class SomeEntityE + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string Property11 { get; set; } + } - public class SomeEntityF - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string Property11 { get; set; } - } + public class SomeEntityF + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string Property11 { get; set; } + } - public class SomeEntityG - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string Property11 { get; set; } - } + public class SomeEntityG + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string Property11 { get; set; } + } - public class SomeEntityH - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string Property11 { get; set; } - } + public class SomeEntityH + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string Property11 { get; set; } + } - public class SomeEntityI - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string Property11 { get; set; } - } + public class SomeEntityI + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string Property11 { get; set; } + } - public class SomeEntityJ - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string Property11 { get; set; } - } + public class SomeEntityJ + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string Property11 { get; set; } + } - public class SomeEntityK - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string Property11 { get; set; } - } + public class SomeEntityK + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string Property11 { get; set; } + } - public class SomeEntityL - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string Property11 { get; set; } - } + public class SomeEntityL + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string Property11 { get; set; } + } - public class SomeEntityM - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string Property11 { get; set; } - } + public class SomeEntityM + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string Property11 { get; set; } + } - public class SomeEntityN - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string Property11 { get; set; } - } + public class SomeEntityN + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string Property11 { get; set; } + } - public class SomeEntityO - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string Property11 { get; set; } - } + public class SomeEntityO + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string Property11 { get; set; } + } - public class SomeEntityP - { - public string Property1 { get; set; } - public string Property21 { get; set; } - public string Property3 { get; set; } - public string Property4 { get; set; } - public string Property5 { get; set; } - public string Property6 { get; set; } - public string Property7 { get; set; } - public string Property8 { get; set; } - public string Property9 { get; set; } - public string Property10 { get; set; } - public string Property11 { get; set; } - } + public class SomeEntityP + { + public string Property1 { get; set; } + public string Property21 { get; set; } + public string Property3 { get; set; } + public string Property4 { get; set; } + public string Property5 { get; set; } + public string Property6 { get; set; } + public string Property7 { get; set; } + public string Property8 { get; set; } + public string Property9 { get; set; } + public string Property10 { get; set; } + public string Property11 { get; set; } + } - public class Entity - { - public T Data { get; set; } - } + public class Entity + { + public T Data { get; set; } + } - public class Dto - { - public T Data { get; set; } - public int Value { get; set; } - } + public class Dto + { + public T Data { get; set; } + public int Value { get; set; } + } - [Fact] - public void Should_work() - { - var sourceType = typeof(Entity<>); - var destinationType = typeof(Dto<>); - var c = new MapperConfiguration(cfg => - { - cfg.CreateMap(sourceType, destinationType).ForMember("Value", o => o.Ignore()); - }); - var mapper = c.CreateMapper(); - var types = new[]{ - new[] { typeof(SomeEntityA), typeof(SomeDtoA) }, - new[] { typeof(SomeEntityB), typeof(SomeDtoB) }, - new[] { typeof(SomeEntityC), typeof(SomeDtoC) }, - new[] { typeof(SomeEntityD), typeof(SomeDtoD) }, - new[] { typeof(SomeEntityE), typeof(SomeDtoE) }, - new[] { typeof(SomeEntityF), typeof(SomeDtoF) }, - new[] { typeof(SomeEntityG), typeof(SomeDtoG) }, - new[] { typeof(SomeEntityH), typeof(SomeDtoH) }, - new[] { typeof(SomeEntityI), typeof(SomeDtoI) }, - new[] { typeof(SomeEntityJ), typeof(SomeDtoJ) }, - new[] { typeof(SomeEntityK), typeof(SomeDtoK) }, - new[] { typeof(SomeEntityL), typeof(SomeDtoL) }, - new[] { typeof(SomeEntityM), typeof(SomeDtoM) }, - new[] { typeof(SomeEntityN), typeof(SomeDtoN) }, - new[] { typeof(SomeEntityO), typeof(SomeDtoO) }, - new[] { typeof(SomeEntityP), typeof(SomeDtoP) }, - }; - var tasks = - types - .Concat(types.Select(t => t.Reverse().ToArray())) - .Select(t=>(SourceType: sourceType.MakeGenericType(t[0]), DestinationType: destinationType.MakeGenericType(t[1]))) - .ToArray() - .Select(s => Task.Factory.StartNew(() => mapper.Map(null, s.SourceType, s.DestinationType))) - .ToArray(); - Task.WaitAll(tasks); - } + [Fact] + public void Should_work() + { + var sourceType = typeof(Entity<>); + var destinationType = typeof(Dto<>); + var c = new MapperConfiguration(cfg => + { + cfg.CreateMap(sourceType, destinationType).ForMember("Value", o => o.Ignore()); + }); + var mapper = c.CreateMapper(); + var types = new[]{ + new[] { typeof(SomeEntityA), typeof(SomeDtoA) }, + new[] { typeof(SomeEntityB), typeof(SomeDtoB) }, + new[] { typeof(SomeEntityC), typeof(SomeDtoC) }, + new[] { typeof(SomeEntityD), typeof(SomeDtoD) }, + new[] { typeof(SomeEntityE), typeof(SomeDtoE) }, + new[] { typeof(SomeEntityF), typeof(SomeDtoF) }, + new[] { typeof(SomeEntityG), typeof(SomeDtoG) }, + new[] { typeof(SomeEntityH), typeof(SomeDtoH) }, + new[] { typeof(SomeEntityI), typeof(SomeDtoI) }, + new[] { typeof(SomeEntityJ), typeof(SomeDtoJ) }, + new[] { typeof(SomeEntityK), typeof(SomeDtoK) }, + new[] { typeof(SomeEntityL), typeof(SomeDtoL) }, + new[] { typeof(SomeEntityM), typeof(SomeDtoM) }, + new[] { typeof(SomeEntityN), typeof(SomeDtoN) }, + new[] { typeof(SomeEntityO), typeof(SomeDtoO) }, + new[] { typeof(SomeEntityP), typeof(SomeDtoP) }, + }; + var tasks = + types + .Concat(types.Select(t => t.Reverse().ToArray())) + .Select(t=>(SourceType: sourceType.MakeGenericType(t[0]), DestinationType: destinationType.MakeGenericType(t[1]))) + .ToArray() + .Select(s => Task.Factory.StartNew(() => mapper.Map(null, s.SourceType, s.DestinationType))) + .ToArray(); + Task.WaitAll(tasks); } } \ No newline at end of file diff --git a/src/UnitTests/Bug/MultidimensionalArrays.cs b/src/UnitTests/Bug/MultidimensionalArrays.cs index 0a5d0ba94e..48599f34eb 100644 --- a/src/UnitTests/Bug/MultidimensionalArrays.cs +++ b/src/UnitTests/Bug/MultidimensionalArrays.cs @@ -5,77 +5,76 @@ using System; using System.Linq; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class MultidimensionalArrays : AutoMapperSpecBase { - public class MultidimensionalArrays : AutoMapperSpecBase - { - const int SomeValue = 154; - Source _e = new Source(SomeValue); - Destination[,] _destination; - Source[,] _source; + const int SomeValue = 154; + Source _e = new Source(SomeValue); + Destination[,] _destination; + Source[,] _source; - public class Source + public class Source + { + public Source(int value) { - public Source(int value) - { - Value = value; - } - public int Value { get; set; } + Value = value; } + public int Value { get; set; } + } - public class Destination - { - public int Value { get; set; } - } + public class Destination + { + public int Value { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + }); - protected override void Because_of() - { - _source = new[,] { { _e, _e, new Source(2) }, { _e, new Source(11), _e }, { new Source(20), _e, _e }, {_e, _e, _e } }; - _destination = Mapper.Map(_source); - } + protected override void Because_of() + { + _source = new[,] { { _e, _e, new Source(2) }, { _e, new Source(11), _e }, { new Source(20), _e, _e }, {_e, _e, _e } }; + _destination = Mapper.Map(_source); + } - [Fact] - public void Should_map_multidimensional_array() - { - _destination.GetLength(0).ShouldBe(_source.GetLength(0)); - _destination.GetLength(1).ShouldBe(_source.GetLength(1)); - _destination[0, 0].Value.ShouldBe(SomeValue); - _destination[0, 2].Value.ShouldBe(2); - _destination[1, 1].Value.ShouldBe(11); - _destination[2, 0].Value.ShouldBe(20); - _destination[3, 2].Value.ShouldBe(SomeValue); - } + [Fact] + public void Should_map_multidimensional_array() + { + _destination.GetLength(0).ShouldBe(_source.GetLength(0)); + _destination.GetLength(1).ShouldBe(_source.GetLength(1)); + _destination[0, 0].Value.ShouldBe(SomeValue); + _destination[0, 2].Value.ShouldBe(2); + _destination[1, 1].Value.ShouldBe(11); + _destination[2, 0].Value.ShouldBe(20); + _destination[3, 2].Value.ShouldBe(SomeValue); } +} - public class FillMultidimensionalArray : NonValidatingSpecBase +public class FillMultidimensionalArray : NonValidatingSpecBase +{ + int[,] _source; + MultidimensionalArrayFiller _filler; + protected override void Because_of() { - int[,] _source; - MultidimensionalArrayFiller _filler; - protected override void Because_of() + _source = new int[4,3]; + _filler = new MultidimensionalArrayFiller(_source); + for(int index = 0; index < _source.Length; index++) { - _source = new int[4,3]; - _filler = new MultidimensionalArrayFiller(_source); - for(int index = 0; index < _source.Length; index++) - { - _filler.NewValue(index); - } + _filler.NewValue(index); } + } - [Fact] - public void Should_set_values_in_array() + [Fact] + public void Should_set_values_in_array() + { + int index = 0; + foreach(var value in _source) { - int index = 0; - foreach(var value in _source) - { - value.ShouldBe(index); - index++; - } - index.ShouldBe(_source.Length); + value.ShouldBe(index); + index++; } + index.ShouldBe(_source.Length); } } \ No newline at end of file diff --git a/src/UnitTests/Bug/MultipleInterfaceInheritance.cs b/src/UnitTests/Bug/MultipleInterfaceInheritance.cs index 3dc4773bdd..a75bc73f3a 100644 --- a/src/UnitTests/Bug/MultipleInterfaceInheritance.cs +++ b/src/UnitTests/Bug/MultipleInterfaceInheritance.cs @@ -1,54 +1,53 @@ using Shouldly; using Xunit; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class MultipleInterfaceInheritance : AutoMapperSpecBase { - public class MultipleInterfaceInheritance : AutoMapperSpecBase - { - private ThingDto _thingDto; - - public class Thing - { - public IItem[] Items { get; set; } - } - - public class ThingDto - { - public ItemDto[] Items { get; set; } - } - - public class Item : IItem - { - } - - public class ItemDto - { - } - - public interface IItem : ISome // everything works well if IItem doesn't inherit ISome. - { - } - - public interface ISome - { - } - - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - cfg.CreateMap(); - }); - - protected override void Because_of() - { - var thing = new Thing { Items = new[] { new Item() } }; - _thingDto = Mapper.Map(thing); - } - - [Fact] - public void Should_map_successfully() - { - _thingDto.Items.Length.ShouldBe(1); - } + private ThingDto _thingDto; + + public class Thing + { + public IItem[] Items { get; set; } + } + + public class ThingDto + { + public ItemDto[] Items { get; set; } + } + + public class Item : IItem + { + } + + public class ItemDto + { + } + + public interface IItem : ISome // everything works well if IItem doesn't inherit ISome. + { + } + + public interface ISome + { + } + + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + cfg.CreateMap(); + }); + + protected override void Because_of() + { + var thing = new Thing { Items = new[] { new Item() } }; + _thingDto = Mapper.Map(thing); + } + + [Fact] + public void Should_map_successfully() + { + _thingDto.Items.Length.ShouldBe(1); } } \ No newline at end of file diff --git a/src/UnitTests/Bug/MultipleTypeConverterInterfaces.cs b/src/UnitTests/Bug/MultipleTypeConverterInterfaces.cs index de60eba68b..f529b57fd3 100644 --- a/src/UnitTests/Bug/MultipleTypeConverterInterfaces.cs +++ b/src/UnitTests/Bug/MultipleTypeConverterInterfaces.cs @@ -1,68 +1,67 @@ using Shouldly; using Xunit; -namespace AutoMapper.UnitTests.Bug -{ - public class When_specifying_a_type_converter_implementing_multiple_type_converter_interfaces : AutoMapperSpecBase +namespace AutoMapper.UnitTests.Bug; + + public class When_specifying_a_type_converter_implementing_multiple_type_converter_interfaces : AutoMapperSpecBase + { + private DestinationFoo _resultFoo; + private DestinationBar _resultBar; + + public class SourceFoo { - private DestinationFoo _resultFoo; - private DestinationBar _resultBar; + public int SourceFooValue { get; set; } + } - public class SourceFoo - { - public int SourceFooValue { get; set; } - } + public class DestinationFoo + { + public int DestinationFooValue { get; set; } + } + public class SourceBar + { + public int SourceBarValue { get; set; } + } - public class DestinationFoo - { - public int DestinationFooValue { get; set; } - } - public class SourceBar - { - public int SourceBarValue { get; set; } - } + public class DestinationBar + { + public int DestinationBarValue { get; set; } + } - public class DestinationBar + public class DualConverter : ITypeConverter, + ITypeConverter + { + public DestinationFoo Convert(SourceFoo source, DestinationFoo destination, ResolutionContext context) { - public int DestinationBarValue { get; set; } + return new DestinationFoo { DestinationFooValue = source.SourceFooValue + 100 }; } - public class DualConverter : ITypeConverter, - ITypeConverter + DestinationBar ITypeConverter.Convert(SourceBar source, DestinationBar destination, ResolutionContext context) { - public DestinationFoo Convert(SourceFoo source, DestinationFoo destination, ResolutionContext context) - { - return new DestinationFoo { DestinationFooValue = source.SourceFooValue + 100 }; - } - - DestinationBar ITypeConverter.Convert(SourceBar source, DestinationBar destination, ResolutionContext context) - { - return new DestinationBar { DestinationBarValue = source.SourceBarValue + 1000 }; - } + return new DestinationBar { DestinationBarValue = source.SourceBarValue + 1000 }; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(typeof (SourceFoo), typeof (DestinationFoo)).ConvertUsing(typeof (DualConverter)); - cfg.CreateMap(typeof (SourceBar), typeof (DestinationBar)).ConvertUsing(typeof (DualConverter)); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(typeof (SourceFoo), typeof (DestinationFoo)).ConvertUsing(typeof (DualConverter)); + cfg.CreateMap(typeof (SourceBar), typeof (DestinationBar)).ConvertUsing(typeof (DualConverter)); + }); - protected override void Because_of() - { - _resultFoo = Mapper.Map(new SourceFoo { SourceFooValue = 5 }); - _resultBar = Mapper.Map(new SourceBar { SourceBarValue = 6 }); - } + protected override void Because_of() + { + _resultFoo = Mapper.Map(new SourceFoo { SourceFooValue = 5 }); + _resultBar = Mapper.Map(new SourceBar { SourceBarValue = 6 }); + } - [Fact] - public void Should_use_implicit_converter() - { - _resultFoo.DestinationFooValue.ShouldBe(105); - } + [Fact] + public void Should_use_implicit_converter() + { + _resultFoo.DestinationFooValue.ShouldBe(105); + } - [Fact] - public void Should_use_explicit_converter() - { - _resultBar.DestinationBarValue.ShouldBe(1006); - } + [Fact] + public void Should_use_explicit_converter() + { + _resultBar.DestinationBarValue.ShouldBe(1006); } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/UnitTests/Bug/NamingConventions.cs b/src/UnitTests/Bug/NamingConventions.cs index cd6dbd41be..a1a6db8c6b 100644 --- a/src/UnitTests/Bug/NamingConventions.cs +++ b/src/UnitTests/Bug/NamingConventions.cs @@ -6,110 +6,109 @@ using System.Reflection; using Xunit; -namespace AutoMapper.UnitTests.Bug.NamingConventions +namespace AutoMapper.UnitTests.Bug.NamingConventions; + +public class RemoveNameSplitMapper : NonValidatingSpecBase { - public class RemoveNameSplitMapper : NonValidatingSpecBase + class Source { - class Source - { - public InnerSource InnerSource { get; set; } - } - class InnerSource - { - public int Value { get; set; } - } - class Destination - { - public int InnerSourceValue { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(c => - { - c.Internal().DestinationMemberNamingConvention = ExactMatchNamingConvention.Instance; - c.CreateMap(); - }); - [Fact] - public void Should_not_validate() => Should.Throw(AssertConfigurationIsValid) - .Errors.Single().UnmappedPropertyNames.Single().ShouldBe(nameof(Destination.InnerSourceValue)); + public InnerSource InnerSource { get; set; } } - public class DisableNamingConvention : NonValidatingSpecBase + class InnerSource { - class Source - { - public string Name { get; set; } - } - class Destination - { - public string Name { get; set; } - public string COMPANY_Name { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg=> - { - cfg.DestinationMemberNamingConvention = ExactMatchNamingConvention.Instance; - cfg.CreateMap(); - }); - [Fact] - public void Should_not_use_pascal_naming_convention() => - new Action(Mapper.ConfigurationProvider.AssertConfigurationIsValid).ShouldThrow() - .Errors[0].UnmappedPropertyNames.ShouldContain("COMPANY_Name"); + public int Value { get; set; } + } + class Destination + { + public int InnerSourceValue { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(c => + { + c.Internal().DestinationMemberNamingConvention = ExactMatchNamingConvention.Instance; + c.CreateMap(); + }); + [Fact] + public void Should_not_validate() => Should.Throw(AssertConfigurationIsValid) + .Errors.Single().UnmappedPropertyNames.Single().ShouldBe(nameof(Destination.InnerSourceValue)); +} +public class DisableNamingConvention : NonValidatingSpecBase +{ + class Source + { + public string Name { get; set; } + } + class Destination + { + public string Name { get; set; } + public string COMPANY_Name { get; set; } } - public class Neda + protected override MapperConfiguration CreateConfiguration() => new(cfg=> { - public string cmok { get; set; } + cfg.DestinationMemberNamingConvention = ExactMatchNamingConvention.Instance; + cfg.CreateMap(); + }); + [Fact] + public void Should_not_use_pascal_naming_convention() => + new Action(Mapper.ConfigurationProvider.AssertConfigurationIsValid).ShouldThrow() + .Errors[0].UnmappedPropertyNames.ShouldContain("COMPANY_Name"); +} +public class Neda +{ + public string cmok { get; set; } - public string moje_ime { get; set; } + public string moje_ime { get; set; } - public string moje_prezime { get; set; } + public string moje_prezime { get; set; } - public string ja_se_zovem_imenom { get; set; } + public string ja_se_zovem_imenom { get; set; } - } +} - public class Dario - { - public string cmok { get; set; } +public class Dario +{ + public string cmok { get; set; } - public string MojeIme { get; set; } + public string MojeIme { get; set; } - public string MojePrezime { get; set; } + public string MojePrezime { get; set; } - public string JaSeZovemImenom { get; set; } - } + public string JaSeZovemImenom { get; set; } +} - public class When_mapping_with_lowercae_naming_conventions_two_ways_in_profiles : AutoMapperSpecBase - { - private Dario _dario; - private Neda _neda; +public class When_mapping_with_lowercae_naming_conventions_two_ways_in_profiles : AutoMapperSpecBase +{ + private Dario _dario; + private Neda _neda; - protected override MapperConfiguration CreateConfiguration() => new(cfg => + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateProfile("MyMapperProfile", prf => { - cfg.CreateProfile("MyMapperProfile", prf => - { - prf.SourceMemberNamingConvention = new LowerUnderscoreNamingConvention(); - prf.CreateMap(); - }); - cfg.CreateProfile("MyMapperProfile2", prf => - { - prf.DestinationMemberNamingConvention = new LowerUnderscoreNamingConvention(); - prf.CreateMap(); - }); + prf.SourceMemberNamingConvention = new LowerUnderscoreNamingConvention(); + prf.CreateMap(); }); - - protected override void Because_of() + cfg.CreateProfile("MyMapperProfile2", prf => { - _dario = Mapper.Map(new Neda {ja_se_zovem_imenom = "foo"}); - _neda = Mapper.Map(_dario); - } + prf.DestinationMemberNamingConvention = new LowerUnderscoreNamingConvention(); + prf.CreateMap(); + }); + }); - [Fact] - public void Should_map_from_lower_to_pascal() - { - _neda.ja_se_zovem_imenom.ShouldBe("foo"); - } + protected override void Because_of() + { + _dario = Mapper.Map(new Neda {ja_se_zovem_imenom = "foo"}); + _neda = Mapper.Map(_dario); + } - [Fact] - public void Should_map_from_pascal_to_lower() - { - _dario.JaSeZovemImenom.ShouldBe("foo"); - } + [Fact] + public void Should_map_from_lower_to_pascal() + { + _neda.ja_se_zovem_imenom.ShouldBe("foo"); + } + + [Fact] + public void Should_map_from_pascal_to_lower() + { + _dario.JaSeZovemImenom.ShouldBe("foo"); } } \ No newline at end of file diff --git a/src/UnitTests/Bug/NestedMappingProjectionsExplicitExpanding.cs b/src/UnitTests/Bug/NestedMappingProjectionsExplicitExpanding.cs index d5e853ecce..150f25ec3f 100644 --- a/src/UnitTests/Bug/NestedMappingProjectionsExplicitExpanding.cs +++ b/src/UnitTests/Bug/NestedMappingProjectionsExplicitExpanding.cs @@ -4,60 +4,59 @@ using Shouldly; using Xunit; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class NestedMappingProjectionsExplicitExpanding : AutoMapperSpecBase { - public class NestedMappingProjectionsExplicitExpanding : AutoMapperSpecBase - { - Fu _destination; - int _propValue = 23; - - public class FuEntity - { - public ManEntity Man { get; set; } - } - - public class ManEntity - { - public ChuEntity Chu { get; set; } - } - - public class ChuEntity - { - public int Prop { get; set; } - } - - public class Fu - { - public Man Man { get; set; } - } - - public class Man - { - public Chu Chu { get; set; } - } - - public class Chu - { - public int Prop { get; set; } - } - - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateProjection().ForMember(dest => dest.Man, opt => opt.ExplicitExpansion()); - cfg.CreateProjection().ForMember(dest => dest.Chu, opt => opt.ExplicitExpansion()); - cfg.CreateProjection(); - }); - - protected override void Because_of() - { - var fuEntity = new FuEntity { Man = new ManEntity { Chu = new ChuEntity { Prop = _propValue } } }; - _destination = new[] { fuEntity }.AsQueryable().ProjectTo(Configuration, m =>m.Man, m=>m.Man.Chu).First(); - } - - [Fact] - public void Should_map_nested_classes() - { - _destination.Man.Chu.Prop.ShouldBe(_propValue); - } + Fu _destination; + int _propValue = 23; + + public class FuEntity + { + public ManEntity Man { get; set; } + } + + public class ManEntity + { + public ChuEntity Chu { get; set; } + } + + public class ChuEntity + { + public int Prop { get; set; } + } + + public class Fu + { + public Man Man { get; set; } + } + + public class Man + { + public Chu Chu { get; set; } + } + + public class Chu + { + public int Prop { get; set; } + } + + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateProjection().ForMember(dest => dest.Man, opt => opt.ExplicitExpansion()); + cfg.CreateProjection().ForMember(dest => dest.Chu, opt => opt.ExplicitExpansion()); + cfg.CreateProjection(); + }); + + protected override void Because_of() + { + var fuEntity = new FuEntity { Man = new ManEntity { Chu = new ChuEntity { Prop = _propValue } } }; + _destination = new[] { fuEntity }.AsQueryable().ProjectTo(Configuration, m =>m.Man, m=>m.Man.Chu).First(); + } + + [Fact] + public void Should_map_nested_classes() + { + _destination.Man.Chu.Prop.ShouldBe(_propValue); } } \ No newline at end of file diff --git a/src/UnitTests/Bug/NonExistingProperty.cs b/src/UnitTests/Bug/NonExistingProperty.cs index ea8854aa90..3df6947e5e 100644 --- a/src/UnitTests/Bug/NonExistingProperty.cs +++ b/src/UnitTests/Bug/NonExistingProperty.cs @@ -2,22 +2,21 @@ using Shouldly; using Xunit; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class NonExistingProperty : NonValidatingSpecBase { - public class NonExistingProperty : NonValidatingSpecBase + public class Source { - public class Source - { - } + } - public class Destination - { - } + public class Destination + { + } - [Fact] - public void Should_report_missing_property() - { - new Action(() => new MapperConfiguration(cfg => cfg.CreateMap().ForMember("X", s => { }))).ShouldThrow(); - } + [Fact] + public void Should_report_missing_property() + { + new Action(() => new MapperConfiguration(cfg => cfg.CreateMap().ForMember("X", s => { }))).ShouldThrow(); } } diff --git a/src/UnitTests/Bug/NullArrayBug.cs b/src/UnitTests/Bug/NullArrayBug.cs index 5a9f4e6cf8..4a7421bb4a 100644 --- a/src/UnitTests/Bug/NullArrayBug.cs +++ b/src/UnitTests/Bug/NullArrayBug.cs @@ -1,49 +1,48 @@ -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +using Shouldly; +using Xunit; + +public class NullArrayBug : AutoMapperSpecBase { - using Shouldly; - using Xunit; + private static Source _source; + private Destination _destination; + + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.AllowNullCollections = false; + cfg.CreateMap(); + + _source = new Source {Name = null, Data = null}; + }); + + protected override void Because_of() + { + _destination = Mapper.Map(_source); + } + + [Fact] + public void Should_map_name_to_null() + { + _destination.Name.ShouldBeNull(); + } + + [Fact] + public void Should_map_null_array_to_empty() + { + _destination.Data.ShouldNotBeNull(); + _destination.Data.ShouldBeEmpty(); + } + + public class Source + { + public string Name { get; set; } + public string[] Data { get; set; } + } - public class NullArrayBug : AutoMapperSpecBase + public class Destination { - private static Source _source; - private Destination _destination; - - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.AllowNullCollections = false; - cfg.CreateMap(); - - _source = new Source {Name = null, Data = null}; - }); - - protected override void Because_of() - { - _destination = Mapper.Map(_source); - } - - [Fact] - public void Should_map_name_to_null() - { - _destination.Name.ShouldBeNull(); - } - - [Fact] - public void Should_map_null_array_to_empty() - { - _destination.Data.ShouldNotBeNull(); - _destination.Data.ShouldBeEmpty(); - } - - public class Source - { - public string Name { get; set; } - public string[] Data { get; set; } - } - - public class Destination - { - public string Name { get; set; } - public string[] Data { get; set; } - } + public string Name { get; set; } + public string[] Data { get; set; } } } \ No newline at end of file diff --git a/src/UnitTests/Bug/NullConstructorParameterName.cs b/src/UnitTests/Bug/NullConstructorParameterName.cs index e7e90fb8de..766ad321a9 100644 --- a/src/UnitTests/Bug/NullConstructorParameterName.cs +++ b/src/UnitTests/Bug/NullConstructorParameterName.cs @@ -3,38 +3,37 @@ using System.Reflection.Emit; using Xunit; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class NullConstructorParameterName { - public class NullConstructorParameterName + [Fact] + public void ShouldBeSkipped() { - [Fact] - public void ShouldBeSkipped() - { - var proxy = CreateDynamicObject(); - var config = new MapperConfiguration(cfg => cfg.CreateMap(typeof(ResourcePointDTO), proxy.GetType())); - } + var proxy = CreateDynamicObject(); + var config = new MapperConfiguration(cfg => cfg.CreateMap(typeof(ResourcePointDTO), proxy.GetType())); + } - public class ResourcePointDTO { } + public class ResourcePointDTO { } - object CreateDynamicObject() - { - var assemblyName = new AssemblyName("TestClass"); - AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); - ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule"); - TypeBuilder typeBuilder = moduleBuilder.DefineType(assemblyName.FullName - , TypeAttributes.Public | - TypeAttributes.Class | - TypeAttributes.AutoClass | - TypeAttributes.AnsiClass | - TypeAttributes.BeforeFieldInit | - TypeAttributes.AutoLayout - , null); - typeBuilder.DefineDefaultConstructor(MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName); - var cBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, CallingConventions.Standard, new []{ typeof(int) }); - ILGenerator myConstructorIL = cBuilder.GetILGenerator(); - myConstructorIL.Emit(OpCodes.Ret); - var type = typeBuilder.CreateType(); - return Activator.CreateInstance(type); - } + object CreateDynamicObject() + { + var assemblyName = new AssemblyName("TestClass"); + AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); + ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule"); + TypeBuilder typeBuilder = moduleBuilder.DefineType(assemblyName.FullName + , TypeAttributes.Public | + TypeAttributes.Class | + TypeAttributes.AutoClass | + TypeAttributes.AnsiClass | + TypeAttributes.BeforeFieldInit | + TypeAttributes.AutoLayout + , null); + typeBuilder.DefineDefaultConstructor(MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName); + var cBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, CallingConventions.Standard, new []{ typeof(int) }); + ILGenerator myConstructorIL = cBuilder.GetILGenerator(); + myConstructorIL.Emit(OpCodes.Ret); + var type = typeBuilder.CreateType(); + return Activator.CreateInstance(type); } } diff --git a/src/UnitTests/Bug/NullSubstituteInnerClass.cs b/src/UnitTests/Bug/NullSubstituteInnerClass.cs index 03348b164b..f4e845e56f 100644 --- a/src/UnitTests/Bug/NullSubstituteInnerClass.cs +++ b/src/UnitTests/Bug/NullSubstituteInnerClass.cs @@ -2,55 +2,54 @@ using Shouldly; using System; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class NullSubstituteInnerClass : AutoMapperSpecBase { - public class NullSubstituteInnerClass : AutoMapperSpecBase + private FooDto _destination; + + public class Foo { - private FooDto _destination; + public int Id { get; set; } + public Bar Bar { get; set; } + } - public class Foo - { - public int Id { get; set; } - public Bar Bar { get; set; } - } + public class Bar + { + public string Name { get; set; } + } - public class Bar - { - public string Name { get; set; } - } + public class FooDto + { + public int Id { get; set; } + public BarDto Bar { get; set; } + } - public class FooDto - { - public int Id { get; set; } - public BarDto Bar { get; set; } - } + public class BarDto + { + public string Name { get; set; } + } - public class BarDto - { - public string Name { get; set; } - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + cfg.CreateMap() + .ForMember(dest => dest.Bar, opts => opts.NullSubstitute(new Bar())); + }); - protected override MapperConfiguration CreateConfiguration() => new(cfg => + protected override void Because_of() + { + _destination = Mapper.Map(new Foo() { - cfg.CreateMap(); - cfg.CreateMap() - .ForMember(dest => dest.Bar, opts => opts.NullSubstitute(new Bar())); + Id = 5, + Bar = null }); + } - protected override void Because_of() - { - _destination = Mapper.Map(new Foo() - { - Id = 5, - Bar = null - }); - } - - [Fact] - public void Should_map_int_to_nullable_decimal() - { - _destination.Bar.ShouldNotBeNull(); - } + [Fact] + public void Should_map_int_to_nullable_decimal() + { + _destination.Bar.ShouldNotBeNull(); } } \ No newline at end of file diff --git a/src/UnitTests/Bug/NullSubstituteType.cs b/src/UnitTests/Bug/NullSubstituteType.cs index 399ad98cd7..cdf1275a6f 100644 --- a/src/UnitTests/Bug/NullSubstituteType.cs +++ b/src/UnitTests/Bug/NullSubstituteType.cs @@ -2,35 +2,34 @@ using Shouldly; using System; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class NullSubstituteType : AutoMapperSpecBase { - public class NullSubstituteType : AutoMapperSpecBase - { - private Destination _destination; + private Destination _destination; - class Source - { - public long? Number { get; set; } - } - class Destination - { - public long? Number { get; set; } - } + class Source + { + public long? Number { get; set; } + } + class Destination + { + public long? Number { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().ForMember(d => d.Number, o => o.NullSubstitute(0)); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().ForMember(d => d.Number, o => o.NullSubstitute(0)); + }); - protected override void Because_of() - { - _destination = Mapper.Map(new Source()); - } + protected override void Because_of() + { + _destination = Mapper.Map(new Source()); + } - [Fact] - public void Should_substitute_zero_for_null() - { - _destination.Number.ShouldBe(0); - } + [Fact] + public void Should_substitute_zero_for_null() + { + _destination.Number.ShouldBe(0); } } \ No newline at end of file diff --git a/src/UnitTests/Bug/NullToString.cs b/src/UnitTests/Bug/NullToString.cs index 6c901de1cd..398c76f0d2 100644 --- a/src/UnitTests/Bug/NullToString.cs +++ b/src/UnitTests/Bug/NullToString.cs @@ -2,38 +2,37 @@ using Shouldly; using System; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class NullToString : AutoMapperSpecBase { - public class NullToString : AutoMapperSpecBase - { - private Destination _destination; + private Destination _destination; - class Source - { - public InnerSource Inner { get; set; } - } - class InnerSource - { - } - class Destination - { - public string Inner { get; set; } - } + class Source + { + public InnerSource Inner { get; set; } + } + class InnerSource + { + } + class Destination + { + public string Inner { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + }); - protected override void Because_of() - { - _destination = Mapper.Map(new Source()); - } + protected override void Because_of() + { + _destination = Mapper.Map(new Source()); + } - [Fact] - public void Should_map_int_to_nullable_decimal() - { - _destination.Inner.ShouldBeNull(); - } + [Fact] + public void Should_map_int_to_nullable_decimal() + { + _destination.Inner.ShouldBeNull(); } } \ No newline at end of file diff --git a/src/UnitTests/Bug/NullableBytesAndEnums.cs b/src/UnitTests/Bug/NullableBytesAndEnums.cs index 9d790f63b5..c6044694b3 100644 --- a/src/UnitTests/Bug/NullableBytesAndEnums.cs +++ b/src/UnitTests/Bug/NullableBytesAndEnums.cs @@ -1,110 +1,109 @@ using Shouldly; using Xunit; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class NullableBytesAndEnums : AutoMapperSpecBase { - public class NullableBytesAndEnums : AutoMapperSpecBase - { - private Destination _destination; - - public class Source - { - public byte? Value { get; set; } - } - - public enum Foo : byte - { - Blarg = 1, - Splorg = 2 - } - - public class Destination - { - public Foo? Value { get; set; } - } - - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - }); - - protected override void Because_of() - { - _destination = Mapper.Map(new Source {Value = 2}); - } - - [Fact] - public void Should_map_the_byte_to_the_enum_with_the_same_value() - { - _destination.Value.ShouldBe(Foo.Splorg); - } + private Destination _destination; + + public class Source + { + public byte? Value { get; set; } } - public class NullableLong : AutoMapperSpecBase + public enum Foo : byte { - private Destination _destination; + Blarg = 1, + Splorg = 2 + } - public class Source - { - public int Value { get; set; } - } + public class Destination + { + public Foo? Value { get; set; } + } + + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + }); + + protected override void Because_of() + { + _destination = Mapper.Map(new Source {Value = 2}); + } - public class Destination - { - public long? Value { get; set; } - } + [Fact] + public void Should_map_the_byte_to_the_enum_with_the_same_value() + { + _destination.Value.ShouldBe(Foo.Splorg); + } +} - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - }); +public class NullableLong : AutoMapperSpecBase +{ + private Destination _destination; - protected override void Because_of() - { - _destination = Mapper.Map(new Source { Value = 2 }); - } + public class Source + { + public int Value { get; set; } + } - [Fact] - public void Should_map_the_byte_to_the_enum_with_the_same_value() - { - _destination.Value.ShouldBe(2); - } + public class Destination + { + public long? Value { get; set; } } - public class NullableShortWithCustomMapFrom : AutoMapperSpecBase - { - public class Source - { - public short Value { get; set; } - } - - public class Destination - { - public short? Value { get; set; } - } - - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ForMember(t => t.Value, opts => opts.MapFrom(s => s.Value > 0 ? s.Value : default(short?))); - }); - - protected override void Because_of() - { - } - - [Fact] - public void Should_map_the_value() - { - var destination = Mapper.Map(new Source { Value = 2 }); - destination.Value.ShouldBe((short)2); - } - - [Fact] - public void Should_map_the_value_with_condition() - { - var destination = Mapper.Map(new Source { Value = 0 }); - destination.Value.ShouldBeNull(); - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + }); + + protected override void Because_of() + { + _destination = Mapper.Map(new Source { Value = 2 }); + } + + [Fact] + public void Should_map_the_byte_to_the_enum_with_the_same_value() + { + _destination.Value.ShouldBe(2); + } +} + +public class NullableShortWithCustomMapFrom : AutoMapperSpecBase +{ + public class Source + { + public short Value { get; set; } + } + + public class Destination + { + public short? Value { get; set; } + } + + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .ForMember(t => t.Value, opts => opts.MapFrom(s => s.Value > 0 ? s.Value : default(short?))); + }); + + protected override void Because_of() + { + } + + [Fact] + public void Should_map_the_value() + { + var destination = Mapper.Map(new Source { Value = 2 }); + destination.Value.ShouldBe((short)2); + } + + [Fact] + public void Should_map_the_value_with_condition() + { + var destination = Mapper.Map(new Source { Value = 0 }); + destination.Value.ShouldBeNull(); } } diff --git a/src/UnitTests/Bug/NullableDateTime.cs b/src/UnitTests/Bug/NullableDateTime.cs index cc50123ddc..1d02a85752 100644 --- a/src/UnitTests/Bug/NullableDateTime.cs +++ b/src/UnitTests/Bug/NullableDateTime.cs @@ -4,103 +4,102 @@ using AutoMapper; using Xunit; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class NullableDateTimeMapFromArray : AutoMapperSpecBase +{ + public class Source + { + public SourceInner[] Bars { get; set; } + } + + public class SourceInner + { + public DateTime Bar { get; set; } + } + + public class Destination + { + public DateTime? Foo { get; set; } + } + + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .ForMember(m => m.Foo, opt => + { + opt.Condition(src => src.Bars != null && src.Bars.Length > 0); + opt.MapFrom(src => src.Bars.Min(b => b.Bar)); + }); + }); + [Fact] + public void Validate() => AssertConfigurationIsValid(); +} + +public class FromDateToNullableDateTime : AutoMapperSpecBase +{ + Destination _destination; + DateTime _date = new DateTime(1900, 1, 1); + + public class Source + { + public DateTime? FiredDate { get; set; } + public DateTime HiredDate { get; set; } + } + + public class Destination + { + public DateTime? FiredDate { get; set; } + public DateTime HiredDate { get; set; } + } + + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().ForMember(d => d.FiredDate, o => o.MapFrom(s => s.HiredDate.Date)); + }); + + protected override void Because_of() + { + _destination = Mapper.Map(new Source { HiredDate = _date }); + } + + [Fact] + public void Should_map_as_usual() + { + _destination.FiredDate.ShouldBe(_date.Date); + } +} + +public class NullableDateTime : AutoMapperSpecBase { - public class NullableDateTimeMapFromArray : AutoMapperSpecBase + Destination _destination; + DateTime _date = new DateTime(1900, 1, 1); + + public class Source + { + public DateTime Value { get; set; } + } + + public class Destination { - public class Source - { - public SourceInner[] Bars { get; set; } - } - - public class SourceInner - { - public DateTime Bar { get; set; } - } - - public class Destination - { - public DateTime? Foo { get; set; } - } - - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ForMember(m => m.Foo, opt => - { - opt.Condition(src => src.Bars != null && src.Bars.Length > 0); - opt.MapFrom(src => src.Bars.Min(b => b.Bar)); - }); - }); - [Fact] - public void Validate() => AssertConfigurationIsValid(); + public DateTime Value { get; set; } } - public class FromDateToNullableDateTime : AutoMapperSpecBase + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + cfg.CreateMap() + .ConvertUsing(source => source == new DateTime(1900, 1, 1) ? (DateTime?) null : source); + }); + + protected override void Because_of() { - Destination _destination; - DateTime _date = new DateTime(1900, 1, 1); - - public class Source - { - public DateTime? FiredDate { get; set; } - public DateTime HiredDate { get; set; } - } - - public class Destination - { - public DateTime? FiredDate { get; set; } - public DateTime HiredDate { get; set; } - } - - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().ForMember(d => d.FiredDate, o => o.MapFrom(s => s.HiredDate.Date)); - }); - - protected override void Because_of() - { - _destination = Mapper.Map(new Source { HiredDate = _date }); - } - - [Fact] - public void Should_map_as_usual() - { - _destination.FiredDate.ShouldBe(_date.Date); - } + _destination = Mapper.Map(new Source { Value = _date }); } - public class NullableDateTime : AutoMapperSpecBase + [Fact] + public void Should_map_as_usual() { - Destination _destination; - DateTime _date = new DateTime(1900, 1, 1); - - public class Source - { - public DateTime Value { get; set; } - } - - public class Destination - { - public DateTime Value { get; set; } - } - - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - cfg.CreateMap() - .ConvertUsing(source => source == new DateTime(1900, 1, 1) ? (DateTime?) null : source); - }); - - protected override void Because_of() - { - _destination = Mapper.Map(new Source { Value = _date }); - } - - [Fact] - public void Should_map_as_usual() - { - _destination.Value.ShouldBe(_date); - } + _destination.Value.ShouldBe(_date); } } \ No newline at end of file diff --git a/src/UnitTests/Bug/NullableEnumToNullableValueType.cs b/src/UnitTests/Bug/NullableEnumToNullableValueType.cs index e80e03eb1d..c215edbaea 100644 --- a/src/UnitTests/Bug/NullableEnumToNullableValueType.cs +++ b/src/UnitTests/Bug/NullableEnumToNullableValueType.cs @@ -1,42 +1,41 @@ using Shouldly; using Xunit; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class NullableEnumToNullableValueType { - public class NullableEnumToNullableValueType + public class CannotConvertEnumToNullableWhenPassedNull : AutoMapperSpecBase { - public class CannotConvertEnumToNullableWhenPassedNull : AutoMapperSpecBase + public enum DummyTypes : int + { + Foo = 1, + Bar = 2 + } + + public class DummySource { - public enum DummyTypes : int - { - Foo = 1, - Bar = 2 - } - - public class DummySource - { - public DummyTypes? Dummy { get; set; } - } - - public class DummyDestination - { - public int? Dummy { get; set; } - } - - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - }); - - [Fact] - public void Should_map_null_enum_to_nullable_base_type() - { - DummySource src = new DummySource() { Dummy = null }; - - var destination = Mapper.Map(src); - - destination.Dummy.ShouldBeNull(); - } - } - } + public DummyTypes? Dummy { get; set; } + } + + public class DummyDestination + { + public int? Dummy { get; set; } + } + + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + }); + + [Fact] + public void Should_map_null_enum_to_nullable_base_type() + { + DummySource src = new DummySource() { Dummy = null }; + + var destination = Mapper.Map(src); + + destination.Dummy.ShouldBeNull(); + } + } } \ No newline at end of file diff --git a/src/UnitTests/Bug/NullableEnums.cs b/src/UnitTests/Bug/NullableEnums.cs index 946de50c28..f261ebdfe8 100644 --- a/src/UnitTests/Bug/NullableEnums.cs +++ b/src/UnitTests/Bug/NullableEnums.cs @@ -1,26 +1,25 @@ using Xunit; using Shouldly; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class NullableEnums : AutoMapperSpecBase { - public class NullableEnums : AutoMapperSpecBase - { - public class Src { public EnumType? A { get; set; } } - public class Dst { public EnumType? A { get; set; } } + public class Src { public EnumType? A { get; set; } } + public class Dst { public EnumType? A { get; set; } } - public enum EnumType { One, Two } + public enum EnumType { One, Two } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + }); - [Fact] - public void TestNullableEnum() - { - var d = Mapper.Map(new Src { A = null }, new Dst { A = EnumType.One }); + [Fact] + public void TestNullableEnum() + { + var d = Mapper.Map(new Src { A = null }, new Dst { A = EnumType.One }); - d.A.ShouldBeNull(); - } - } + d.A.ShouldBeNull(); + } } \ No newline at end of file diff --git a/src/UnitTests/Bug/NullableIntToNullableDecimal.cs b/src/UnitTests/Bug/NullableIntToNullableDecimal.cs index a687467150..fc419b9a0c 100644 --- a/src/UnitTests/Bug/NullableIntToNullableDecimal.cs +++ b/src/UnitTests/Bug/NullableIntToNullableDecimal.cs @@ -2,72 +2,71 @@ using Shouldly; using System; -namespace AutoMapper.UnitTests.Bug -{ - public class NullableIntToNullableDecimal : AutoMapperSpecBase - { - private Destination _destination; +namespace AutoMapper.UnitTests.Bug; - class Source - { - public int? Number { get; set; } - } - class Destination - { - public decimal? Number { get; set; } - } +public class NullableIntToNullableDecimal : AutoMapperSpecBase +{ + private Destination _destination; - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - }); + class Source + { + public int? Number { get; set; } + } + class Destination + { + public decimal? Number { get; set; } + } - protected override void Because_of() - { - var source = new Source - { - Number = 23 - }; - _destination = Mapper.Map(source); - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + }); - [Fact] - public void Should_map_int_to_nullable_decimal() + protected override void Because_of() + { + var source = new Source { - _destination.Number.ShouldBe(23); - } + Number = 23 + }; + _destination = Mapper.Map(source); } - public class NullNullableIntToNullableDecimal : AutoMapperSpecBase + [Fact] + public void Should_map_int_to_nullable_decimal() { - private Destination _destination; + _destination.Number.ShouldBe(23); + } +} - class Source - { - public int? Number { get; set; } - } - class Destination - { - public decimal? Number { get; set; } - } +public class NullNullableIntToNullableDecimal : AutoMapperSpecBase +{ + private Destination _destination; - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - }); + class Source + { + public int? Number { get; set; } + } + class Destination + { + public decimal? Number { get; set; } + } - protected override void Because_of() - { - var source = new Source - { - }; - _destination = Mapper.Map(source); - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + }); - [Fact] - public void Should_map_int_to_nullable_decimal() + protected override void Because_of() + { + var source = new Source { - _destination.Number.ShouldBeNull(); - } + }; + _destination = Mapper.Map(source); + } + + [Fact] + public void Should_map_int_to_nullable_decimal() + { + _destination.Number.ShouldBeNull(); } } \ No newline at end of file diff --git a/src/UnitTests/Bug/NullableIntToNullableEnum.cs b/src/UnitTests/Bug/NullableIntToNullableEnum.cs index 3870372f28..a1c82a814f 100644 --- a/src/UnitTests/Bug/NullableIntToNullableEnum.cs +++ b/src/UnitTests/Bug/NullableIntToNullableEnum.cs @@ -3,43 +3,42 @@ using AutoMapper; using Xunit; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class NullableIntToNullableEnum : AutoMapperSpecBase { - public class NullableIntToNullableEnum : AutoMapperSpecBase + Destination _destination; + + public enum Values + { + One = 1, + Two = 2, + Three = 3 + } + + public class Source + { + public int? Value { get; set; } + } + + public class Destination + { + public Values? Value { get; set; } + } + + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + }); + + protected override void Because_of() + { + _destination = Mapper.Map(new Source()); + } + + [Fact] + public void Should_map_null_to_null() { - Destination _destination; - - public enum Values - { - One = 1, - Two = 2, - Three = 3 - } - - public class Source - { - public int? Value { get; set; } - } - - public class Destination - { - public Values? Value { get; set; } - } - - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - }); - - protected override void Because_of() - { - _destination = Mapper.Map(new Source()); - } - - [Fact] - public void Should_map_null_to_null() - { - _destination.Value.ShouldBeNull(); - } + _destination.Value.ShouldBeNull(); } } \ No newline at end of file diff --git a/src/UnitTests/Bug/NullablePropertiesBug.cs b/src/UnitTests/Bug/NullablePropertiesBug.cs index 0f742e70ea..af16328852 100644 --- a/src/UnitTests/Bug/NullablePropertiesBug.cs +++ b/src/UnitTests/Bug/NullablePropertiesBug.cs @@ -1,22 +1,21 @@ using Xunit; using Shouldly; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class NullablePropertiesBug { - public class NullablePropertiesBug - { - public class Source { public int? A { get; set; } } - public class Target { public int? A { get; set; } } + public class Source { public int? A { get; set; } } + public class Target { public int? A { get; set; } } - [Fact] - public void Example() - { + [Fact] + public void Example() + { - var config = new MapperConfiguration(cfg => cfg.CreateMap()); + var config = new MapperConfiguration(cfg => cfg.CreateMap()); - var d = config.CreateMapper().Map(new Source { A = null }, new Target { A = 10 }); + var d = config.CreateMapper().Map(new Source { A = null }, new Target { A = 10 }); - d.A.ShouldBeNull(); - } + d.A.ShouldBeNull(); } } \ No newline at end of file diff --git a/src/UnitTests/Bug/NullableResolveUsing.cs b/src/UnitTests/Bug/NullableResolveUsing.cs index 86907134fb..cab70ae7ae 100644 --- a/src/UnitTests/Bug/NullableResolveUsing.cs +++ b/src/UnitTests/Bug/NullableResolveUsing.cs @@ -2,35 +2,34 @@ using Shouldly; using System; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class NullableResolveUsing : AutoMapperSpecBase { - public class NullableResolveUsing : AutoMapperSpecBase - { - private Destination _destination; + private Destination _destination; - class Source - { - public decimal? Number { get; set; } - } - class Destination - { - public decimal? OddNumber { get; set; } - } + class Source + { + public decimal? Number { get; set; } + } + class Destination + { + public decimal? OddNumber { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().ForMember(d => d.OddNumber, o => o.MapFrom(s => s.Number)); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().ForMember(d => d.OddNumber, o => o.MapFrom(s => s.Number)); + }); - protected override void Because_of() - { - _destination = Mapper.Map(new Source()); - } + protected override void Because_of() + { + _destination = Mapper.Map(new Source()); + } - [Fact] - public void Should_map_nullable_decimal_with_ResolveUsing() - { - _destination.OddNumber.ShouldBeNull(); - } + [Fact] + public void Should_map_nullable_decimal_with_ResolveUsing() + { + _destination.OddNumber.ShouldBeNull(); } } \ No newline at end of file diff --git a/src/UnitTests/Bug/NullableToInvalid.cs b/src/UnitTests/Bug/NullableToInvalid.cs index 96ad09ef49..667928165a 100644 --- a/src/UnitTests/Bug/NullableToInvalid.cs +++ b/src/UnitTests/Bug/NullableToInvalid.cs @@ -2,33 +2,32 @@ using Shouldly; using Xunit; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class NullableToInvalid : NonValidatingSpecBase { - public class NullableToInvalid : NonValidatingSpecBase + public class Source { - public class Source - { - public int? Value { get; set; } - } + public int? Value { get; set; } + } - public class Destination - { - public SomeObject Value { get; set; } - } + public class Destination + { + public SomeObject Value { get; set; } + } - public class SomeObject - { - } + public class SomeObject + { + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + }); - [Fact] - public void Should_not_validate() - { - new Action(AssertConfigurationIsValid).ShouldThrow(); - } + [Fact] + public void Should_not_validate() + { + new Action(AssertConfigurationIsValid).ShouldThrow(); } } diff --git a/src/UnitTests/Bug/NullableUntypedMapFrom.cs b/src/UnitTests/Bug/NullableUntypedMapFrom.cs index 4ba05a9b41..e4966c5557 100644 --- a/src/UnitTests/Bug/NullableUntypedMapFrom.cs +++ b/src/UnitTests/Bug/NullableUntypedMapFrom.cs @@ -1,35 +1,34 @@ using Xunit; using Shouldly; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class NullableUntypedMapFrom : AutoMapperSpecBase { - public class NullableUntypedMapFrom : AutoMapperSpecBase - { - private Destination _destination; + private Destination _destination; - class Source - { - public decimal? Number { get; set; } - } - class Destination - { - public decimal? OddNumber { get; set; } - } + class Source + { + public decimal? Number { get; set; } + } + class Destination + { + public decimal? OddNumber { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().ForMember(d => d.OddNumber, o => o.MapFrom(s => (object)s.Number)); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().ForMember(d => d.OddNumber, o => o.MapFrom(s => (object)s.Number)); + }); - protected override void Because_of() - { - _destination = Mapper.Map(new Source { Number = 12 }); - } + protected override void Because_of() + { + _destination = Mapper.Map(new Source { Number = 12 }); + } - [Fact] - public void Should_map_nullable_decimal() - { - _destination.OddNumber.ShouldBe(12); - } + [Fact] + public void Should_map_nullable_decimal() + { + _destination.OddNumber.ShouldBe(12); } } \ No newline at end of file diff --git a/src/UnitTests/Bug/ObjectEnumToObjectEnum.cs b/src/UnitTests/Bug/ObjectEnumToObjectEnum.cs index a41999be60..9e2df7d2ad 100644 --- a/src/UnitTests/Bug/ObjectEnumToObjectEnum.cs +++ b/src/UnitTests/Bug/ObjectEnumToObjectEnum.cs @@ -3,49 +3,48 @@ using AutoMapper.Internal.Mappers; using Xunit; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class ObjectEnumToObjectEnum : AutoMapperSpecBase { - public class ObjectEnumToObjectEnum : AutoMapperSpecBase + Target _target; + + public enum SourceEnumValue + { + Donkey, + Mule + } + + public enum TargetEnumValue + { + Donkey, + Mule + } + + public class Source + { + public object Value { get; set; } + } + + public class Target + { + public object Value { get; set; } + } + + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + var parentMapping = cfg.CreateMap(); + parentMapping.ForMember(dest => dest.Value, opt => opt.MapFrom(s => (TargetEnumValue) s.Value)); + }); + + protected override void Because_of() + { + _target = Mapper.Map(new Source { Value = SourceEnumValue.Mule }); + } + + [Fact] + public void Should_be_enum() { - Target _target; - - public enum SourceEnumValue - { - Donkey, - Mule - } - - public enum TargetEnumValue - { - Donkey, - Mule - } - - public class Source - { - public object Value { get; set; } - } - - public class Target - { - public object Value { get; set; } - } - - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - var parentMapping = cfg.CreateMap(); - parentMapping.ForMember(dest => dest.Value, opt => opt.MapFrom(s => (TargetEnumValue) s.Value)); - }); - - protected override void Because_of() - { - _target = Mapper.Map(new Source { Value = SourceEnumValue.Mule }); - } - - [Fact] - public void Should_be_enum() - { - _target.Value.ShouldBeOfType(); - } + _target.Value.ShouldBeOfType(); } } \ No newline at end of file diff --git a/src/UnitTests/Bug/ObjectTypeMapFailure.cs b/src/UnitTests/Bug/ObjectTypeMapFailure.cs index 307465ac36..805773a0ec 100644 --- a/src/UnitTests/Bug/ObjectTypeMapFailure.cs +++ b/src/UnitTests/Bug/ObjectTypeMapFailure.cs @@ -1,37 +1,36 @@ using Xunit; using Shouldly; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class ObjectTypeMapFailure : NonValidatingSpecBase { - public class ObjectTypeMapFailure : NonValidatingSpecBase + [Fact] + public void Should_map_the_object_type() { - [Fact] - public void Should_map_the_object_type() + var displayModel = new DisplayModel { - var displayModel = new DisplayModel - { - Radius = 300 - }; - object vm = new SomeViewModel(); - var config = new MapperConfiguration(cfg => cfg.CreateMap()); + Radius = 300 + }; + object vm = new SomeViewModel(); + var config = new MapperConfiguration(cfg => cfg.CreateMap()); - var mapper = config.CreateMapper(); - mapper.Map(displayModel, vm); - ((SomeViewModel)vm).Radius.ShouldBe(300); // fails + var mapper = config.CreateMapper(); + mapper.Map(displayModel, vm); + ((SomeViewModel)vm).Radius.ShouldBe(300); // fails - var vm2 = new SomeViewModel(); - mapper.Map(displayModel, vm2); - vm2.Radius.ShouldBe(300); // succeeds - } + var vm2 = new SomeViewModel(); + mapper.Map(displayModel, vm2); + vm2.Radius.ShouldBe(300); // succeeds + } - public class SomeViewModel - { - public int Radius { get; set; } - } + public class SomeViewModel + { + public int Radius { get; set; } + } - public class DisplayModel - { - public int Radius { get; set; } - } + public class DisplayModel + { + public int Radius { get; set; } } } diff --git a/src/UnitTests/Bug/OneSourceWithMultipleDestinationsAndPreserveReferences.cs b/src/UnitTests/Bug/OneSourceWithMultipleDestinationsAndPreserveReferences.cs index e788f29fa2..92a09e9496 100644 --- a/src/UnitTests/Bug/OneSourceWithMultipleDestinationsAndPreserveReferences.cs +++ b/src/UnitTests/Bug/OneSourceWithMultipleDestinationsAndPreserveReferences.cs @@ -1,43 +1,42 @@ using Xunit; using Shouldly; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class OneSourceWithMultipleDestinationsAndPreserveReferences : AutoMapperSpecBase { - public class OneSourceWithMultipleDestinationsAndPreserveReferences : AutoMapperSpecBase - { - ClientModel _destination; + ClientModel _destination; - public partial class Client - { - public string Address1 { get; set; } - } - public class AddressModel - { - public string Address1 { get; set; } - } - public class ClientModel - { - public AddressModel Address { get; set; } - } + public partial class Client + { + public string Address1 { get; set; } + } + public class AddressModel + { + public string Address1 { get; set; } + } + public class ClientModel + { + public AddressModel Address { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(mapConfig => - { - mapConfig.CreateMap() - .ForMember(m => m.Address, opt => opt.MapFrom(x => x)) - .PreserveReferences(); - mapConfig.CreateMap() - .PreserveReferences(); - }); + protected override MapperConfiguration CreateConfiguration() => new(mapConfig => + { + mapConfig.CreateMap() + .ForMember(m => m.Address, opt => opt.MapFrom(x => x)) + .PreserveReferences(); + mapConfig.CreateMap() + .PreserveReferences(); + }); - protected override void Because_of() - { - _destination = Mapper.Map(new Client { Address1 = "abc" }); - } + protected override void Because_of() + { + _destination = Mapper.Map(new Client { Address1 = "abc" }); + } - [Fact] - public void Should_map_ok() - { - _destination.Address.Address1.ShouldBe("abc"); - } + [Fact] + public void Should_map_ok() + { + _destination.Address.Address1.ShouldBe("abc"); } } \ No newline at end of file diff --git a/src/UnitTests/Bug/OneSourceWithMultipleDestinationsWithoutPR.cs b/src/UnitTests/Bug/OneSourceWithMultipleDestinationsWithoutPR.cs index b1398139be..8188853321 100644 --- a/src/UnitTests/Bug/OneSourceWithMultipleDestinationsWithoutPR.cs +++ b/src/UnitTests/Bug/OneSourceWithMultipleDestinationsWithoutPR.cs @@ -1,41 +1,40 @@ using Xunit; using Shouldly; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class OneSourceWithMultipleDestinationsWithoutPR : AutoMapperSpecBase { - public class OneSourceWithMultipleDestinationsWithoutPR : AutoMapperSpecBase - { - ClientModel _destination; + ClientModel _destination; - public partial class Client - { - public string Address1 { get; set; } - } - public class AddressModel - { - public string Address1 { get; set; } - } - public class ClientModel - { - public AddressModel Address { get; set; } - } + public partial class Client + { + public string Address1 { get; set; } + } + public class AddressModel + { + public string Address1 { get; set; } + } + public class ClientModel + { + public AddressModel Address { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(mapConfig => - { - mapConfig.CreateMap() - .ForMember(m => m.Address, opt => opt.MapFrom(x => x)); - mapConfig.CreateMap(); - }); + protected override MapperConfiguration CreateConfiguration() => new(mapConfig => + { + mapConfig.CreateMap() + .ForMember(m => m.Address, opt => opt.MapFrom(x => x)); + mapConfig.CreateMap(); + }); - protected override void Because_of() - { - _destination = Mapper.Map(new Client { Address1 = "abc" }); - } + protected override void Because_of() + { + _destination = Mapper.Map(new Client { Address1 = "abc" }); + } - [Fact] - public void Should_map_ok() - { - _destination.Address.Address1.ShouldBe("abc"); - } + [Fact] + public void Should_map_ok() + { + _destination.Address.Address1.ShouldBe("abc"); } } \ No newline at end of file diff --git a/src/UnitTests/Bug/PreserveReferencesSameDestination.cs b/src/UnitTests/Bug/PreserveReferencesSameDestination.cs index add1e723bd..881909cd72 100644 --- a/src/UnitTests/Bug/PreserveReferencesSameDestination.cs +++ b/src/UnitTests/Bug/PreserveReferencesSameDestination.cs @@ -4,89 +4,88 @@ using System.Linq; using System.Collections.Generic; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class Self_referencing_existing_destination : AutoMapperSpecBase { - public class Self_referencing_existing_destination : AutoMapperSpecBase + public class BaseType { - public class BaseType + public BaseType() { - public BaseType() - { - SelfReference = this; - } - public BaseType SelfReference { get; set; } + SelfReference = this; } + public BaseType SelfReference { get; set; } + } - public class BaseTypeDto + public class BaseTypeDto + { + public BaseTypeDto() { - public BaseTypeDto() - { - SelfReference = this; - } - public BaseTypeDto SelfReference { get; set; } + SelfReference = this; } + public BaseTypeDto SelfReference { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg=> cfg.CreateMap().PreserveReferences()); - [Fact] - public void Should_work() - { - var baseType = new BaseType(); - var baseTypeDto = new BaseTypeDto(); + protected override MapperConfiguration CreateConfiguration() => new(cfg=> cfg.CreateMap().PreserveReferences()); + [Fact] + public void Should_work() + { + var baseType = new BaseType(); + var baseTypeDto = new BaseTypeDto(); - Mapper.Map(baseType, baseTypeDto); - } + Mapper.Map(baseType, baseTypeDto); } +} - public class PreserveReferencesSameDestination : AutoMapperSpecBase +public class PreserveReferencesSameDestination : AutoMapperSpecBase +{ + public class DtoOne { - public class DtoOne - { - public DtoTwo Two { get; set; } - } + public DtoTwo Two { get; set; } + } - public class DtoTwo - { - public virtual ICollection Ones { get; set; } - } + public class DtoTwo + { + public virtual ICollection Ones { get; set; } + } - public class DtoThree - { - public int Id { get; set; } - } + public class DtoThree + { + public int Id { get; set; } + } - public class EntityOne - { - public int Id { get; set; } - public EntityTwo Two { get; set; } - } + public class EntityOne + { + public int Id { get; set; } + public EntityTwo Two { get; set; } + } - public class EntityTwo - { - public virtual ICollection Ones { get; set; } - } + public class EntityTwo + { + public virtual ICollection Ones { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().PreserveReferences(); - cfg.CreateMap().PreserveReferences(); - cfg.CreateMap().PreserveReferences(); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().PreserveReferences(); + cfg.CreateMap().PreserveReferences(); + cfg.CreateMap().PreserveReferences(); + }); - [Fact] - public void Should_use_the_right_map() - { - var source = - new EntityOne { - Two = new EntityTwo { - Ones = new List { - new EntityOne { - Two = new EntityTwo { Ones = new List() } - } + [Fact] + public void Should_use_the_right_map() + { + var source = + new EntityOne { + Two = new EntityTwo { + Ones = new List { + new EntityOne { + Two = new EntityTwo { Ones = new List() } } } - }; - Mapper.Map(source).ShouldBeOfType(); - Mapper.Map(source).ShouldBeOfType(); - } + } + }; + Mapper.Map(source).ShouldBeOfType(); + Mapper.Map(source).ShouldBeOfType(); } } \ No newline at end of file diff --git a/src/UnitTests/Bug/ProjectConstructorParameters.cs b/src/UnitTests/Bug/ProjectConstructorParameters.cs index 886c90c6e4..21de3d19a3 100644 --- a/src/UnitTests/Bug/ProjectConstructorParameters.cs +++ b/src/UnitTests/Bug/ProjectConstructorParameters.cs @@ -3,55 +3,54 @@ using Shouldly; using Xunit; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class ProjectConstructorParameters : AutoMapperSpecBase { - public class ProjectConstructorParameters : AutoMapperSpecBase + SourceDto _dest; + const int SomeValue = 15; + + public class Inner { - SourceDto _dest; - const int SomeValue = 15; + public int Member { get; set; } + } - public class Inner - { - public int Member { get; set; } - } + public class Source + { + public int Value { get; set; } + public Inner Inner { get; set; } + } + + public class SourceDto + { + private int _value; - public class Source + public SourceDto(int innerMember) { - public int Value { get; set; } - public Inner Inner { get; set; } + _value = innerMember; } - public class SourceDto + public int Value { - private int _value; - - public SourceDto(int innerMember) - { - _value = innerMember; - } - - public int Value - { - get { return _value; } - } + get { return _value; } } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateProjection(); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateProjection(); + }); - protected override void Because_of() - { - var source = new Source { Inner = new Inner { Member = SomeValue } }; - //_dest = Mapper.Map(source); - _dest = new[] { source }.AsQueryable().ProjectTo(Configuration).First(); - } + protected override void Because_of() + { + var source = new Source { Inner = new Inner { Member = SomeValue } }; + //_dest = Mapper.Map(source); + _dest = new[] { source }.AsQueryable().ProjectTo(Configuration).First(); + } - [Fact] - public void Should_project_constructor_parameter_mappings() - { - _dest.Value.ShouldBe(SomeValue); - } + [Fact] + public void Should_project_constructor_parameter_mappings() + { + _dest.Value.ShouldBe(SomeValue); } } \ No newline at end of file diff --git a/src/UnitTests/Bug/ProjectUsingTheQueriedEntity.cs b/src/UnitTests/Bug/ProjectUsingTheQueriedEntity.cs index 9d9140d239..c166ee6781 100644 --- a/src/UnitTests/Bug/ProjectUsingTheQueriedEntity.cs +++ b/src/UnitTests/Bug/ProjectUsingTheQueriedEntity.cs @@ -4,35 +4,34 @@ using System.Linq; using AutoMapper.QueryableExtensions; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class ProjectUsingTheQueriedEntity : AutoMapperSpecBase { - public class ProjectUsingTheQueriedEntity : AutoMapperSpecBase - { - private Destination _destination; + private Destination _destination; - class Source - { - public int Number { get; set; } - } - class Destination - { - public int Number { get; set; } - } + class Source + { + public int Number { get; set; } + } + class Destination + { + public int Number { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateProjection().ConvertUsing(s => new Destination {Number = 23 + s.Number}); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateProjection().ConvertUsing(s => new Destination {Number = 23 + s.Number}); + }); - protected override void Because_of() - { - _destination = new[] { new Source() }.AsQueryable().ProjectTo(Configuration).First(); - } + protected override void Because_of() + { + _destination = new[] { new Source() }.AsQueryable().ProjectTo(Configuration).First(); + } - [Fact] - public void Should_handle_projectusing_with_the_queried_entity() - { - _destination.Number.ShouldBe(23); - } + [Fact] + public void Should_handle_projectusing_with_the_queried_entity() + { + _destination.Number.ShouldBe(23); } } \ No newline at end of file diff --git a/src/UnitTests/Bug/PropertyNamedType.cs b/src/UnitTests/Bug/PropertyNamedType.cs index efa2f1c4a0..cdcbc08074 100644 --- a/src/UnitTests/Bug/PropertyNamedType.cs +++ b/src/UnitTests/Bug/PropertyNamedType.cs @@ -2,25 +2,24 @@ using Shouldly; using System; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class PropertyNamedType { - public class PropertyNamedType + class Source + { + public int Number { get; set; } + } + class Destination { - class Source - { - public int Number { get; set; } - } - class Destination - { - public int Type { get; set; } - } + public int Type { get; set; } + } - [Fact] - public void Should_detect_unmapped_destination_property_named_type() - { - var config = new MapperConfiguration(c=>c.CreateMap()); - new Action(config.AssertConfigurationIsValid).ShouldThrowException( - ex=>ex.Errors[0].UnmappedPropertyNames[0].ShouldBe("Type")); - } + [Fact] + public void Should_detect_unmapped_destination_property_named_type() + { + var config = new MapperConfiguration(c=>c.CreateMap()); + new Action(config.AssertConfigurationIsValid).ShouldThrowException( + ex=>ex.Errors[0].UnmappedPropertyNames[0].ShouldBe("Type")); } } \ No newline at end of file diff --git a/src/UnitTests/Bug/ReadOnlyCollectionMappingBug.cs b/src/UnitTests/Bug/ReadOnlyCollectionMappingBug.cs index 5b99a425a8..f37310f114 100644 --- a/src/UnitTests/Bug/ReadOnlyCollectionMappingBug.cs +++ b/src/UnitTests/Bug/ReadOnlyCollectionMappingBug.cs @@ -3,25 +3,24 @@ using Shouldly; using Xunit; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +// Bug #511 +// https://github.com/AutoMapper/AutoMapper/issues/511 +public class ReadOnlyCollectionMappingBug { - // Bug #511 - // https://github.com/AutoMapper/AutoMapper/issues/511 - public class ReadOnlyCollectionMappingBug - { - class Source { public int X { get; set; } } - class Target { public int X { get; set; } } + class Source { public int X { get; set; } } + class Target { public int X { get; set; } } - [Fact] - public void Example() - { - var config = new MapperConfiguration(cfg => cfg.CreateMap()); + [Fact] + public void Example() + { + var config = new MapperConfiguration(cfg => cfg.CreateMap()); - var source = new List { new Source { X = 42 } }; - var target = config.CreateMapper().Map>(source); + var source = new List { new Source { X = 42 } }; + var target = config.CreateMapper().Map>(source); - target.Count.ShouldBe(source.Count); - target[0].X.ShouldBe(source[0].X); - } + target.Count.ShouldBe(source.Count); + target[0].X.ShouldBe(source[0].X); } } diff --git a/src/UnitTests/Bug/ReadOnlyFieldMappingBug.cs b/src/UnitTests/Bug/ReadOnlyFieldMappingBug.cs index 049eb3bbfa..2690c700a6 100644 --- a/src/UnitTests/Bug/ReadOnlyFieldMappingBug.cs +++ b/src/UnitTests/Bug/ReadOnlyFieldMappingBug.cs @@ -1,39 +1,38 @@ using Shouldly; using Xunit; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class ReadOnlyFieldMappingBug : AutoMapperSpecBase { - public class ReadOnlyFieldMappingBug : AutoMapperSpecBase + public class Source { - public class Source - { - public string Value { get; set; } - } + public string Value { get; set; } + } - public class Destination - { - public readonly string Value; + public class Destination + { + public readonly string Value; - public Destination(string value) - { - Value = value; - } + public Destination(string value) + { + Value = value; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - // BUG. ArgumentException : Expression must be writeable - cfg.CreateMap(); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + // BUG. ArgumentException : Expression must be writeable + cfg.CreateMap(); + }); - [Fact] - public void Should_map_over_constructor() - { - var source = new Source { Value = "value" }; + [Fact] + public void Should_map_over_constructor() + { + var source = new Source { Value = "value" }; - var dest = Mapper.Map(source); + var dest = Mapper.Map(source); - dest.Value.ShouldBe(source.Value); - } + dest.Value.ShouldBe(source.Value); } } \ No newline at end of file diff --git a/src/UnitTests/Bug/RecognizeDestinationPostfixes.cs b/src/UnitTests/Bug/RecognizeDestinationPostfixes.cs index 7452f99fb1..b4d911bed5 100644 --- a/src/UnitTests/Bug/RecognizeDestinationPostfixes.cs +++ b/src/UnitTests/Bug/RecognizeDestinationPostfixes.cs @@ -2,35 +2,34 @@ using System; using Xunit; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class RecognizeDestinationPostfixes : AutoMapperSpecBase { - public class RecognizeDestinationPostfixes : AutoMapperSpecBase + class Person { - class Person - { - public int Age { get; set; } - public int Age2 => 2017 - Birthday.Year; - public DateTime Birthday { get; set; } - public string Name { get; set; } - } + public int Age { get; set; } + public int Age2 => 2017 - Birthday.Year; + public DateTime Birthday { get; set; } + public string Name { get; set; } + } - class PersonDto - { - public int AgeV { get; set; } - public string NameV { get; set; } - } + class PersonDto + { + public int AgeV { get; set; } + public string NameV { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg=> - { - cfg.RecognizeDestinationPostfixes("V"); - cfg.CreateMap().ForMember("AgeV", m => m.MapFrom("Age2")); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg=> + { + cfg.RecognizeDestinationPostfixes("V"); + cfg.CreateMap().ForMember("AgeV", m => m.MapFrom("Age2")); + }); - [Fact] - public void Should_be_overriden_by_MapFrom() - { - var person = new Person { Birthday = new DateTime(2000, 1, 1), Name = "Shy" }; - Mapper.Map(person).AgeV.ShouldBe(17); - } + [Fact] + public void Should_be_overriden_by_MapFrom() + { + var person = new Person { Birthday = new DateTime(2000, 1, 1), Name = "Shy" }; + Mapper.Map(person).AgeV.ShouldBe(17); } } diff --git a/src/UnitTests/Bug/RemovePrefixes.cs b/src/UnitTests/Bug/RemovePrefixes.cs index 863b92c20e..c35411cf15 100644 --- a/src/UnitTests/Bug/RemovePrefixes.cs +++ b/src/UnitTests/Bug/RemovePrefixes.cs @@ -3,29 +3,28 @@ using System; using AutoMapper.Internal.Mappers; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class RemovePrefixes : NonValidatingSpecBase { - public class RemovePrefixes : NonValidatingSpecBase + class Source + { + public int GetNumber { get; set; } + } + class Destination { - class Source - { - public int GetNumber { get; set; } - } - class Destination - { - public int Number { get; set; } - } + public int Number { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.ClearPrefixes(); - cfg.CreateMap(); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.ClearPrefixes(); + cfg.CreateMap(); + }); - [Fact] - public void Should_not_map_with_default_postfix() - { - new Action(AssertConfigurationIsValid).ShouldThrow(); - } + [Fact] + public void Should_not_map_with_default_postfix() + { + new Action(AssertConfigurationIsValid).ShouldThrow(); } } \ No newline at end of file diff --git a/src/UnitTests/Bug/RepeatedMappingConfigurationTest.cs b/src/UnitTests/Bug/RepeatedMappingConfigurationTest.cs index 0b4e9766ec..2ae967ffb7 100644 --- a/src/UnitTests/Bug/RepeatedMappingConfigurationTest.cs +++ b/src/UnitTests/Bug/RepeatedMappingConfigurationTest.cs @@ -1,44 +1,43 @@ using Xunit; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class When_mapping_for_derived_class_is_duplicated : NonValidatingSpecBase { - public class When_mapping_for_derived_class_is_duplicated : NonValidatingSpecBase + public class ModelObject { - public class ModelObject - { - public string BaseString { get; set; } - } + public string BaseString { get; set; } + } - public class ModelSubObject : ModelObject - { - public string SubString { get; set; } - } + public class ModelSubObject : ModelObject + { + public string SubString { get; set; } + } - public class DtoObject - { - public string BaseString { get; set; } - } + public class DtoObject + { + public string BaseString { get; set; } + } - public class DtoSubObject : DtoObject - { - public string SubString { get; set; } - } + public class DtoSubObject : DtoObject + { + public string SubString { get; set; } + } - [Fact] - public void should_not_throw_duplicated_key_exception() + [Fact] + public void should_not_throw_duplicated_key_exception() + { + new MapperConfiguration(cfg => { - new MapperConfiguration(cfg => - { - cfg.CreateMap() - .Include(); + cfg.CreateMap() + .Include(); - cfg.CreateMap(); + cfg.CreateMap(); - cfg.CreateMap() - .Include(); + cfg.CreateMap() + .Include(); - cfg.CreateMap(); - }); - } + cfg.CreateMap(); + }); } } diff --git a/src/UnitTests/Bug/ReportMissingInclude.cs b/src/UnitTests/Bug/ReportMissingInclude.cs index d6f153f118..ead988c6fb 100644 --- a/src/UnitTests/Bug/ReportMissingInclude.cs +++ b/src/UnitTests/Bug/ReportMissingInclude.cs @@ -2,81 +2,80 @@ using Shouldly; using System; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class ReportMissingInclude { - public class ReportMissingInclude + [Fact] + public void ShouldDiscoverMissingMappingsInIncludedType() { - [Fact] - public void ShouldDiscoverMissingMappingsInIncludedType() + new Action(() => new MapperConfiguration(cfg => { - new Action(() => new MapperConfiguration(cfg => - { - cfg.CreateMap().Include(); - })).ShouldThrowException(ex => ex.Message.ShouldStartWith($"Missing map from {typeof(object)} to {typeof(ChildType)}.")); - } + cfg.CreateMap().Include(); + })).ShouldThrowException(ex => ex.Message.ShouldStartWith($"Missing map from {typeof(object)} to {typeof(ChildType)}.")); + } - public class BaseType { } + public class BaseType { } - public class ChildType : BaseType - { - public string Value { get; set; } - } + public class ChildType : BaseType + { + public string Value { get; set; } } +} - public class ReportMissingIncludeCreateMissingMap +public class ReportMissingIncludeCreateMissingMap +{ + [Fact] + public void ShouldDiscoverMissingMappingsInIncludedType() { - [Fact] - public void ShouldDiscoverMissingMappingsInIncludedType() + new Action(() => new MapperConfiguration(cfg => { - new Action(() => new MapperConfiguration(cfg => - { - cfg.CreateMap().Include(); - })).ShouldThrowException(ex => ex.Message.ShouldStartWith($"Missing map from {typeof(ReportMissingIncludeCreateMissingMap)} to {typeof(ChildType)}.")); - } + cfg.CreateMap().Include(); + })).ShouldThrowException(ex => ex.Message.ShouldStartWith($"Missing map from {typeof(ReportMissingIncludeCreateMissingMap)} to {typeof(ChildType)}.")); + } - public class BaseType { } + public class BaseType { } - public class ChildType : BaseType - { - public string Value { get; set; } - } + public class ChildType : BaseType + { + public string Value { get; set; } } +} - public class ReportMissingIncludeBase +public class ReportMissingIncludeBase +{ + [Fact] + public void ShouldDiscoverMissingMappingsInIncludedType() { - [Fact] - public void ShouldDiscoverMissingMappingsInIncludedType() + new Action(() => new MapperConfiguration(cfg => { - new Action(() => new MapperConfiguration(cfg => - { - cfg.CreateMap().IncludeBase(); - })).ShouldThrowException(ex => ex.Message.ShouldStartWith($"Missing map from {typeof(object)} to {typeof(BaseType)}.")); - } + cfg.CreateMap().IncludeBase(); + })).ShouldThrowException(ex => ex.Message.ShouldStartWith($"Missing map from {typeof(object)} to {typeof(BaseType)}.")); + } - public class BaseType { } + public class BaseType { } - public class ChildType : BaseType - { - public string Value { get; set; } - } + public class ChildType : BaseType + { + public string Value { get; set; } } +} - public class ReportMissingIncludeBaseCreateMissingMap +public class ReportMissingIncludeBaseCreateMissingMap +{ + [Fact] + public void ShouldDiscoverMissingMappingsInIncludedType() { - [Fact] - public void ShouldDiscoverMissingMappingsInIncludedType() + new Action(() => new MapperConfiguration(cfg => { - new Action(() => new MapperConfiguration(cfg => - { - cfg.CreateMap().IncludeBase(); - })).ShouldThrowException(ex => ex.Message.ShouldStartWith($"Missing map from {typeof(ReportMissingIncludeBaseCreateMissingMap)} to {typeof(BaseType)}.")); - } + cfg.CreateMap().IncludeBase(); + })).ShouldThrowException(ex => ex.Message.ShouldStartWith($"Missing map from {typeof(ReportMissingIncludeBaseCreateMissingMap)} to {typeof(BaseType)}.")); + } - public class BaseType { } + public class BaseType { } - public class ChildType : BaseType - { - public string Value { get; set; } - } + public class ChildType : BaseType + { + public string Value { get; set; } } } \ No newline at end of file diff --git a/src/UnitTests/Bug/ReverseMapReplaceMemberName.cs b/src/UnitTests/Bug/ReverseMapReplaceMemberName.cs index 4291264219..462bff2e45 100644 --- a/src/UnitTests/Bug/ReverseMapReplaceMemberName.cs +++ b/src/UnitTests/Bug/ReverseMapReplaceMemberName.cs @@ -2,100 +2,99 @@ using Shouldly; using System; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class ReverseMapAndReplaceMemberName : AutoMapperSpecBase { - public class ReverseMapAndReplaceMemberName : AutoMapperSpecBase + const string SomeId = "someId"; + const string SomeOtherId = "someOtherId"; + private Source _source; + private Destination _destination; + + class Source { - const string SomeId = "someId"; - const string SomeOtherId = "someOtherId"; - private Source _source; - private Destination _destination; + public string AccountId { get; set; } + } + class Destination + { + public string UserId { get; set; } + } - class Source - { - public string AccountId { get; set; } - } - class Destination - { - public string UserId { get; set; } - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.ReplaceMemberName("Account", "User"); + cfg.ReplaceMemberName("User", "Account"); + cfg.CreateMap().ReverseMap(); + }); - protected override MapperConfiguration CreateConfiguration() => new(cfg => + protected override void Because_of() + { + _source = Mapper.Map(new Destination { - cfg.ReplaceMemberName("Account", "User"); - cfg.ReplaceMemberName("User", "Account"); - cfg.CreateMap().ReverseMap(); + UserId = SomeId }); - - protected override void Because_of() + _destination = Mapper.Map(new Source { - _source = Mapper.Map(new Destination - { - UserId = SomeId - }); - _destination = Mapper.Map(new Source - { - AccountId = SomeOtherId - }); - } + AccountId = SomeOtherId + }); + } - [Fact] - public void Should_work_together() - { - _source.AccountId.ShouldBe(SomeId); - _destination.UserId.ShouldBe(SomeOtherId); - } + [Fact] + public void Should_work_together() + { + _source.AccountId.ShouldBe(SomeId); + _destination.UserId.ShouldBe(SomeOtherId); } +} + +public class ReverseMapAndReplaceMemberNameWithProfile : AutoMapperSpecBase +{ + const string SomeId = "someId"; + const string SomeOtherId = "someOtherId"; + private Source _source; + private Destination _destination; - public class ReverseMapAndReplaceMemberNameWithProfile : AutoMapperSpecBase + class Source { - const string SomeId = "someId"; - const string SomeOtherId = "someOtherId"; - private Source _source; - private Destination _destination; + public string AccountId { get; set; } + } - class Source - { - public string AccountId { get; set; } - } + class Destination + { + public string UserId { get; set; } + } - class Destination + class MyProfile : Profile + { + public MyProfile() { - public string UserId { get; set; } + ReplaceMemberName("Account", "User"); + ReplaceMemberName("User", "Account"); + CreateMap().ReverseMap(); } + } - class MyProfile : Profile - { - public MyProfile() - { - ReplaceMemberName("Account", "User"); - ReplaceMemberName("User", "Account"); - CreateMap().ReverseMap(); - } - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.AddProfile(); + }); - protected override MapperConfiguration CreateConfiguration() => new(cfg => + protected override void Because_of() + { + _source = Mapper.Map(new Destination { - cfg.AddProfile(); + UserId = SomeId }); - - protected override void Because_of() + _destination = Mapper.Map(new Source { - _source = Mapper.Map(new Destination - { - UserId = SomeId - }); - _destination = Mapper.Map(new Source - { - AccountId = SomeOtherId - }); - } + AccountId = SomeOtherId + }); + } - [Fact] - public void Should_work_together() - { - _source.AccountId.ShouldBe(SomeId); - _destination.UserId.ShouldBe(SomeOtherId); - } + [Fact] + public void Should_work_together() + { + _source.AccountId.ShouldBe(SomeId); + _destination.UserId.ShouldBe(SomeOtherId); } } \ No newline at end of file diff --git a/src/UnitTests/Bug/SelectiveConfigurationValidation.cs b/src/UnitTests/Bug/SelectiveConfigurationValidation.cs index 803ea3a8e4..1f69759648 100644 --- a/src/UnitTests/Bug/SelectiveConfigurationValidation.cs +++ b/src/UnitTests/Bug/SelectiveConfigurationValidation.cs @@ -1,50 +1,49 @@ -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +using System; +using Xunit; + +public class SelectiveConfigurationValidation : NonValidatingSpecBase { - using System; - using Xunit; + public class GoodSrc { } + public class GoodDest { } - public class SelectiveConfigurationValidation : NonValidatingSpecBase + public class BadSrc { - public class GoodSrc { } - public class GoodDest { } - - public class BadSrc - { - public Type BlowUp { get; set; } - } + public Type BlowUp { get; set; } + } - public class BadDest - { - public int Value { get; set; } - public int BlowUp { get; set; } - } - public class GoodProfile : Profile + public class BadDest + { + public int Value { get; set; } + public int BlowUp { get; set; } + } + public class GoodProfile : Profile + { + public GoodProfile() { - public GoodProfile() - { - CreateMap(); - } + CreateMap(); } + } - public class BadProfile : Profile + public class BadProfile : Profile + { + public BadProfile() { - public BadProfile() - { - CreateMap(); - } + CreateMap(); } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.AddProfile(); - cfg.AddProfile(); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.AddProfile(); + cfg.AddProfile(); + }); - [Fact] - public void Should_pass_specific_profile_assertion() - { - typeof(AutoMapperConfigurationException) - .ShouldNotBeThrownBy(AssertConfigurationIsValid); - } + [Fact] + public void Should_pass_specific_profile_assertion() + { + typeof(AutoMapperConfigurationException) + .ShouldNotBeThrownBy(AssertConfigurationIsValid); } } \ No newline at end of file diff --git a/src/UnitTests/Bug/SequenceContainsNoElementsTest.cs b/src/UnitTests/Bug/SequenceContainsNoElementsTest.cs index 5e259fef43..7d89ad0cbc 100644 --- a/src/UnitTests/Bug/SequenceContainsNoElementsTest.cs +++ b/src/UnitTests/Bug/SequenceContainsNoElementsTest.cs @@ -6,43 +6,42 @@ using Xunit; using Shouldly; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class SequenceContainsNoElementsTest : AutoMapperSpecBase { - public class SequenceContainsNoElementsTest : AutoMapperSpecBase + protected override MapperConfiguration CreateConfiguration() => new(cfg => { - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - }); - - [Fact] - public void should_not_throw_InvalidOperationException() - { - Person[] personArr = new Person[] { }; - People people = new People(personArr); - var pmc = Mapper.Map>(people); - pmc.ShouldNotBeNull(); - pmc.Count.ShouldBe(0); - } - } + cfg.CreateMap(); + }); - public class People : IEnumerable + [Fact] + public void should_not_throw_InvalidOperationException() { - private readonly Person[] people; - public People(Person[] people) - { - this.people = people; - } - public IEnumerator GetEnumerator() => people.GetEnumerator(); + Person[] personArr = new Person[] { }; + People people = new People(personArr); + var pmc = Mapper.Map>(people); + pmc.ShouldNotBeNull(); + pmc.Count.ShouldBe(0); } +} - public class Person +public class People : IEnumerable +{ + private readonly Person[] people; + public People(Person[] people) { - public string Name { get; set; } + this.people = people; } + public IEnumerator GetEnumerator() => people.GetEnumerator(); +} - public class PersonModel - { - public string Name { get; set; } - } +public class Person +{ + public string Name { get; set; } +} + +public class PersonModel +{ + public string Name { get; set; } } diff --git a/src/UnitTests/Bug/StructMapping.cs b/src/UnitTests/Bug/StructMapping.cs index 2bfa3d0679..d7e75fb7c4 100644 --- a/src/UnitTests/Bug/StructMapping.cs +++ b/src/UnitTests/Bug/StructMapping.cs @@ -2,55 +2,54 @@ using Shouldly; using System; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class StructMapping : AutoMapperSpecBase { - public class StructMapping : AutoMapperSpecBase - { - private Destination _destination; + private Destination _destination; - struct Source - { - public int Number { get; set; } - } - class Destination - { - public int Number { get; set; } - } + struct Source + { + public int Number { get; set; } + } + class Destination + { + public int Number { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + }); - protected override void Because_of() + protected override void Because_of() + { + var source = new Source { - var source = new Source - { - Number = 23 - }; - _destination = Mapper.Map(source); - } + Number = 23 + }; + _destination = Mapper.Map(source); + } - [Fact] - public void Should_work() - { - _destination.Number.ShouldBe(23); - } + [Fact] + public void Should_work() + { + _destination.Number.ShouldBe(23); } - public class DestinationStructMapping : AutoMapperSpecBase +} +public class DestinationStructMapping : AutoMapperSpecBase +{ + struct Source { - struct Source - { - public int Number { get; set; } - } - struct Destination - { - public int Number { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.CreateMap()); - [Fact] - public void Should_work() => Mapper.Map(new Source { Number = 23 }).Number.ShouldBe(23); - [Fact] - public void Should_work_with_object() => ((Destination)Mapper.Map(new Source { Number = 23 }, typeof(Source), typeof(Destination))).Number.ShouldBe(23); + public int Number { get; set; } + } + struct Destination + { + public int Number { get; set; } } + protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.CreateMap()); + [Fact] + public void Should_work() => Mapper.Map(new Source { Number = 23 }).Number.ShouldBe(23); + [Fact] + public void Should_work_with_object() => ((Destination)Mapper.Map(new Source { Number = 23 }, typeof(Source), typeof(Destination))).Number.ShouldBe(23); } \ No newline at end of file diff --git a/src/UnitTests/Bug/SubclassMappings.cs b/src/UnitTests/Bug/SubclassMappings.cs index fa65e7d5d1..3b94a507ac 100644 --- a/src/UnitTests/Bug/SubclassMappings.cs +++ b/src/UnitTests/Bug/SubclassMappings.cs @@ -1,41 +1,40 @@ using Xunit; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class SubclassMappings : AutoMapperSpecBase { - public class SubclassMappings : AutoMapperSpecBase + public class Source { - public class Source - { - public string Name { get; set; } - } + public string Name { get; set; } + } - public class Destination - { - public string Name { get; set; } - } + public class Destination + { + public string Name { get; set; } + } - public class SubDestination : Destination - { - public string SubName { get; set; } - } + public class SubDestination : Destination + { + public string SubName { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + }); - [Fact] - public void TestCase() - { + [Fact] + public void TestCase() + { - var source = new Source() { Name = "Test" }; - var destination = new Destination(); + var source = new Source() { Name = "Test" }; + var destination = new Destination(); - Mapper.Map(source, destination); // Works + Mapper.Map(source, destination); // Works - var subDestination = new SubDestination(); + var subDestination = new SubDestination(); - Mapper.Map(source, subDestination); // Fails - } + Mapper.Map(source, subDestination); // Fails } } \ No newline at end of file diff --git a/src/UnitTests/Bug/TargetISet.cs b/src/UnitTests/Bug/TargetISet.cs index b4f3a89330..2b33ecad2f 100644 --- a/src/UnitTests/Bug/TargetISet.cs +++ b/src/UnitTests/Bug/TargetISet.cs @@ -3,43 +3,42 @@ using System; using System.Collections.Generic; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class TargetISet : AutoMapperSpecBase { - public class TargetISet : AutoMapperSpecBase + Destination _destination; + string[] _items = new[] { "one", "two", "three" }; + + public class Source + { + public IEnumerable Items { get; set; } + } + + class Destination + { + public ISet Items { get; set; } + } + + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + }); + + protected override void Because_of() + { + _destination = Mapper.Map(new Source { Items = _items }); + } + + [Fact] + public void Should_map_IEnumerable_to_ISet() + { + _destination.Items.SetEquals(_items).ShouldBeTrue(); + } + + [Fact] + public void Should_map_null_to_empty() { - Destination _destination; - string[] _items = new[] { "one", "two", "three" }; - - public class Source - { - public IEnumerable Items { get; set; } - } - - class Destination - { - public ISet Items { get; set; } - } - - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - }); - - protected override void Because_of() - { - _destination = Mapper.Map(new Source { Items = _items }); - } - - [Fact] - public void Should_map_IEnumerable_to_ISet() - { - _destination.Items.SetEquals(_items).ShouldBeTrue(); - } - - [Fact] - public void Should_map_null_to_empty() - { - Mapper.Map(new Source()).ShouldNotBeNull(); - } + Mapper.Map(new Source()).ShouldNotBeNull(); } } \ No newline at end of file diff --git a/src/UnitTests/Bug/TypeMapIncludeBaseTypes.cs b/src/UnitTests/Bug/TypeMapIncludeBaseTypes.cs index 01a7f6b570..42214fc428 100644 --- a/src/UnitTests/Bug/TypeMapIncludeBaseTypes.cs +++ b/src/UnitTests/Bug/TypeMapIncludeBaseTypes.cs @@ -3,78 +3,77 @@ using System.Linq; using Xunit; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public abstract class TypeMapIncludeBaseTypes { - public abstract class TypeMapIncludeBaseTypes - { - public abstract class Source { public int? A { get; set; } } - public class SourceA : Source { } - public class SourceB : Source { } - public abstract class Target { public int? A { get; set; } } - public class TargetA : Target { } - public class TargetB : Target { } + public abstract class Source { public int? A { get; set; } } + public class SourceA : Source { } + public class SourceB : Source { } + public abstract class Target { public int? A { get; set; } } + public class TargetA : Target { } + public class TargetB : Target { } - public class IncludeFromBase : TypeMapIncludeBaseTypes + public class IncludeFromBase : TypeMapIncludeBaseTypes + { + protected override IGlobalConfiguration CreateConfigurationProvider() { - protected override IGlobalConfiguration CreateConfigurationProvider() + return new MapperConfiguration(cfg => { - return new MapperConfiguration(cfg => - { - cfg.CreateMap() - .Include() - .Include(); + cfg.CreateMap() + .Include() + .Include(); - cfg.CreateMap(); + cfg.CreateMap(); - cfg.CreateMap(); - }); - } + cfg.CreateMap(); + }); } + } - public class IncludeFromDerived : TypeMapIncludeBaseTypes + public class IncludeFromDerived : TypeMapIncludeBaseTypes + { + protected override IGlobalConfiguration CreateConfigurationProvider() { - protected override IGlobalConfiguration CreateConfigurationProvider() + return new MapperConfiguration(cfg => { - return new MapperConfiguration(cfg => - { - cfg.CreateMap(); + cfg.CreateMap(); - cfg.CreateMap() - .IncludeBase(); + cfg.CreateMap() + .IncludeBase(); - cfg.CreateMap() - .IncludeBase(); - }); - } + cfg.CreateMap() + .IncludeBase(); + }); } + } - [Fact] - public void TypeMap_Should_include_derivied_types() - { - var config = CreateConfigurationProvider(); - var typeMap = config.ResolveTypeMap(typeof(Source), typeof(Target)); - - var typePairs = new[]{ - new TypePair(typeof(SourceA), typeof(TargetA)), - new TypePair(typeof(SourceB), typeof(TargetB)), - }; + [Fact] + public void TypeMap_Should_include_derivied_types() + { + var config = CreateConfigurationProvider(); + var typeMap = config.ResolveTypeMap(typeof(Source), typeof(Target)); - typeMap.IncludedDerivedTypes.SequenceEqual(typePairs).ShouldBeTrue(); - } + var typePairs = new[]{ + new TypePair(typeof(SourceA), typeof(TargetA)), + new TypePair(typeof(SourceB), typeof(TargetB)), + }; - [Fact] - public void TypeMap_Should_include_base_types() - { - var config = CreateConfigurationProvider(); - var typeMap = config.ResolveTypeMap(typeof(SourceA), typeof(TargetA)); + typeMap.IncludedDerivedTypes.SequenceEqual(typePairs).ShouldBeTrue(); + } - var typePairs = new[]{ - new TypePair(typeof(Source), typeof(Target)) - }; + [Fact] + public void TypeMap_Should_include_base_types() + { + var config = CreateConfigurationProvider(); + var typeMap = config.ResolveTypeMap(typeof(SourceA), typeof(TargetA)); - typeMap.IncludedBaseTypes.SequenceEqual(typePairs).ShouldBeTrue(); - } + var typePairs = new[]{ + new TypePair(typeof(Source), typeof(Target)) + }; - protected abstract IGlobalConfiguration CreateConfigurationProvider(); + typeMap.IncludedBaseTypes.SequenceEqual(typePairs).ShouldBeTrue(); } + + protected abstract IGlobalConfiguration CreateConfigurationProvider(); } diff --git a/src/UnitTests/Bug/UseDestinationValue.cs b/src/UnitTests/Bug/UseDestinationValue.cs index 5434d34b16..a645b8a6a0 100644 --- a/src/UnitTests/Bug/UseDestinationValue.cs +++ b/src/UnitTests/Bug/UseDestinationValue.cs @@ -3,193 +3,192 @@ using System; using System.Collections.Generic; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class UseDestinationValue : AutoMapperSpecBase { - public class UseDestinationValue : AutoMapperSpecBase + public class OrganizationDTO { - public class OrganizationDTO - { - public long? ID { get; set; } - public string Name { get; set; } + public long? ID { get; set; } + public string Name { get; set; } - private CollectionDTOController _branchCollection; - public CollectionDTOController BranchCollection + private CollectionDTOController _branchCollection; + public CollectionDTOController BranchCollection + { + get { - get - { - if(_branchCollection == null) - _branchCollection = new CollectionDTOController(); - - return _branchCollection; - } - set { _branchCollection = value; } + if(_branchCollection == null) + _branchCollection = new CollectionDTOController(); + + return _branchCollection; } + set { _branchCollection = value; } } + } - public class BranchDTO - { - public short? ID { get; set; } - public string Name { get; set; } + public class BranchDTO + { + public short? ID { get; set; } + public string Name { get; set; } - } + } - public class CollectionDTOController - where T : class - where K : struct - { - public IEnumerable Models { get; set; } - public K? SelectedID { get; set; } - } + public class CollectionDTOController + where T : class + where K : struct + { + public IEnumerable Models { get; set; } + public K? SelectedID { get; set; } + } - public class Organization - { - public long? ID { get; set; } - public string Name { get; set; } + public class Organization + { + public long? ID { get; set; } + public string Name { get; set; } - private CollectionController _BranchCollection; - public CollectionController BranchCollection + private CollectionController _BranchCollection; + public CollectionController BranchCollection + { + get { - get - { - if(_BranchCollection == null) - _BranchCollection = new CollectionController(this); - - return _BranchCollection; - } - set { _BranchCollection = value; } + if(_BranchCollection == null) + _BranchCollection = new CollectionController(this); + + return _BranchCollection; } + set { _BranchCollection = value; } } + } - public class Branch - { - public short? ID { get; set; } - public string Name { get; set; } + public class Branch + { + public short? ID { get; set; } + public string Name { get; set; } - } + } - public class CollectionController - where T : class - where K : struct - where Z : EventArgs + public class CollectionController + where T : class + where K : struct + where Z : EventArgs + { + private object _owner; + public CollectionController(object owner) { - private object _owner; - public CollectionController(object owner) - { - _owner = owner; - } - public IEnumerable Models { get; set; } - public K? SelectedID { get; set; } + _owner = owner; } + public IEnumerable Models { get; set; } + public K? SelectedID { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().ForMember(d=>d.BranchCollection, o=>o.UseDestinationValue()); - cfg.CreateMap(); - cfg.CreateMap(typeof(CollectionDTOController<,>), typeof(CollectionController<,,>), MemberList.None); - }); - [Fact] - public void Should_work() - { - var branchDto = new BranchDTO { ID = 51, Name = "B1" }; - var orgDto = new OrganizationDTO { ID = 5, Name = "O1" }; - orgDto.BranchCollection.Models = new BranchDTO[] { branchDto }; + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().ForMember(d=>d.BranchCollection, o=>o.UseDestinationValue()); + cfg.CreateMap(); + cfg.CreateMap(typeof(CollectionDTOController<,>), typeof(CollectionController<,,>), MemberList.None); + }); + [Fact] + public void Should_work() + { + var branchDto = new BranchDTO { ID = 51, Name = "B1" }; + var orgDto = new OrganizationDTO { ID = 5, Name = "O1" }; + orgDto.BranchCollection.Models = new BranchDTO[] { branchDto }; - Mapper.Map(orgDto); - } + Mapper.Map(orgDto); } +} - public class DontUseDestinationValue : NonValidatingSpecBase +public class DontUseDestinationValue : NonValidatingSpecBase +{ + public class OrganizationDTO { - public class OrganizationDTO - { - public long? ID { get; set; } - public string Name { get; set; } + public long? ID { get; set; } + public string Name { get; set; } - private CollectionDTOController _branchCollection; - public CollectionDTOController BranchCollection + private CollectionDTOController _branchCollection; + public CollectionDTOController BranchCollection + { + get { - get - { - if(_branchCollection == null) - _branchCollection = new CollectionDTOController(); - - return _branchCollection; - } - set { _branchCollection = value; } + if(_branchCollection == null) + _branchCollection = new CollectionDTOController(); + + return _branchCollection; } + set { _branchCollection = value; } } + } - public class BranchDTO - { - public short? ID { get; set; } - public string Name { get; set; } + public class BranchDTO + { + public short? ID { get; set; } + public string Name { get; set; } - } + } - public class CollectionDTOController - where T : class - where K : struct - { - public IEnumerable Models { get; set; } - public K? SelectedID { get; set; } - } + public class CollectionDTOController + where T : class + where K : struct + { + public IEnumerable Models { get; set; } + public K? SelectedID { get; set; } + } - public class Organization - { - public long? ID { get; set; } - public string Name { get; set; } + public class Organization + { + public long? ID { get; set; } + public string Name { get; set; } - private CollectionController _BranchCollection; - public CollectionController BranchCollection + private CollectionController _BranchCollection; + public CollectionController BranchCollection + { + get { - get - { - if(_BranchCollection == null) - _BranchCollection = new CollectionController(this); - - return _BranchCollection; - } - set { _BranchCollection = value; } + if(_BranchCollection == null) + _BranchCollection = new CollectionController(this); + + return _BranchCollection; } + set { _BranchCollection = value; } } + } - public class Branch - { - public short? ID { get; set; } - public string Name { get; set; } + public class Branch + { + public short? ID { get; set; } + public string Name { get; set; } - } + } - public class CollectionController - where T : class - where K : struct - where Z : EventArgs + public class CollectionController + where T : class + where K : struct + where Z : EventArgs + { + private object _owner; + public CollectionController(object owner) { - private object _owner; - public CollectionController(object owner) - { - _owner = owner; - } - public IEnumerable Models { get; set; } - public K? SelectedID { get; set; } + _owner = owner; } + public IEnumerable Models { get; set; } + public K? SelectedID { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - cfg.CreateMap(); - cfg.CreateMap(typeof(CollectionDTOController<,>), typeof(CollectionController<,,>), MemberList.None); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + cfg.CreateMap(); + cfg.CreateMap(typeof(CollectionDTOController<,>), typeof(CollectionController<,,>), MemberList.None); + }); - [Fact] - public void Should_report_missing_constructor() - { - var branchDto = new BranchDTO { ID = 51, Name = "B1" }; - var orgDto = new OrganizationDTO { ID = 5, Name = "O1" }; - orgDto.BranchCollection.Models = new BranchDTO[] { branchDto }; + [Fact] + public void Should_report_missing_constructor() + { + var branchDto = new BranchDTO { ID = 51, Name = "B1" }; + var orgDto = new OrganizationDTO { ID = 5, Name = "O1" }; + orgDto.BranchCollection.Models = new BranchDTO[] { branchDto }; - new Action(()=>Mapper.Map(orgDto)).ShouldThrowException( - ex=>ex.InnerException.Message.ShouldStartWith(typeof(CollectionController) + " needs to have a constructor with 0 args or only optional args")); - } + new Action(()=>Mapper.Map(orgDto)).ShouldThrowException( + ex=>ex.InnerException.Message.ShouldStartWith(typeof(CollectionController) + " needs to have a constructor with 0 args or only optional args")); } } \ No newline at end of file diff --git a/src/UnitTests/Bug/WithoutPreserveReferencesSameDestination.cs b/src/UnitTests/Bug/WithoutPreserveReferencesSameDestination.cs index 93207722a3..1424a7f69a 100644 --- a/src/UnitTests/Bug/WithoutPreserveReferencesSameDestination.cs +++ b/src/UnitTests/Bug/WithoutPreserveReferencesSameDestination.cs @@ -4,89 +4,88 @@ using System.Linq; using System.Collections.Generic; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class Self_referencing_existing_destination_without_PreserveReferences : AutoMapperSpecBase { - public class Self_referencing_existing_destination_without_PreserveReferences : AutoMapperSpecBase + public class BaseType { - public class BaseType + public BaseType() { - public BaseType() - { - SelfReference = this; - } - public BaseType SelfReference { get; set; } + SelfReference = this; } + public BaseType SelfReference { get; set; } + } - public class BaseTypeDto + public class BaseTypeDto + { + public BaseTypeDto() { - public BaseTypeDto() - { - SelfReference = this; - } - public BaseTypeDto SelfReference { get; set; } + SelfReference = this; } + public BaseTypeDto SelfReference { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg=> cfg.CreateMap()); - [Fact] - public void Should_work() - { - var baseType = new BaseType(); - var baseTypeDto = new BaseTypeDto(); + protected override MapperConfiguration CreateConfiguration() => new(cfg=> cfg.CreateMap()); + [Fact] + public void Should_work() + { + var baseType = new BaseType(); + var baseTypeDto = new BaseTypeDto(); - Mapper.Map(baseType, baseTypeDto); - } + Mapper.Map(baseType, baseTypeDto); } +} - public class WithoutPreserveReferencesSameDestination : AutoMapperSpecBase +public class WithoutPreserveReferencesSameDestination : AutoMapperSpecBase +{ + public class DtoOne { - public class DtoOne - { - public DtoTwo Two { get; set; } - } + public DtoTwo Two { get; set; } + } - public class DtoTwo - { - public virtual ICollection Ones { get; set; } - } + public class DtoTwo + { + public virtual ICollection Ones { get; set; } + } - public class DtoThree - { - public int Id { get; set; } - } + public class DtoThree + { + public int Id { get; set; } + } - public class EntityOne - { - public int Id { get; set; } - public EntityTwo Two { get; set; } - } + public class EntityOne + { + public int Id { get; set; } + public EntityTwo Two { get; set; } + } - public class EntityTwo - { - public virtual ICollection Ones { get; set; } - } + public class EntityTwo + { + public virtual ICollection Ones { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - cfg.CreateMap(); - cfg.CreateMap(); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + cfg.CreateMap(); + cfg.CreateMap(); + }); - [Fact] - public void Should_use_the_right_map() - { - var source = - new EntityOne { - Two = new EntityTwo { - Ones = new List { - new EntityOne { - Two = new EntityTwo { Ones = new List() } - } + [Fact] + public void Should_use_the_right_map() + { + var source = + new EntityOne { + Two = new EntityTwo { + Ones = new List { + new EntityOne { + Two = new EntityTwo { Ones = new List() } } } - }; - Mapper.Map(source).ShouldBeOfType(); - Mapper.Map(source).ShouldBeOfType(); - } + } + }; + Mapper.Map(source).ShouldBeOfType(); + Mapper.Map(source).ShouldBeOfType(); } } \ No newline at end of file diff --git a/src/UnitTests/CollectionMapping.cs b/src/UnitTests/CollectionMapping.cs index a8144e4ede..f237fb43b5 100644 --- a/src/UnitTests/CollectionMapping.cs +++ b/src/UnitTests/CollectionMapping.cs @@ -9,1152 +9,1151 @@ using AutoMapper.Internal; using System.Collections.Immutable; -namespace AutoMapper.UnitTests +namespace AutoMapper.UnitTests; + +public class NonPublicEnumeratorCurrent : AutoMapperSpecBase { - public class NonPublicEnumeratorCurrent : AutoMapperSpecBase + class Source + { + public string Value { get; set; } + } + class Destination + { + public MyJObject Value { get; set; } + } + class MyJObject : List { - class Source - { - public string Value { get; set; } - } - class Destination - { - public MyJObject Value { get; set; } - } - class MyJObject : List - { public new MyEnumerator GetEnumerator() => new(base.GetEnumerator()); - } - class MyEnumerator : IEnumerator - { - IEnumerator _enumerator; - public MyEnumerator(IEnumerator enumerator) - { - _enumerator = enumerator; - } - object IEnumerator.Current => _enumerator.Current; - public bool MoveNext() => _enumerator.MoveNext(); - public void Reset() => _enumerator.Reset(); - } - protected override MapperConfiguration CreateConfiguration() => new(c => - c.CreateMap().ForMember(d=>d.Value, o=>o.MapFrom(_=>new MyJObject { 1, 2, 3 }))); - [Fact] - public void Should_work() => Map(new Source()).Value.ShouldBe(new[] { 1, 2, 3 }); } - public class ImmutableCollection : AutoMapperSpecBase + class MyEnumerator : IEnumerator { - class Source + IEnumerator _enumerator; + public MyEnumerator(IEnumerator enumerator) { - public string Value { get; set; } + _enumerator = enumerator; } - class Destination - { - public ImmutableArray Value { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(c => - c.CreateMap().ForMember(d=>d.Value, o=>o.MapFrom(_=>ImmutableArray.Create()))); - [Fact] - public void Should_work() => Map(new Source()).Value.ShouldBeOfType>(); + object IEnumerator.Current => _enumerator.Current; + public bool MoveNext() => _enumerator.MoveNext(); + public void Reset() => _enumerator.Reset(); + } + protected override MapperConfiguration CreateConfiguration() => new(c => + c.CreateMap().ForMember(d=>d.Value, o=>o.MapFrom(_=>new MyJObject { 1, 2, 3 }))); + [Fact] + public void Should_work() => Map(new Source()).Value.ShouldBe(new[] { 1, 2, 3 }); +} +public class ImmutableCollection : AutoMapperSpecBase +{ + class Source + { + public string Value { get; set; } } - public class AssignableCollection : AutoMapperSpecBase + class Destination { - class Source + public ImmutableArray Value { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(c => + c.CreateMap().ForMember(d=>d.Value, o=>o.MapFrom(_=>ImmutableArray.Create()))); + [Fact] + public void Should_work() => Map(new Source()).Value.ShouldBeOfType>(); +} +public class AssignableCollection : AutoMapperSpecBase +{ + class Source + { + public string Value { get; set; } + } + class Destination + { + public MyJObject Value { get; set; } + } + class MyJObject : IEnumerable + { + public IEnumerator GetEnumerator() => throw new NotImplementedException(); + } + protected override MapperConfiguration CreateConfiguration() => new(c => + c.CreateMap().ForMember(d=>d.Value, o=>o.MapFrom(_=>new MyJObject()))); + [Fact] + public void Should_work() => Map(new Source()).Value.ShouldBeOfType(); +} +public class RecursiveCollection : AutoMapperSpecBase +{ + class Source + { + public string Value { get; set; } + } + class Destination + { + public MyJObject Value { get; set; } + } + class MyJObject : List{} + protected override MapperConfiguration CreateConfiguration() => new(c => + c.CreateMap().ForMember(d=>d.Value, o=>o.MapFrom(_=>new MyJObject()))); + [Fact] + public void Should_work() => Map(new Source()).Value.ShouldBeOfType(); +} +public class AmbigousMethod : AutoMapperSpecBase +{ + public class Source + { + public string Value { get; set; } + } + public class Destination + { + public string Value { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(c => c.CreateMap()); + [Fact] + public void Should_work() => Map(new[] { new Source() }.OrderBy(s => s.Value)); +} +public class Enumerator_disposable_at_runtime_class : AutoMapperSpecBase +{ + class CustomList : List + { + private CustomEnumerator _enumerator; + + public new EnumeratorBase GetEnumerator() { - public string Value { get; set; } + _enumerator = new CustomEnumerator(base.GetEnumerator(), this); + return _enumerator; } - class Destination + public bool Disposed { get; set; } + public class EnumeratorBase { - public MyJObject Value { get; set; } + public EnumeratorBase(IEnumerator enumerator, CustomList list) + { + Enumerator = enumerator; + List = list; + } + public IEnumerator Enumerator { get; } + public CustomList List { get; } + public T Current => Enumerator.Current; + public void Dispose() + { + Enumerator.Dispose(); + List.Disposed = true; + } + public bool MoveNext() => Enumerator.MoveNext(); + public void Reset() => Enumerator.Reset(); } - class MyJObject : IEnumerable + public class CustomEnumerator : EnumeratorBase, IDisposable { - public IEnumerator GetEnumerator() => throw new NotImplementedException(); + public CustomEnumerator(IEnumerator enumerator, CustomList list) : base(enumerator, list) { } } - protected override MapperConfiguration CreateConfiguration() => new(c => - c.CreateMap().ForMember(d=>d.Value, o=>o.MapFrom(_=>new MyJObject()))); - [Fact] - public void Should_work() => Map(new Source()).Value.ShouldBeOfType(); } - public class RecursiveCollection : AutoMapperSpecBase + + protected override MapperConfiguration CreateConfiguration() => new(_ => { }); + + [Fact] + public void Should_call_dispose() { - class Source - { - public string Value { get; set; } - } - class Destination - { - public MyJObject Value { get; set; } - } - class MyJObject : List{} - protected override MapperConfiguration CreateConfiguration() => new(c => - c.CreateMap().ForMember(d=>d.Value, o=>o.MapFrom(_=>new MyJObject()))); - [Fact] - public void Should_work() => Map(new Source()).Value.ShouldBeOfType(); + var source = new CustomList(); + Mapper.Map>(source); + source.Disposed.ShouldBeTrue(); } - public class AmbigousMethod : AutoMapperSpecBase +} +public class Enumerator_non_disposable_struct : AutoMapperSpecBase +{ + class CustomList : List { - public class Source + private CustomEnumerator _enumerator; + + public new CustomEnumerator GetEnumerator() { - public string Value { get; set; } + _enumerator = new CustomEnumerator(base.GetEnumerator(), this); + return _enumerator; } - public class Destination + public bool Disposed { get; set; } + public struct CustomEnumerator { - public string Value { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(c => c.CreateMap()); - [Fact] - public void Should_work() => Map(new[] { new Source() }.OrderBy(s => s.Value)); - } - public class Enumerator_disposable_at_runtime_class : AutoMapperSpecBase - { - class CustomList : List - { - private CustomEnumerator _enumerator; - - public new EnumeratorBase GetEnumerator() - { - _enumerator = new CustomEnumerator(base.GetEnumerator(), this); - return _enumerator; - } - public bool Disposed { get; set; } - public class EnumeratorBase + public CustomEnumerator(IEnumerator enumerator, CustomList list) { - public EnumeratorBase(IEnumerator enumerator, CustomList list) - { - Enumerator = enumerator; - List = list; - } - public IEnumerator Enumerator { get; } - public CustomList List { get; } - public T Current => Enumerator.Current; - public void Dispose() - { - Enumerator.Dispose(); - List.Disposed = true; - } - public bool MoveNext() => Enumerator.MoveNext(); - public void Reset() => Enumerator.Reset(); + Enumerator = enumerator; + List = list; } - public class CustomEnumerator : EnumeratorBase, IDisposable + public IEnumerator Enumerator { get; } + public CustomList List { get; } + public T Current => Enumerator.Current; + public void Dispose() { - public CustomEnumerator(IEnumerator enumerator, CustomList list) : base(enumerator, list) { } + Enumerator.Dispose(); + List.Disposed = true; } + public bool MoveNext() => Enumerator.MoveNext(); + public void Reset() => Enumerator.Reset(); } + } - protected override MapperConfiguration CreateConfiguration() => new(_ => { }); + protected override MapperConfiguration CreateConfiguration() => new(_ => { }); - [Fact] - public void Should_call_dispose() - { - var source = new CustomList(); - Mapper.Map>(source); - source.Disposed.ShouldBeTrue(); - } + [Fact] + public void Should_not_call_dispose() + { + var source = new CustomList(); + Mapper.Map>(source); + source.Disposed.ShouldBeFalse(); } - public class Enumerator_non_disposable_struct : AutoMapperSpecBase +} +public class Enumerator_dispose : AutoMapperSpecBase +{ + class CustomList : List { - class CustomList : List - { - private CustomEnumerator _enumerator; + private CustomEnumerator _enumerator; - public new CustomEnumerator GetEnumerator() - { - _enumerator = new CustomEnumerator(base.GetEnumerator(), this); - return _enumerator; - } + public new IEnumerator GetEnumerator() + { + _enumerator = new CustomEnumerator(base.GetEnumerator()); + return _enumerator; + } + public bool Disposed => _enumerator.Disposed; + class CustomEnumerator : IEnumerator + { + public CustomEnumerator(IEnumerator enumerator) => Enumerator = enumerator; public bool Disposed { get; set; } - public struct CustomEnumerator + public IEnumerator Enumerator { get; } + public T Current => Enumerator.Current; + object IEnumerator.Current => Enumerator.Current; + public void Dispose() { - public CustomEnumerator(IEnumerator enumerator, CustomList list) - { - Enumerator = enumerator; - List = list; - } - public IEnumerator Enumerator { get; } - public CustomList List { get; } - public T Current => Enumerator.Current; - public void Dispose() - { - Enumerator.Dispose(); - List.Disposed = true; - } - public bool MoveNext() => Enumerator.MoveNext(); - public void Reset() => Enumerator.Reset(); + Enumerator.Dispose(); + Disposed = true; } + public bool MoveNext() => Enumerator.MoveNext(); + public void Reset() => Enumerator.Reset(); } + } - protected override MapperConfiguration CreateConfiguration() => new(_ => { }); + protected override MapperConfiguration CreateConfiguration() => new(_ => { }); - [Fact] - public void Should_not_call_dispose() - { - var source = new CustomList(); - Mapper.Map>(source); - source.Disposed.ShouldBeFalse(); - } + [Fact] + public void Should_call_dispose() + { + var source = new CustomList(); + Mapper.Map>(source); + source.Disposed.ShouldBeTrue(); } - public class Enumerator_dispose : AutoMapperSpecBase +} + +public class Enumerator_dispose_exception : AutoMapperSpecBase +{ + class CustomList : List { - class CustomList : List - { - private CustomEnumerator _enumerator; + private CustomEnumerator _enumerator; - public new IEnumerator GetEnumerator() - { - _enumerator = new CustomEnumerator(base.GetEnumerator()); - return _enumerator; - } - public bool Disposed => _enumerator.Disposed; - class CustomEnumerator : IEnumerator + public new IEnumerator GetEnumerator() + { + _enumerator = new CustomEnumerator(base.GetEnumerator()); + return _enumerator; + } + public bool Disposed => _enumerator.Disposed; + class CustomEnumerator : IEnumerator + { + public CustomEnumerator(IEnumerator enumerator) => Enumerator = enumerator; + public bool Disposed { get; set; } + public IEnumerator Enumerator { get; } + public T Current => Enumerator.Current; + object IEnumerator.Current => Enumerator.Current; + public void Dispose() { - public CustomEnumerator(IEnumerator enumerator) => Enumerator = enumerator; - public bool Disposed { get; set; } - public IEnumerator Enumerator { get; } - public T Current => Enumerator.Current; - object IEnumerator.Current => Enumerator.Current; - public void Dispose() - { - Enumerator.Dispose(); - Disposed = true; - } - public bool MoveNext() => Enumerator.MoveNext(); - public void Reset() => Enumerator.Reset(); + Enumerator.Dispose(); + Disposed = true; } + public bool MoveNext() => throw new NotImplementedException(); + public void Reset() => Enumerator.Reset(); } + } - protected override MapperConfiguration CreateConfiguration() => new(_ => { }); + protected override MapperConfiguration CreateConfiguration() => new(_ => { }); - [Fact] - public void Should_call_dispose() + [Fact] + public void Should_call_dispose() + { + var source = new CustomList(); + try { - var source = new CustomList(); Mapper.Map>(source); - source.Disposed.ShouldBeTrue(); } + catch + { + } + source.Disposed.ShouldBeTrue(); } +} - public class Enumerator_dispose_exception : AutoMapperSpecBase +public class Enumerator_dispose_struct : AutoMapperSpecBase +{ + class CustomList : List { - class CustomList : List - { - private CustomEnumerator _enumerator; + private CustomEnumerator _enumerator; - public new IEnumerator GetEnumerator() - { - _enumerator = new CustomEnumerator(base.GetEnumerator()); - return _enumerator; - } - public bool Disposed => _enumerator.Disposed; - class CustomEnumerator : IEnumerator - { - public CustomEnumerator(IEnumerator enumerator) => Enumerator = enumerator; - public bool Disposed { get; set; } - public IEnumerator Enumerator { get; } - public T Current => Enumerator.Current; - object IEnumerator.Current => Enumerator.Current; - public void Dispose() - { - Enumerator.Dispose(); - Disposed = true; - } - public bool MoveNext() => throw new NotImplementedException(); - public void Reset() => Enumerator.Reset(); - } + public new CustomEnumerator GetEnumerator() + { + _enumerator = new CustomEnumerator(base.GetEnumerator(), this); + return _enumerator; } - - protected override MapperConfiguration CreateConfiguration() => new(_ => { }); - - [Fact] - public void Should_call_dispose() + public bool Disposed { get; set; } + public struct CustomEnumerator : IEnumerator { - var source = new CustomList(); - try + public CustomEnumerator(IEnumerator enumerator, CustomList list) { - Mapper.Map>(source); + Enumerator = enumerator; + List = list; } - catch + public IEnumerator Enumerator { get; } + public CustomList List { get; } + public T Current => Enumerator.Current; + object IEnumerator.Current => Enumerator.Current; + public void Dispose() { + Enumerator.Dispose(); + List.Disposed = true; } - source.Disposed.ShouldBeTrue(); + public bool MoveNext() => Enumerator.MoveNext(); + public void Reset() => Enumerator.Reset(); } } - public class Enumerator_dispose_struct : AutoMapperSpecBase + protected override MapperConfiguration CreateConfiguration() => new(_ => { }); + + [Fact] + public void Should_call_dispose() { - class CustomList : List - { - private CustomEnumerator _enumerator; + var source = new CustomList(); + Mapper.Map>(source); + source.Disposed.ShouldBeTrue(); + } +} - public new CustomEnumerator GetEnumerator() +public class Enumerator_dispose_exception_struct : AutoMapperSpecBase +{ + class CustomList : List + { + private CustomEnumerator _enumerator; + + public new CustomEnumerator GetEnumerator() + { + _enumerator = new CustomEnumerator(base.GetEnumerator(), this); + return _enumerator; + } + public bool Disposed { get; set; } + public struct CustomEnumerator : IEnumerator + { + public CustomEnumerator(IEnumerator enumerator, CustomList list) { - _enumerator = new CustomEnumerator(base.GetEnumerator(), this); - return _enumerator; + Enumerator = enumerator; + List = list; } - public bool Disposed { get; set; } - public struct CustomEnumerator : IEnumerator + public IEnumerator Enumerator { get; } + public T Current => Enumerator.Current; + object IEnumerator.Current => Enumerator.Current; + public CustomList List { get; } + public void Dispose() { - public CustomEnumerator(IEnumerator enumerator, CustomList list) - { - Enumerator = enumerator; - List = list; - } - public IEnumerator Enumerator { get; } - public CustomList List { get; } - public T Current => Enumerator.Current; - object IEnumerator.Current => Enumerator.Current; - public void Dispose() - { - Enumerator.Dispose(); - List.Disposed = true; - } - public bool MoveNext() => Enumerator.MoveNext(); - public void Reset() => Enumerator.Reset(); + Enumerator.Dispose(); + List.Disposed = true; } + public bool MoveNext() => throw new NotImplementedException(); + public void Reset() => Enumerator.Reset(); } + } - protected override MapperConfiguration CreateConfiguration() => new(_ => { }); + protected override MapperConfiguration CreateConfiguration() => new(_ => { }); - [Fact] - public void Should_call_dispose() + [Fact] + public void Should_call_dispose() + { + var source = new CustomList(); + try { - var source = new CustomList(); Mapper.Map>(source); - source.Disposed.ShouldBeTrue(); } + catch + { + } + source.Disposed.ShouldBeTrue(); } +} - public class Enumerator_dispose_exception_struct : AutoMapperSpecBase +public class When_mapping_to_existing_observable_collection : AutoMapperSpecBase +{ + class CollectionHolder { - class CustomList : List + public CollectionHolder() { - private CustomEnumerator _enumerator; - - public new CustomEnumerator GetEnumerator() - { - _enumerator = new CustomEnumerator(base.GetEnumerator(), this); - return _enumerator; - } - public bool Disposed { get; set; } - public struct CustomEnumerator : IEnumerator - { - public CustomEnumerator(IEnumerator enumerator, CustomList list) - { - Enumerator = enumerator; - List = list; - } - public IEnumerator Enumerator { get; } - public T Current => Enumerator.Current; - object IEnumerator.Current => Enumerator.Current; - public CustomList List { get; } - public void Dispose() - { - Enumerator.Dispose(); - List.Disposed = true; - } - public bool MoveNext() => throw new NotImplementedException(); - public void Reset() => Enumerator.Reset(); - } + Observable = new ObservableCollection>(); } - protected override MapperConfiguration CreateConfiguration() => new(_ => { }); - - [Fact] - public void Should_call_dispose() - { - var source = new CustomList(); - try - { - Mapper.Map>(source); - } - catch - { - } - source.Disposed.ShouldBeTrue(); - } + public ObservableCollection> Observable { get; set; } } - public class When_mapping_to_existing_observable_collection : AutoMapperSpecBase + class CollectionHolderDto { - class CollectionHolder + public CollectionHolderDto() { - public CollectionHolder() - { - Observable = new ObservableCollection>(); - } - - public ObservableCollection> Observable { get; set; } + Observable = new List>(); } - class CollectionHolderDto - { - public CollectionHolderDto() - { - Observable = new List>(); - } + public List> Observable { get; set; } + } - public List> Observable { get; set; } - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.CreateMap().ForMember(a => a.Observable, opt => opt.UseDestinationValue())); - protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.CreateMap().ForMember(a => a.Observable, opt => opt.UseDestinationValue())); + [Fact] + public void Should_map_ok() + { + var ch = new CollectionHolderDto(); + var list = new List{ 5, 6 }; + ch.Observable.Add(list); + var mapped = Mapper.Map(ch); + mapped.Observable.Single().ShouldBe(list); + } +} - [Fact] - public void Should_map_ok() - { - var ch = new CollectionHolderDto(); - var list = new List{ 5, 6 }; - ch.Observable.Add(list); - var mapped = Mapper.Map(ch); - mapped.Observable.Single().ShouldBe(list); - } +public class When_mapping_to_member_typed_as_IEnumerable : AutoMapperSpecBase +{ + public class SourceItem { } + public class DestItem { } + public class SourceA + { + public IEnumerable Items { get; set; } + public IEnumerable Bs { get; set; } // Problem } - public class When_mapping_to_member_typed_as_IEnumerable : AutoMapperSpecBase + public class SourceB { - public class SourceItem { } - public class DestItem { } - public class SourceA - { - public IEnumerable Items { get; set; } - public IEnumerable Bs { get; set; } // Problem - } + public IEnumerable Items { get; set; } + } - public class SourceB - { - public IEnumerable Items { get; set; } - } + public class DestA + { + public IEnumerable Items { get; set; } + public IEnumerable Bs { get; set; } // Problem + } - public class DestA - { - public IEnumerable Items { get; set; } - public IEnumerable Bs { get; set; } // Problem - } + public class DestB + { + public IEnumerable Items { get; set; } + } - public class DestB - { - public IEnumerable Items { get; set; } - } + protected override MapperConfiguration CreateConfiguration() => new(cfg=> + { + cfg.CreateMap(); + cfg.CreateMap(); + cfg.CreateMap(); + }); - protected override MapperConfiguration CreateConfiguration() => new(cfg=> - { - cfg.CreateMap(); - cfg.CreateMap(); - cfg.CreateMap(); - }); + [Fact] + public void Should_map_ok() + { + Mapper.Map(new SourceB()).Items.ShouldBeEmpty(); + } +} - [Fact] - public void Should_map_ok() - { - Mapper.Map(new SourceB()).Items.ShouldBeEmpty(); - } +public class When_mapping_to_existing_collection_typed_as_IEnumerable : AutoMapperSpecBase +{ + protected override MapperConfiguration CreateConfiguration() => new(_=>{ }); + + [Fact] + public void Should_map_ok() + { + IEnumerable destination = new List(); + var source = Enumerable.Range(1, 10).ToArray(); + Mapper.Map(source, destination); + destination.SequenceEqual(source).ShouldBeTrue(); } - - public class When_mapping_to_existing_collection_typed_as_IEnumerable : AutoMapperSpecBase +} + +public class When_mapping_to_readonly_property_as_IEnumerable_and_existing_destination : AutoMapperSpecBase +{ + public class Source { - protected override MapperConfiguration CreateConfiguration() => new(_=>{ }); + private readonly List _myCollection = new List { "one", "two" }; - [Fact] - public void Should_map_ok() - { - IEnumerable destination = new List(); - var source = Enumerable.Range(1, 10).ToArray(); - Mapper.Map(source, destination); - destination.SequenceEqual(source).ShouldBeTrue(); - } + public string[] MyCollection => _myCollection.ToArray(); } - public class When_mapping_to_readonly_property_as_IEnumerable_and_existing_destination : AutoMapperSpecBase + public class Destination { - public class Source + private IList _myCollection = new List(); + public IEnumerable MyCollection => _myCollection; + } + + protected override MapperConfiguration CreateConfiguration() => new(cfg => + cfg.CreateMap().ForMember(m => m.MyCollection, opt => { - private readonly List _myCollection = new List { "one", "two" }; + opt.MapFrom(src => src.MyCollection); + })); - public string[] MyCollection => _myCollection.ToArray(); - } + [Fact] + public void Should_map_ok() + { + Mapper.Map(new Source(), new Destination()) + .MyCollection.SequenceEqual(new[] { "one", "two" }).ShouldBeTrue(); + } +} - public class Destination - { - private IList _myCollection = new List(); - public IEnumerable MyCollection => _myCollection; - } +public class When_mapping_to_readonly_collection_without_setter : AutoMapperSpecBase +{ + public class Source + { + public IEnumerable MyCollection { get; } = new[] { "one", "two" }; + } + public class Destination + { + public IEnumerable MyCollection { get; } = new ReadOnlyCollection(new string[0]); + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.CreateMap()); + [Fact] + public void Should_fail() => new Action(() => Mapper.Map(new Source(), new Destination())) + .ShouldThrow() + .InnerException.ShouldBeOfType() + .Message.ShouldBe("Collection is read-only."); +} - protected override MapperConfiguration CreateConfiguration() => new(cfg => - cfg.CreateMap().ForMember(m => m.MyCollection, opt => - { - opt.MapFrom(src => src.MyCollection); - })); +public class When_mapping_to_readonly_property_UseDestinationValue : AutoMapperSpecBase +{ + public class Source + { + private readonly List _myCollection = new List { "one", "two" }; - [Fact] - public void Should_map_ok() - { - Mapper.Map(new Source(), new Destination()) - .MyCollection.SequenceEqual(new[] { "one", "two" }).ShouldBeTrue(); - } + public string[] MyCollection => _myCollection.ToArray(); } - public class When_mapping_to_readonly_collection_without_setter : AutoMapperSpecBase + public class Destination { - public class Source - { - public IEnumerable MyCollection { get; } = new[] { "one", "two" }; - } - public class Destination + private IList _myCollection = new List(); + public IEnumerable MyCollection => _myCollection; + } + + protected override MapperConfiguration CreateConfiguration() => new(cfg => + cfg.CreateMap().ForMember(m => m.MyCollection, opt => { - public IEnumerable MyCollection { get; } = new ReadOnlyCollection(new string[0]); - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.CreateMap()); - [Fact] - public void Should_fail() => new Action(() => Mapper.Map(new Source(), new Destination())) - .ShouldThrow() - .InnerException.ShouldBeOfType() - .Message.ShouldBe("Collection is read-only."); + opt.MapFrom(src => src.MyCollection); + })); + + [Fact] + public void Should_map_ok() + { + Mapper.Map(new Source()) + .MyCollection.SequenceEqual(new[] { "one", "two" }).ShouldBeTrue(); } +} - public class When_mapping_to_readonly_property_UseDestinationValue : AutoMapperSpecBase +public class When_mapping_to_readonly_property_as_IEnumerable : AutoMapperSpecBase +{ + public class Source { - public class Source - { - private readonly List _myCollection = new List { "one", "two" }; + private readonly List _myCollection = new List { "one", "two" }; - public string[] MyCollection => _myCollection.ToArray(); - } + public string[] MyCollection => _myCollection.ToArray(); + } - public class Destination - { - private IList _myCollection = new List(); - public IEnumerable MyCollection => _myCollection; - } + public class Destination + { + private IList _myCollection = new List(); + public IEnumerable MyCollection => _myCollection; + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - cfg.CreateMap().ForMember(m => m.MyCollection, opt => + protected override MapperConfiguration CreateConfiguration() => new(cfg => + cfg.CreateMap().ForMember(m => m.MyCollection, opt => { opt.MapFrom(src => src.MyCollection); + opt.UseDestinationValue(); })); - [Fact] - public void Should_map_ok() - { - Mapper.Map(new Source()) - .MyCollection.SequenceEqual(new[] { "one", "two" }).ShouldBeTrue(); - } + [Fact] + public void Should_map_ok() + { + Mapper.Map(new Source()) + .MyCollection.SequenceEqual(new[] { "one", "two" }).ShouldBeTrue(); } +} - public class When_mapping_to_readonly_property_as_IEnumerable : AutoMapperSpecBase +public class When_mapping_from_struct_collection : AutoMapperSpecBase +{ + public struct MyCollection : IEnumerable { - public class Source + public IEnumerator GetEnumerator() { - private readonly List _myCollection = new List { "one", "two" }; - - public string[] MyCollection => _myCollection.ToArray(); + for(int i = 1; i <= 10; i++) + { + yield return i; + } } - public class Destination + IEnumerator IEnumerable.GetEnumerator() { - private IList _myCollection = new List(); - public IEnumerable MyCollection => _myCollection; + return GetEnumerator(); } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - cfg.CreateMap().ForMember(m => m.MyCollection, opt => - { - opt.MapFrom(src => src.MyCollection); - opt.UseDestinationValue(); - })); - - [Fact] - public void Should_map_ok() - { - Mapper.Map(new Source()) - .MyCollection.SequenceEqual(new[] { "one", "two" }).ShouldBeTrue(); - } + public class SourceItem + { + public string Name { get; set; } + public MyCollection ShipsTo { get; set; } } - public class When_mapping_from_struct_collection : AutoMapperSpecBase + public class DestItem { - public struct MyCollection : IEnumerable - { - public IEnumerator GetEnumerator() - { - for(int i = 1; i <= 10; i++) - { - yield return i; - } - } + public string Name { get; set; } + public List ShipsTo { get; set; } + } - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - } + protected override MapperConfiguration CreateConfiguration() => + new MapperConfiguration(cfg => cfg.CreateMap()); - public class SourceItem - { - public string Name { get; set; } - public MyCollection ShipsTo { get; set; } - } - - public class DestItem - { - public string Name { get; set; } - public List ShipsTo { get; set; } - } + [Fact] + public void Should_map_ok() + { + Mapper.Map(new SourceItem { ShipsTo = new MyCollection() }) + .ShipsTo.SequenceEqual(Enumerable.Range(1, 10)).ShouldBeTrue(); + } +} - protected override MapperConfiguration CreateConfiguration() => - new MapperConfiguration(cfg => cfg.CreateMap()); +public class When_mapping_to_custom_collection_type : AutoMapperSpecBase +{ + public class MyCollection : CollectionBase + { + } - [Fact] - public void Should_map_ok() - { - Mapper.Map(new SourceItem { ShipsTo = new MyCollection() }) - .ShipsTo.SequenceEqual(Enumerable.Range(1, 10)).ShouldBeTrue(); - } + public class SourceItem + { + public string Name { get; set; } + public List ShipsTo { get; set; } } - public class When_mapping_to_custom_collection_type : AutoMapperSpecBase + public class DestItem { - public class MyCollection : CollectionBase - { - } + public string Name { get; set; } + public MyCollection ShipsTo { get; set; } + } - public class SourceItem - { - public string Name { get; set; } - public List ShipsTo { get; set; } - } + protected override MapperConfiguration CreateConfiguration() => + new MapperConfiguration(cfg => cfg.CreateMap()); - public class DestItem - { - public string Name { get; set; } - public MyCollection ShipsTo { get; set; } - } + [Fact] + public void Should_map_ok() + { + var items = Enumerable.Range(1, 10).Select(i => i.ToString()).ToArray(); + Mapper.Map(new SourceItem { ShipsTo = new List(items) }) + .ShipsTo.Cast().SequenceEqual(items).ShouldBeTrue(); + } +} - protected override MapperConfiguration CreateConfiguration() => - new MapperConfiguration(cfg => cfg.CreateMap()); +public class When_mapping_to_unknown_collection_type : NonValidatingSpecBase +{ + public class MyCollection + { + } - [Fact] - public void Should_map_ok() - { - var items = Enumerable.Range(1, 10).Select(i => i.ToString()).ToArray(); - Mapper.Map(new SourceItem { ShipsTo = new List(items) }) - .ShipsTo.Cast().SequenceEqual(items).ShouldBeTrue(); - } + public class SourceItem + { + public string Name { get; set; } + public List ShipsTo { get; set; } } - public class When_mapping_to_unknown_collection_type : NonValidatingSpecBase + public class DestItem { - public class MyCollection - { - } + public string Name { get; set; } + public MyCollection ShipsTo { get; set; } + } - public class SourceItem + protected override MapperConfiguration CreateConfiguration() => + new MapperConfiguration(cfg => { - public string Name { get; set; } - public List ShipsTo { get; set; } - } + cfg.CreateMap(); + }); - public class DestItem + [Fact] + public void Should_report_missing_map() + { + new Action(AssertConfigurationIsValid).ShouldThrowException(ex => { - public string Name { get; set; } - public MyCollection ShipsTo { get; set; } - } - - protected override MapperConfiguration CreateConfiguration() => - new MapperConfiguration(cfg => - { - cfg.CreateMap(); - }); + ex.MemberMap.SourceMember.ShouldBe(typeof(SourceItem).GetProperty("ShipsTo")); + ex.Types.Value.ShouldBe(new TypePair(typeof(SourceItem), typeof(DestItem))); + }); + } +} - [Fact] - public void Should_report_missing_map() - { - new Action(AssertConfigurationIsValid).ShouldThrowException(ex => - { - ex.MemberMap.SourceMember.ShouldBe(typeof(SourceItem).GetProperty("ShipsTo")); - ex.Types.Value.ShouldBe(new TypePair(typeof(SourceItem), typeof(DestItem))); - }); - } +public class When_mapping_collections_with_inheritance : AutoMapperSpecBase +{ + public class Source + { + public IEnumerable Items { get; set; } + } + public class Destination + { + public IEnumerable Items { get; set; } + } + public class SourceItem + { + public int Value { get; set; } + } + public class DestinationItemBase + { + public int Value { get; set; } + } + public class SpecificDestinationItem : DestinationItemBase + { } - public class When_mapping_collections_with_inheritance : AutoMapperSpecBase + protected override MapperConfiguration CreateConfiguration() => new(cfg => { - public class Source - { - public IEnumerable Items { get; set; } - } - public class Destination - { - public IEnumerable Items { get; set; } - } - public class SourceItem - { - public int Value { get; set; } - } - public class DestinationItemBase - { - public int Value { get; set; } - } - public class SpecificDestinationItem : DestinationItemBase - { - } + cfg.CreateMap().As(); + cfg.CreateMap(); + cfg.CreateMap(); + }); + [Fact] + public void Validate() => AssertConfigurationIsValid(); +} - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().As(); - cfg.CreateMap(); - cfg.CreateMap(); - }); - [Fact] - public void Validate() => AssertConfigurationIsValid(); +public class When_passing_a_not_empty_collection : AutoMapperSpecBase +{ + Destination _destination = new Destination(); + + class Source + { + public List Items { get; } } - public class When_passing_a_not_empty_collection : AutoMapperSpecBase + class SourceItem { - Destination _destination = new Destination(); + } - class Source - { - public List Items { get; } - } + class Destination + { + public List Items { get; } = new List { new DestinationItem() }; + } - class SourceItem - { - } + class DestinationItem + { + } - class Destination - { - public List Items { get; } = new List { new DestinationItem() }; - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + cfg.CreateMap(); + }); - class DestinationItem - { - } + protected override void Because_of() + { + Mapper.Map(new Source(), _destination); + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - cfg.CreateMap(); - }); + [Fact] + public void It_should_be_cleared_first() + { + _destination.Items.ShouldBeEmpty(); + } +} - protected override void Because_of() - { - Mapper.Map(new Source(), _destination); - } +public class When_mapping_collections_with_structs : AutoMapperSpecBase +{ + BarDTO _destination; - [Fact] - public void It_should_be_cleared_first() - { - _destination.Items.ShouldBeEmpty(); - } + public struct Foo { } + public struct Bar + { + public IEnumerable Foos { get; set; } } - public class When_mapping_collections_with_structs : AutoMapperSpecBase + public struct FooDTO { } + public struct BarDTO { - BarDTO _destination; + public IEnumerable Foos { get; set; } + } - public struct Foo { } - public struct Bar - { - public IEnumerable Foos { get; set; } - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + cfg.CreateMap(); + }); - public struct FooDTO { } - public struct BarDTO - { - public IEnumerable Foos { get; set; } - } + protected override void Because_of() + { + _destination = Mapper.Map(new Bar { Foos = new Foo[5] }); + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - cfg.CreateMap(); - }); + [Fact] + public void Should_map_ok() + { + _destination.Foos.SequenceEqual(new FooDTO[5]).ShouldBeTrue(); + } +} - protected override void Because_of() - { - _destination = Mapper.Map(new Bar { Foos = new Foo[5] }); - } +public class CollectionMapping +{ + public class MasterWithList + { + private IList _details = new List(); + + public int Id { get; set; } - [Fact] - public void Should_map_ok() + public IList Details { - _destination.Foos.SequenceEqual(new FooDTO[5]).ShouldBeTrue(); + get { return _details; } + set { _details = value; } } } - public class CollectionMapping + public class MasterWithCollection { - public class MasterWithList + public MasterWithCollection(ICollection details) { - private IList _details = new List(); + Details = details; + } - public int Id { get; set; } + public int Id { get; set; } - public IList Details - { - get { return _details; } - set { _details = value; } - } - } + public ICollection Details { get; set; } + } - public class MasterWithCollection - { - public MasterWithCollection(ICollection details) - { - Details = details; - } + public class MasterWithNoExistingCollection + { + public int Id { get; set; } + public HashSet Details { get; set; } + } - public int Id { get; set; } + public class Detail + { + public int Id { get; set; } + } - public ICollection Details { get; set; } - } + public class MasterDto + { + public int Id { get; set; } + public DetailDto[] Details { get; set; } + } - public class MasterWithNoExistingCollection - { - public int Id { get; set; } - public HashSet Details { get; set; } - } + public class DetailDto + { + public int Id { get; set; } + } - public class Detail - { - public int Id { get; set; } - } + private static IMapper mapper; - public class MasterDto + private static void FillCollection( + TSource s, TDestination d, + Func> getSourceEnum, + Func> getDestinationColl) + { + ICollection collection = getDestinationColl(d); + collection.Clear(); + foreach (TSourceItem sourceItem in getSourceEnum(s)) { - public int Id { get; set; } - public DetailDto[] Details { get; set; } + collection.Add(mapper.Map(sourceItem)); } + } - public class DetailDto + [Fact] + public void Should_keep_and_fill_destination_collection_when_collection_is_implemented_as_list() + { + var config = new MapperConfiguration(cfg => { - public int Id { get; set; } - } - private static IMapper mapper; + cfg.CreateMap() + .ForMember(d => d.Details, o => o.UseDestinationValue()); + cfg.CreateMap(); + }); - private static void FillCollection( - TSource s, TDestination d, - Func> getSourceEnum, - Func> getDestinationColl) + var dto = new MasterDto { - ICollection collection = getDestinationColl(d); - collection.Clear(); - foreach (TSourceItem sourceItem in getSourceEnum(s)) + Id = 1, + Details = new[] { - collection.Add(mapper.Map(sourceItem)); + new DetailDto {Id = 2}, + new DetailDto {Id = 3}, } - } + }; - [Fact] - public void Should_keep_and_fill_destination_collection_when_collection_is_implemented_as_list() - { - var config = new MapperConfiguration(cfg => - { - - cfg.CreateMap() - .ForMember(d => d.Details, o => o.UseDestinationValue()); - cfg.CreateMap(); - }); - - var dto = new MasterDto - { - Id = 1, - Details = new[] - { - new DetailDto {Id = 2}, - new DetailDto {Id = 3}, - } - }; + var master = new MasterWithCollection(new List()); + ICollection originalCollection = master.Details; - var master = new MasterWithCollection(new List()); - ICollection originalCollection = master.Details; + config.CreateMapper().Map(dto, master); - config.CreateMapper().Map(dto, master); - - originalCollection.ShouldBeSameAs(master.Details); - originalCollection.Count.ShouldBe(master.Details.Count); - } + originalCollection.ShouldBeSameAs(master.Details); + originalCollection.Count.ShouldBe(master.Details.Count); + } - [Fact] - public void Should_keep_and_fill_destination_collection_when_collection_is_implemented_as_set() + [Fact] + public void Should_keep_and_fill_destination_collection_when_collection_is_implemented_as_set() + { + var config = new MapperConfiguration(cfg => { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap() - .ForMember(d => d.Details, o => o.UseDestinationValue()); - cfg.CreateMap(); - }); + cfg.CreateMap() + .ForMember(d => d.Details, o => o.UseDestinationValue()); + cfg.CreateMap(); + }); - var dto = new MasterDto + var dto = new MasterDto + { + Id = 1, + Details = new[] { - Id = 1, - Details = new[] - { - new DetailDto {Id = 2}, - new DetailDto {Id = 3}, - } - }; + new DetailDto {Id = 2}, + new DetailDto {Id = 3}, + } + }; - var master = new MasterWithCollection(new HashSet()); - ICollection originalCollection = master.Details; + var master = new MasterWithCollection(new HashSet()); + ICollection originalCollection = master.Details; - config.CreateMapper().Map(dto, master); + config.CreateMapper().Map(dto, master); - originalCollection.ShouldBeSameAs(master.Details); - originalCollection.Count.ShouldBe(master.Details.Count); - } + originalCollection.ShouldBeSameAs(master.Details); + originalCollection.Count.ShouldBe(master.Details.Count); + } - [Fact] - public void Should_keep_and_fill_destination_collection_when_collection_is_implemented_as_set_with_aftermap() + [Fact] + public void Should_keep_and_fill_destination_collection_when_collection_is_implemented_as_set_with_aftermap() + { + var config = new MapperConfiguration(cfg => { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap() - .ForMember(d => d.Details, o => o.Ignore()) - .AfterMap((s, d) => FillCollection(s, d, ss => ss.Details, dd => dd.Details)); - cfg.CreateMap(); - }); + cfg.CreateMap() + .ForMember(d => d.Details, o => o.Ignore()) + .AfterMap((s, d) => FillCollection(s, d, ss => ss.Details, dd => dd.Details)); + cfg.CreateMap(); + }); - var dto = new MasterDto + var dto = new MasterDto + { + Id = 1, + Details = new[] { - Id = 1, - Details = new[] - { - new DetailDto {Id = 2}, - new DetailDto {Id = 3}, - } - }; + new DetailDto {Id = 2}, + new DetailDto {Id = 3}, + } + }; - var master = new MasterWithCollection(new HashSet()); - ICollection originalCollection = master.Details; + var master = new MasterWithCollection(new HashSet()); + ICollection originalCollection = master.Details; - mapper = config.CreateMapper(); + mapper = config.CreateMapper(); - mapper.Map(dto, master); + mapper.Map(dto, master); - originalCollection.ShouldBeSameAs(master.Details); - originalCollection.Count.ShouldBe(master.Details.Count); - } + originalCollection.ShouldBeSameAs(master.Details); + originalCollection.Count.ShouldBe(master.Details.Count); + } - [Fact] - public void Should_keep_and_fill_destination_list() + [Fact] + public void Should_keep_and_fill_destination_list() + { + var config = new MapperConfiguration(cfg => { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap() - .ForMember(d => d.Details, o => o.UseDestinationValue()); - cfg.CreateMap(); - }); + cfg.CreateMap() + .ForMember(d => d.Details, o => o.UseDestinationValue()); + cfg.CreateMap(); + }); - var dto = new MasterDto + var dto = new MasterDto + { + Id = 1, + Details = new[] { - Id = 1, - Details = new[] - { - new DetailDto {Id = 2}, - new DetailDto {Id = 3}, - } - }; + new DetailDto {Id = 2}, + new DetailDto {Id = 3}, + } + }; - var master = new MasterWithList(); - IList originalCollection = master.Details; + var master = new MasterWithList(); + IList originalCollection = master.Details; - config.CreateMapper().Map(dto, master); + config.CreateMapper().Map(dto, master); - originalCollection.ShouldBeSameAs(master.Details); - originalCollection.Count.ShouldBe(master.Details.Count); - } + originalCollection.ShouldBeSameAs(master.Details); + originalCollection.Count.ShouldBe(master.Details.Count); + } - [Fact] - public void Should_not_replace_destination_collection() + [Fact] + public void Should_not_replace_destination_collection() + { + var config = new MapperConfiguration(cfg => { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap() - .ForMember(d => d.Details, opt => opt.UseDestinationValue()); - cfg.CreateMap(); - }); + cfg.CreateMap() + .ForMember(d => d.Details, opt => opt.UseDestinationValue()); + cfg.CreateMap(); + }); - var dto = new MasterDto + var dto = new MasterDto + { + Id = 1, + Details = new[] { - Id = 1, - Details = new[] - { - new DetailDto {Id = 2}, - new DetailDto {Id = 3}, - } - }; + new DetailDto {Id = 2}, + new DetailDto {Id = 3}, + } + }; - var master = new MasterWithCollection(new List()); - ICollection originalCollection = master.Details; + var master = new MasterWithCollection(new List()); + ICollection originalCollection = master.Details; - config.CreateMapper().Map(dto, master); + config.CreateMapper().Map(dto, master); - originalCollection.ShouldBeSameAs(master.Details); - } + originalCollection.ShouldBeSameAs(master.Details); + } - [Fact] - public void Should_be_able_to_map_to_a_collection_type_that_implements_ICollection_of_T() + [Fact] + public void Should_be_able_to_map_to_a_collection_type_that_implements_ICollection_of_T() + { + var config = new MapperConfiguration(cfg => { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap(); - cfg.CreateMap(); - }); + cfg.CreateMap(); + cfg.CreateMap(); + }); - var dto = new MasterDto + var dto = new MasterDto + { + Id = 1, + Details = new[] { - Id = 1, - Details = new[] - { - new DetailDto {Id = 2}, - new DetailDto {Id = 3}, - } - }; + new DetailDto {Id = 2}, + new DetailDto {Id = 3}, + } + }; - var master = config.CreateMapper().Map(dto); + var master = config.CreateMapper().Map(dto); - master.Details.Count.ShouldBe(2); - } + master.Details.Count.ShouldBe(2); + } - [Fact] - public void Should_not_replace_destination_list() + [Fact] + public void Should_not_replace_destination_list() + { + var config = new MapperConfiguration(cfg => { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap() - .ForMember(d => d.Details, opt => opt.UseDestinationValue()); - cfg.CreateMap(); - }); + cfg.CreateMap() + .ForMember(d => d.Details, opt => opt.UseDestinationValue()); + cfg.CreateMap(); + }); - var dto = new MasterDto + var dto = new MasterDto + { + Id = 1, + Details = new[] { - Id = 1, - Details = new[] - { - new DetailDto {Id = 2}, - new DetailDto {Id = 3}, - } - }; + new DetailDto {Id = 2}, + new DetailDto {Id = 3}, + } + }; - var master = new MasterWithList(); - IList originalCollection = master.Details; + var master = new MasterWithList(); + IList originalCollection = master.Details; - config.CreateMapper().Map(dto, master); + config.CreateMapper().Map(dto, master); - originalCollection.ShouldBeSameAs(master.Details); - } + originalCollection.ShouldBeSameAs(master.Details); + } - [Fact] - public void Should_map_to_NameValueCollection() { - var c = new NameValueCollection(); - var config = new MapperConfiguration(cfg => { }); - var mappedCollection = config.CreateMapper().Map(c); - mappedCollection.ShouldNotBeSameAs(c); - mappedCollection.ShouldNotBeNull(); - } + [Fact] + public void Should_map_to_NameValueCollection() { + var c = new NameValueCollection(); + var config = new MapperConfiguration(cfg => { }); + var mappedCollection = config.CreateMapper().Map(c); + mappedCollection.ShouldNotBeSameAs(c); + mappedCollection.ShouldNotBeNull(); } +} - public class When_mapping_from_ICollection_types_but_implementations_are_different : AutoMapperSpecBase +public class When_mapping_from_ICollection_types_but_implementations_are_different : AutoMapperSpecBase +{ + public class Source { - public class Source - { - public ICollection Items { get; set; } + public ICollection Items { get; set; } - public class Item - { - public int Value { get; set; } - } - } - public class Dest + public class Item { - public ICollection Items { get; set; } = new HashSet(); - - public class Item - { - public int Value { get; set; } - } + public int Value { get; set; } } + } + public class Dest + { + public ICollection Items { get; set; } = new HashSet(); - protected override MapperConfiguration CreateConfiguration() => new(cfg => + public class Item { - cfg.CreateMap(); - cfg.CreateMap(); - }); + public int Value { get; set; } + } + } + + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + cfg.CreateMap(); + }); - [Fact] - public void Should_map_items() + [Fact] + public void Should_map_items() + { + var source = new Source { - var source = new Source + Items = new List { - Items = new List - { - new Source.Item { Value = 5 } - } - }; - var dest = new Dest(); + new Source.Item { Value = 5 } + } + }; + var dest = new Dest(); - Mapper.Map(source, dest); + Mapper.Map(source, dest); - dest.Items.Count.ShouldBe(1); - dest.Items.First().Value.ShouldBe(5); - } + dest.Items.Count.ShouldBe(1); + dest.Items.First().Value.ShouldBe(5); } +} - public class When_mapping_enumerable_to_array : AutoMapperSpecBase +public class When_mapping_enumerable_to_array : AutoMapperSpecBase +{ + public class Source { - public class Source - { - public int X { get; set; } - public IEnumerable Items { get; set; } - } + public int X { get; set; } + public IEnumerable Items { get; set; } + } - public class SourceItem - { - public int I { get; set; } - } + public class SourceItem + { + public int I { get; set; } + } - public class Target - { - public int X { get; set; } - public TargetItem[] Items { get; set; } - } + public class Target + { + public int X { get; set; } + public TargetItem[] Items { get; set; } + } - public class TargetItem - { - public int I { get; set; } - } + public class TargetItem + { + public int I { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.AllowNullCollections = true; + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.AllowNullCollections = true; - cfg.CreateMap(); - cfg.CreateMap(); - }); + cfg.CreateMap(); + cfg.CreateMap(); + }); - [Fact] - public void IncludedMappings() + [Fact] + public void IncludedMappings() + { + var src = new Source { - var src = new Source + X = 5, + Items = new List { - X = 5, - Items = new List - { - new SourceItem {I = 1}, - new SourceItem {I = 2}, - new SourceItem {I = 3} - } - }; - - var dest = Mapper.Map(src); - - src.X.ShouldBe(dest.X); - - dest.Items.Length.ShouldBe(3); - dest.Items[0].I.ShouldBe(1); - dest.Items[1].I.ShouldBe(2); - dest.Items[2].I.ShouldBe(3); - } + new SourceItem {I = 1}, + new SourceItem {I = 2}, + new SourceItem {I = 3} + } + }; + + var dest = Mapper.Map(src); + + src.X.ShouldBe(dest.X); + + dest.Items.Length.ShouldBe(3); + dest.Items[0].I.ShouldBe(1); + dest.Items[1].I.ShouldBe(2); + dest.Items[2].I.ShouldBe(3); } } diff --git a/src/UnitTests/ConditionalMapping.cs b/src/UnitTests/ConditionalMapping.cs index 992b30c431..921b352209 100644 --- a/src/UnitTests/ConditionalMapping.cs +++ b/src/UnitTests/ConditionalMapping.cs @@ -4,293 +4,292 @@ using Xunit; using Shouldly; -namespace AutoMapper.UnitTests.ConditionalMapping -{ - public class When_adding_a_condition_for_all_members : AutoMapperSpecBase - { - Source _source = new Source { Value = 3 }; - Destination _destination = new Destination { Value = 7 }; +namespace AutoMapper.UnitTests.ConditionalMapping; - class Source - { - public int Value { get; set; } - } +public class When_adding_a_condition_for_all_members : AutoMapperSpecBase +{ + Source _source = new Source { Value = 3 }; + Destination _destination = new Destination { Value = 7 }; - class Destination - { - public int Value { get; set; } - } + class Source + { + public int Value { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().ForAllMembers(o => o.Condition((source, destination, sourceProperty, destinationProperty) => - { - source.ShouldBeSameAs(_source); - destination.ShouldBeSameAs(_destination); - ((int)sourceProperty).ShouldBe(3); - ((int)destinationProperty).ShouldBe(7); - return true; - })); - }); - [Fact] - public void Should_work() => Mapper.Map(_source, _destination); + class Destination + { + public int Value { get; set; } } - public class When_ignoring_all_properties_with_an_inaccessible_setter_and_explicitly_implemented_member : AutoMapperSpecBase + protected override MapperConfiguration CreateConfiguration() => new(cfg => { - protected override MapperConfiguration CreateConfiguration() => new(c => c.CreateMap().IgnoreAllPropertiesWithAnInaccessibleSetter()); + cfg.CreateMap().ForAllMembers(o => o.Condition((source, destination, sourceProperty, destinationProperty) => + { + source.ShouldBeSameAs(_source); + destination.ShouldBeSameAs(_destination); + ((int)sourceProperty).ShouldBe(3); + ((int)destinationProperty).ShouldBe(7); + return true; + })); + }); + [Fact] + public void Should_work() => Mapper.Map(_source, _destination); +} + +public class When_ignoring_all_properties_with_an_inaccessible_setter_and_explicitly_implemented_member : AutoMapperSpecBase +{ + protected override MapperConfiguration CreateConfiguration() => new(c => c.CreateMap().IgnoreAllPropertiesWithAnInaccessibleSetter()); - interface Interface - { - int Value { get; } - } + interface Interface + { + int Value { get; } + } - class SourceClass - { - public int PublicProperty { get; set; } - } + class SourceClass + { + public int PublicProperty { get; set; } + } - class DestinationClass : Interface - { - int Interface.Value { get { return 123; } } + class DestinationClass : Interface + { + int Interface.Value { get { return 123; } } - public int PrivateProperty { get; private set; } + public int PrivateProperty { get; private set; } - public int PublicProperty { get; set; } - } - [Fact] - public void Validate() => AssertConfigurationIsValid(); + public int PublicProperty { get; set; } } + [Fact] + public void Validate() => AssertConfigurationIsValid(); +} - public class When_configuring_a_member_to_skip_based_on_the_property_value : AutoMapperSpecBase +public class When_configuring_a_member_to_skip_based_on_the_property_value : AutoMapperSpecBase +{ + public class Source { - public class Source - { - public int Value { get; set; } - } + public int Value { get; set; } + } - public class Destination - { - public int Value { get; set; } - } + public class Destination + { + public int Value { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ForMember(dest => dest.Value, opt => opt.Condition(src => src.Value > 0)); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .ForMember(dest => dest.Value, opt => opt.Condition(src => src.Value > 0)); + }); - [Fact] - public void Should_skip_the_mapping_when_the_condition_is_true() - { - var destination = Mapper.Map(new Source {Value = -1}); + [Fact] + public void Should_skip_the_mapping_when_the_condition_is_true() + { + var destination = Mapper.Map(new Source {Value = -1}); - destination.Value.ShouldBe(0); - } + destination.Value.ShouldBe(0); + } - [Fact] - public void Should_execute_the_mapping_when_the_condition_is_false() - { - var destination = Mapper.Map(new Source { Value = 7 }); + [Fact] + public void Should_execute_the_mapping_when_the_condition_is_false() + { + var destination = Mapper.Map(new Source { Value = 7 }); - destination.Value.ShouldBe(7); - } + destination.Value.ShouldBe(7); } +} - public class When_configuring_a_member_to_skip_based_on_the_property_value_with_custom_mapping : AutoMapperSpecBase +public class When_configuring_a_member_to_skip_based_on_the_property_value_with_custom_mapping : AutoMapperSpecBase +{ + public class Source { - public class Source - { - public int Value { get; set; } - } + public int Value { get; set; } + } - public class Destination - { - public int Value { get; set; } - } + public class Destination + { + public int Value { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ForMember(dest => dest.Value, opt => - { - opt.Condition(src => src.Value > 0); - opt.MapFrom(src => 10); - }); - }); - - [Fact] - public void Should_skip_the_mapping_when_the_condition_is_true() - { - var destination = Mapper.Map(new Source { Value = -1 }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .ForMember(dest => dest.Value, opt => + { + opt.Condition(src => src.Value > 0); + opt.MapFrom(src => 10); + }); + }); - destination.Value.ShouldBe(0); - } + [Fact] + public void Should_skip_the_mapping_when_the_condition_is_true() + { + var destination = Mapper.Map(new Source { Value = -1 }); - [Fact] - public void Should_execute_the_mapping_when_the_condition_is_false() - { - Mapper.Map(new Source { Value = 7 }).Value.ShouldBe(10); - } + destination.Value.ShouldBe(0); } - public class When_configuring_a_map_to_ignore_all_properties_with_an_inaccessible_setter : AutoMapperSpecBase + [Fact] + public void Should_execute_the_mapping_when_the_condition_is_false() { - private Destination _destination; - - public class Source - { - public int Id { get; set; } - public string Title { get; set; } - public string CodeName { get; set; } - public string Nickname { get; set; } - public string ScreenName { get; set; } - } - - public class Destination - { - private double _height; + Mapper.Map(new Source { Value = 7 }).Value.ShouldBe(10); + } +} - public int Id { get; set; } - public virtual string Name { get; protected set; } - public string Title { get; internal set; } - public string CodeName { get; private set; } - public string Nickname { get; private set; } - public string ScreenName { get; private set; } - public int Age { get; private set; } +public class When_configuring_a_map_to_ignore_all_properties_with_an_inaccessible_setter : AutoMapperSpecBase +{ + private Destination _destination; - public double Height - { - get { return _height; } - } + public class Source + { + public int Id { get; set; } + public string Title { get; set; } + public string CodeName { get; set; } + public string Nickname { get; set; } + public string ScreenName { get; set; } + } - public Destination() - { - _height = 60; - } - } + public class Destination + { + private double _height; - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ForMember(dest => dest.ScreenName, opt => opt.MapFrom(src => src.ScreenName)) - .IgnoreAllPropertiesWithAnInaccessibleSetter() - .ForMember(dest => dest.Nickname, opt => opt.MapFrom(src => src.Nickname)); - }); + public int Id { get; set; } + public virtual string Name { get; protected set; } + public string Title { get; internal set; } + public string CodeName { get; private set; } + public string Nickname { get; private set; } + public string ScreenName { get; private set; } + public int Age { get; private set; } - protected override void Because_of() + public double Height { - _destination = Mapper.Map(new Source { Id = 5, CodeName = "007", Nickname = "Jimmy", ScreenName = "jbogard" }); + get { return _height; } } - [Fact] - public void Should_consider_the_configuration_valid_even_if_some_properties_with_an_inaccessible_setter_are_unmapped() + public Destination() { - typeof(AutoMapperConfigurationException).ShouldNotBeThrownBy(AssertConfigurationIsValid); + _height = 60; } + } - [Fact] - public void Should_map_a_property_with_an_inaccessible_setter_if_a_specific_mapping_is_configured_after_the_ignore_method() - { - _destination.Nickname.ShouldBe("Jimmy"); - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .ForMember(dest => dest.ScreenName, opt => opt.MapFrom(src => src.ScreenName)) + .IgnoreAllPropertiesWithAnInaccessibleSetter() + .ForMember(dest => dest.Nickname, opt => opt.MapFrom(src => src.Nickname)); + }); - [Fact] - public void Should_not_map_a_property_with_an_inaccessible_setter_if_no_specific_mapping_is_configured_even_though_name_and_type_match() - { - _destination.CodeName.ShouldBeNull(); - } + protected override void Because_of() + { + _destination = Mapper.Map(new Source { Id = 5, CodeName = "007", Nickname = "Jimmy", ScreenName = "jbogard" }); + } - [Fact] - public void Should_not_map_a_property_with_no_public_setter_if_a_specific_mapping_is_configured_before_the_ignore_method() - { - _destination.ScreenName.ShouldBeNull(); - } + [Fact] + public void Should_consider_the_configuration_valid_even_if_some_properties_with_an_inaccessible_setter_are_unmapped() + { + typeof(AutoMapperConfigurationException).ShouldNotBeThrownBy(AssertConfigurationIsValid); } - public class When_configuring_a_reverse_map_to_ignore_all_source_properties_with_an_inaccessible_setter : AutoMapperSpecBase + [Fact] + public void Should_map_a_property_with_an_inaccessible_setter_if_a_specific_mapping_is_configured_after_the_ignore_method() { - private Destination _destination; - private Source _source; + _destination.Nickname.ShouldBe("Jimmy"); + } - public class Source - { - public int Id { get; set; } - public string Name { get; set; } - public int Age { get; set; } - public string Force { get; set; } - public string ReverseForce { get; private set; } - public string Respect { get; private set; } - public int Foo { get; private set; } - public int Bar { get; protected set; } - - public void Initialize() - { - ReverseForce = "You With"; - Respect = "R-E-S-P-E-C-T"; - } - } + [Fact] + public void Should_not_map_a_property_with_an_inaccessible_setter_if_no_specific_mapping_is_configured_even_though_name_and_type_match() + { + _destination.CodeName.ShouldBeNull(); + } - public class Destination - { - public string Name { get; set; } - public int Age { get; set; } - public bool IsVisible { get; set; } - public string Force { get; private set; } - public string ReverseForce { get; set; } - public string Respect { get; set; } - public int Foz { get; private set; } - public int Baz { get; protected set; } - } + [Fact] + public void Should_not_map_a_property_with_no_public_setter_if_a_specific_mapping_is_configured_before_the_ignore_method() + { + _destination.ScreenName.ShouldBeNull(); + } +} - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .IgnoreAllPropertiesWithAnInaccessibleSetter() - .ForMember(dest => dest.IsVisible, opt => opt.Ignore()) - .ForMember(dest => dest.Force, opt => opt.MapFrom(src => src.Force)) - .ReverseMap() - .IgnoreAllSourcePropertiesWithAnInaccessibleSetter() - .ForMember(dest => dest.ReverseForce, opt => opt.MapFrom(src => src.ReverseForce)) - .ForSourceMember(dest => dest.IsVisible, opt => opt.DoNotValidate()); - }); - - protected override void Because_of() - { - var source = new Source { Id = 5, Name = "Bob", Age = 35, Force = "With You" }; - source.Initialize(); - _destination = Mapper.Map(source); - _source = Mapper.Map(_destination); - } +public class When_configuring_a_reverse_map_to_ignore_all_source_properties_with_an_inaccessible_setter : AutoMapperSpecBase +{ + private Destination _destination; + private Source _source; - [Fact] - public void Should_consider_the_configuration_valid_even_if_some_properties_with_an_inaccessible_setter_are_unmapped() - { - typeof(AutoMapperConfigurationException).ShouldNotBeThrownBy(AssertConfigurationIsValid); + public class Source + { + public int Id { get; set; } + public string Name { get; set; } + public int Age { get; set; } + public string Force { get; set; } + public string ReverseForce { get; private set; } + public string Respect { get; private set; } + public int Foo { get; private set; } + public int Bar { get; protected set; } + + public void Initialize() + { + ReverseForce = "You With"; + Respect = "R-E-S-P-E-C-T"; } + } - [Fact] - public void Should_forward_and_reverse_map_a_property_that_is_accessible_on_both_source_and_destination() - { - _source.Name.ShouldBe("Bob"); - } + public class Destination + { + public string Name { get; set; } + public int Age { get; set; } + public bool IsVisible { get; set; } + public string Force { get; private set; } + public string ReverseForce { get; set; } + public string Respect { get; set; } + public int Foz { get; private set; } + public int Baz { get; protected set; } + } - [Fact] - public void Should_forward_and_reverse_map_an_inaccessible_destination_property_if_a_mapping_is_defined() - { - _source.Force.ShouldBe("With You"); - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .IgnoreAllPropertiesWithAnInaccessibleSetter() + .ForMember(dest => dest.IsVisible, opt => opt.Ignore()) + .ForMember(dest => dest.Force, opt => opt.MapFrom(src => src.Force)) + .ReverseMap() + .IgnoreAllSourcePropertiesWithAnInaccessibleSetter() + .ForMember(dest => dest.ReverseForce, opt => opt.MapFrom(src => src.ReverseForce)) + .ForSourceMember(dest => dest.IsVisible, opt => opt.DoNotValidate()); + }); + + protected override void Because_of() + { + var source = new Source { Id = 5, Name = "Bob", Age = 35, Force = "With You" }; + source.Initialize(); + _destination = Mapper.Map(source); + _source = Mapper.Map(_destination); + } - [Fact] - public void Should_forward_and_reverse_map_an_inaccessible_source_property_if_a_mapping_is_defined() - { - _source.ReverseForce.ShouldBe("You With"); - } + [Fact] + public void Should_consider_the_configuration_valid_even_if_some_properties_with_an_inaccessible_setter_are_unmapped() + { + typeof(AutoMapperConfigurationException).ShouldNotBeThrownBy(AssertConfigurationIsValid); + } - [Fact] - public void Should_forward_and_reverse_map_an_inaccessible_source_property_even_if_a_mapping_is_not_defined() - { - _source.Respect.ShouldBe("R-E-S-P-E-C-T"); // justification: if the mapping works one way, it should work in reverse - } + [Fact] + public void Should_forward_and_reverse_map_a_property_that_is_accessible_on_both_source_and_destination() + { + _source.Name.ShouldBe("Bob"); + } + + [Fact] + public void Should_forward_and_reverse_map_an_inaccessible_destination_property_if_a_mapping_is_defined() + { + _source.Force.ShouldBe("With You"); + } + + [Fact] + public void Should_forward_and_reverse_map_an_inaccessible_source_property_if_a_mapping_is_defined() + { + _source.ReverseForce.ShouldBe("You With"); + } + + [Fact] + public void Should_forward_and_reverse_map_an_inaccessible_source_property_even_if_a_mapping_is_not_defined() + { + _source.Respect.ShouldBe("R-E-S-P-E-C-T"); // justification: if the mapping works one way, it should work in reverse } } \ No newline at end of file diff --git a/src/UnitTests/ConfigCompilation.cs b/src/UnitTests/ConfigCompilation.cs index 45c16e317b..a6d22a8f2b 100644 --- a/src/UnitTests/ConfigCompilation.cs +++ b/src/UnitTests/ConfigCompilation.cs @@ -1,29 +1,28 @@ -namespace AutoMapper.UnitTests +namespace AutoMapper.UnitTests; + +using System.Collections.Generic; +using Shouldly; +using Xunit; + +public class ConfigCompilation : NonValidatingSpecBase { - using System.Collections.Generic; - using Shouldly; - using Xunit; + public class Source { } + public class Dest { } + public class Source2 { } + public class Dest2 { } - public class ConfigCompilation : NonValidatingSpecBase + protected override MapperConfiguration CreateConfiguration() => new(cfg => { - public class Source { } - public class Dest { } - public class Source2 { } - public class Dest2 { } + cfg.CreateMap(); + cfg.CreateMap(); + cfg.CreateMap(typeof(IEnumerable<>), typeof(IEnumerable<>)).ConvertUsing(s => s); + }); - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - cfg.CreateMap(); - cfg.CreateMap(typeof(IEnumerable<>), typeof(IEnumerable<>)).ConvertUsing(s => s); - }); - - [Fact] - public void Should_compile_mappings() - { - Configuration.CompileMappings(); + [Fact] + public void Should_compile_mappings() + { + Configuration.CompileMappings(); - Mapper.Map(new Source()).ShouldNotBeNull(); - } + Mapper.Map(new Source()).ShouldNotBeNull(); } } \ No newline at end of file diff --git a/src/UnitTests/ConfigurationFeatureTest.cs b/src/UnitTests/ConfigurationFeatureTest.cs index 0529418fbf..f97cac2667 100644 --- a/src/UnitTests/ConfigurationFeatureTest.cs +++ b/src/UnitTests/ConfigurationFeatureTest.cs @@ -4,140 +4,139 @@ using System.Collections.Generic; using Xunit; -namespace AutoMapper.UnitTests +namespace AutoMapper.UnitTests; + +public class ConfigurationFeatureTest { - public class ConfigurationFeatureTest + [Fact] + public void Adding_same_feature_multiple_times_should_replace_eachother() { - [Fact] - public void Adding_same_feature_multiple_times_should_replace_eachother() + var featureA = new ConfigurationExpressionFeatureA(1); + var featureB = new ConfigurationExpressionFeatureB(1); + var config = new MapperConfiguration(cfg => { - var featureA = new ConfigurationExpressionFeatureA(1); - var featureB = new ConfigurationExpressionFeatureB(1); - var config = new MapperConfiguration(cfg => - { - cfg.SetFeature(new ConfigurationExpressionFeatureA(3)); - cfg.SetFeature(new ConfigurationExpressionFeatureA(2)); - cfg.SetFeature(featureA); - cfg.SetFeature(new ConfigurationExpressionFeatureB(3)); - cfg.SetFeature(new ConfigurationExpressionFeatureB(2)); - cfg.SetFeature(featureB); - }); - - Validate(featureA, config); - Validate(featureB, config); - } + cfg.SetFeature(new ConfigurationExpressionFeatureA(3)); + cfg.SetFeature(new ConfigurationExpressionFeatureA(2)); + cfg.SetFeature(featureA); + cfg.SetFeature(new ConfigurationExpressionFeatureB(3)); + cfg.SetFeature(new ConfigurationExpressionFeatureB(2)); + cfg.SetFeature(featureB); + }); + + Validate(featureA, config); + Validate(featureB, config); + } - [Fact] - public void Add_single_feature() + [Fact] + public void Add_single_feature() + { + var featureA = new ConfigurationExpressionFeatureA(1); + var config = new MapperConfiguration(cfg => { - var featureA = new ConfigurationExpressionFeatureA(1); - var config = new MapperConfiguration(cfg => - { - cfg.SetFeature(featureA); - }); + cfg.SetFeature(featureA); + }); - Validate(featureA, config); - } + Validate(featureA, config); + } - [Fact] - public void Add_multiple_features() + [Fact] + public void Add_multiple_features() + { + var featureA = new ConfigurationExpressionFeatureA(1); + var featureB = new ConfigurationExpressionFeatureB(2); + var config = new MapperConfiguration(cfg => { - var featureA = new ConfigurationExpressionFeatureA(1); - var featureB = new ConfigurationExpressionFeatureB(2); - var config = new MapperConfiguration(cfg => - { - cfg.SetFeature(featureA); - cfg.SetFeature(featureB); - }); - - Validate(featureA, config); - Validate(featureB, config); - } + cfg.SetFeature(featureA); + cfg.SetFeature(featureB); + }); - private void Validate(ConfigurationExpressionFeatureBase feature, MapperConfiguration config) - where TFeature : ConfigurationFeatureBase - { - feature.ConfigurationProviders.ShouldBeOfLength(1); + Validate(featureA, config); + Validate(featureB, config); + } + + private void Validate(ConfigurationExpressionFeatureBase feature, MapperConfiguration config) + where TFeature : ConfigurationFeatureBase + { + feature.ConfigurationProviders.ShouldBeOfLength(1); + + var configurationFeature = config.Internal().Features.Get(); + configurationFeature.ShouldNotBeNull(); + configurationFeature.Value.ShouldBe(feature.Value); + configurationFeature.SealedCount.ShouldBe(1); + } - var configurationFeature = config.Internal().Features.Get(); - configurationFeature.ShouldNotBeNull(); - configurationFeature.Value.ShouldBe(feature.Value); - configurationFeature.SealedCount.ShouldBe(1); + public class ConfigurationExpressionFeatureA : ConfigurationExpressionFeatureBase + { + public ConfigurationExpressionFeatureA(int value) : base(value, new ConfigurationFeatureA(value)) + { } + } - public class ConfigurationExpressionFeatureA : ConfigurationExpressionFeatureBase + public class ConfigurationExpressionFeatureB : ConfigurationExpressionFeatureBase + { + public ConfigurationExpressionFeatureB(int value) : base(value, new ConfigurationFeatureB(value)) { - public ConfigurationExpressionFeatureA(int value) : base(value, new ConfigurationFeatureA(value)) - { - } } + } + + public abstract class ConfigurationExpressionFeatureBase : ConfigurationExpressionFeatureBase + where TFeature : IRuntimeFeature + { + private readonly TFeature _feature; - public class ConfigurationExpressionFeatureB : ConfigurationExpressionFeatureBase + protected ConfigurationExpressionFeatureBase(int value, TFeature feature) + : base(value) { - public ConfigurationExpressionFeatureB(int value) : base(value, new ConfigurationFeatureB(value)) - { - } + _feature = feature; } - public abstract class ConfigurationExpressionFeatureBase : ConfigurationExpressionFeatureBase - where TFeature : IRuntimeFeature + public override void Configure(IGlobalConfiguration configurationProvider) { - private readonly TFeature _feature; - - protected ConfigurationExpressionFeatureBase(int value, TFeature feature) - : base(value) - { - _feature = feature; - } - - public override void Configure(IGlobalConfiguration configurationProvider) - { - ConfigurationProviders.Add(configurationProvider); - configurationProvider.Features.Set(_feature); - } + ConfigurationProviders.Add(configurationProvider); + configurationProvider.Features.Set(_feature); } + } + + public abstract class ConfigurationExpressionFeatureBase : IGlobalFeature + { + public int Value { get; } + public List ConfigurationProviders { get; } = new List(); - public abstract class ConfigurationExpressionFeatureBase : IGlobalFeature + protected ConfigurationExpressionFeatureBase(int value) { - public int Value { get; } - public List ConfigurationProviders { get; } = new List(); + Value = value; + } - protected ConfigurationExpressionFeatureBase(int value) - { - Value = value; - } + public abstract void Configure(IGlobalConfiguration configurationProvider); + } - public abstract void Configure(IGlobalConfiguration configurationProvider); + public class ConfigurationFeatureA : ConfigurationFeatureBase + { + public ConfigurationFeatureA(int value) : base(value) + { } + } - public class ConfigurationFeatureA : ConfigurationFeatureBase + public class ConfigurationFeatureB : ConfigurationFeatureBase + { + public ConfigurationFeatureB(int value) : base(value) { - public ConfigurationFeatureA(int value) : base(value) - { - } } + } + + public abstract class ConfigurationFeatureBase : IRuntimeFeature + { + public int SealedCount { get; private set; } + public int Value { get; } - public class ConfigurationFeatureB : ConfigurationFeatureBase + public ConfigurationFeatureBase(int value) { - public ConfigurationFeatureB(int value) : base(value) - { - } + Value = value; } - public abstract class ConfigurationFeatureBase : IRuntimeFeature + void IRuntimeFeature.Seal(IGlobalConfiguration configurationProvider) { - public int SealedCount { get; private set; } - public int Value { get; } - - public ConfigurationFeatureBase(int value) - { - Value = value; - } - - void IRuntimeFeature.Seal(IGlobalConfiguration configurationProvider) - { - SealedCount++; - } + SealedCount++; } } } \ No newline at end of file diff --git a/src/UnitTests/ConfigurationRules.cs b/src/UnitTests/ConfigurationRules.cs index ebc900675a..f41fee8a84 100644 --- a/src/UnitTests/ConfigurationRules.cs +++ b/src/UnitTests/ConfigurationRules.cs @@ -4,93 +4,92 @@ using Shouldly; using Xunit; -namespace AutoMapper.UnitTests +namespace AutoMapper.UnitTests; + +public class ConfigurationRules : NonValidatingSpecBase { - public class ConfigurationRules : NonValidatingSpecBase - { - public class Source { } - public class Dest { } + public class Source { } + public class Dest { } - public class Profile1 : Profile + public class Profile1 : Profile + { + public Profile1() { - public Profile1() - { - CreateMap(); - } + CreateMap(); } + } - public class Profile2 : Profile + public class Profile2 : Profile + { + public Profile2() { - public Profile2() - { - CreateMap(); - } + CreateMap(); } + } - [Fact] - public void Should_throw_for_multiple_create_map_calls() + [Fact] + public void Should_throw_for_multiple_create_map_calls() + { + var config = new MapperConfiguration(cfg => { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap(); - cfg.CreateMap(); - }); + cfg.CreateMap(); + cfg.CreateMap(); + }); - typeof(DuplicateTypeMapConfigurationException).ShouldBeThrownBy(() => config.AssertConfigurationIsValid()); - } + typeof(DuplicateTypeMapConfigurationException).ShouldBeThrownBy(() => config.AssertConfigurationIsValid()); + } - [Fact] - public void Should_not_throw_when_allowing_multiple_create_map_calls() + [Fact] + public void Should_not_throw_when_allowing_multiple_create_map_calls() + { + var config = new MapperConfiguration(cfg => { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap(); - cfg.CreateMap(); - cfg.Internal().AllowAdditiveTypeMapCreation = true; - }); + cfg.CreateMap(); + cfg.CreateMap(); + cfg.Internal().AllowAdditiveTypeMapCreation = true; + }); - typeof(DuplicateTypeMapConfigurationException).ShouldNotBeThrownBy(() => config.AssertConfigurationIsValid()); - } + typeof(DuplicateTypeMapConfigurationException).ShouldNotBeThrownBy(() => config.AssertConfigurationIsValid()); + } - [Fact] - public void Should_throw_for_multiple_create_map_calls_in_different_profiles() + [Fact] + public void Should_throw_for_multiple_create_map_calls_in_different_profiles() + { + var config = new MapperConfiguration(cfg => { - var config = new MapperConfiguration(cfg => - { - cfg.AddProfile(); - cfg.AddProfile(); - }); + cfg.AddProfile(); + cfg.AddProfile(); + }); - typeof(DuplicateTypeMapConfigurationException).ShouldBeThrownBy(() => config.AssertConfigurationIsValid()); - } + typeof(DuplicateTypeMapConfigurationException).ShouldBeThrownBy(() => config.AssertConfigurationIsValid()); + } - [Fact] - public void Should_not_throw_when_allowing_multiple_create_map_calls_in_different_profiles() + [Fact] + public void Should_not_throw_when_allowing_multiple_create_map_calls_in_different_profiles() + { + var config = new MapperConfiguration(cfg => { - var config = new MapperConfiguration(cfg => - { - cfg.AddProfile(); - cfg.AddProfile(); - cfg.Internal().AllowAdditiveTypeMapCreation = true; - }); + cfg.AddProfile(); + cfg.AddProfile(); + cfg.Internal().AllowAdditiveTypeMapCreation = true; + }); - typeof(DuplicateTypeMapConfigurationException).ShouldNotBeThrownBy(() => config.AssertConfigurationIsValid()); - } + typeof(DuplicateTypeMapConfigurationException).ShouldNotBeThrownBy(() => config.AssertConfigurationIsValid()); + } - [Fact] - public void Should_throw_for_multiple_create_map_calls_in_configuration_expression_and_profile() + [Fact] + public void Should_throw_for_multiple_create_map_calls_in_configuration_expression_and_profile() + { + var config = new MapperConfiguration(cfg => { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap(); - cfg.AddProfile(); - }); - - new Action(() => config.AssertConfigurationIsValid()).ShouldThrowException(c => - { - c.Errors.SelectMany(t => t.ProfileNames).ShouldNotContain(string.Empty); - }); - } + cfg.CreateMap(); + cfg.AddProfile(); + }); + new Action(() => config.AssertConfigurationIsValid()).ShouldThrowException(c => + { + c.Errors.SelectMany(t => t.ProfileNames).ShouldNotContain(string.Empty); + }); } + } \ No newline at end of file diff --git a/src/UnitTests/ConfigurationValidation.cs b/src/UnitTests/ConfigurationValidation.cs index d7c36aa70c..72d7366aa9 100644 --- a/src/UnitTests/ConfigurationValidation.cs +++ b/src/UnitTests/ConfigurationValidation.cs @@ -4,802 +4,801 @@ using Shouldly; using Xunit; -namespace AutoMapper.UnitTests.ConfigurationValidation +namespace AutoMapper.UnitTests.ConfigurationValidation; + +public class ConstructorMappingValidation : NonValidatingSpecBase { - public class ConstructorMappingValidation : NonValidatingSpecBase + public class Destination { - public class Destination - { - public Destination(ComplexType myComplexMember) - { - MyComplexMember = myComplexMember; - } - public ComplexType MyComplexMember { get; } - } - public class Source + public Destination(ComplexType myComplexMember) { - public string MyComplexMember { get; set; } + MyComplexMember = myComplexMember; } - public class ComplexType - { - public int SomeMember { get; } - private ComplexType(int someMember) - { - SomeMember = someMember; - } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - }); - - [Fact] - public void Should_fail_validation() => new Action(AssertConfigurationIsValid).ShouldThrowException(ex=> - ex.MemberMap.ToString().ShouldBe("AutoMapper.UnitTests.ConfigurationValidation.ConstructorMappingValidation+Destination Void .ctor(ComplexType), parameter myComplexMember")); + public ComplexType MyComplexMember { get; } } - - public class When_using_a_type_converter : AutoMapperSpecBase + public class Source { - public class A - { - public string Foo { get; set; } - } - public class B + public string MyComplexMember { get; set; } + } + public class ComplexType + { + public int SomeMember { get; } + private ComplexType(int someMember) { - public C Foo { get; set; } + SomeMember = someMember; } - public class C { } + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + }); - protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.CreateMap().ConvertUsing(x => new B { Foo = new C() })); - [Fact] - public void Validate() => AssertConfigurationIsValid(); + [Fact] + public void Should_fail_validation() => new Action(AssertConfigurationIsValid).ShouldThrowException(ex=> + ex.MemberMap.ToString().ShouldBe("AutoMapper.UnitTests.ConfigurationValidation.ConstructorMappingValidation+Destination Void .ctor(ComplexType), parameter myComplexMember")); +} + +public class When_using_a_type_converter : AutoMapperSpecBase +{ + public class A + { + public string Foo { get; set; } } + public class B + { + public C Foo { get; set; } + } + public class C { } + + protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.CreateMap().ConvertUsing(x => new B { Foo = new C() })); + [Fact] + public void Validate() => AssertConfigurationIsValid(); +} - public class When_using_a_type_converter_class : AutoMapperSpecBase +public class When_using_a_type_converter_class : AutoMapperSpecBase +{ + public class A { - public class A - { - public string Foo { get; set; } - } - public class B - { - public C Foo { get; set; } - } - public class C { } + public string Foo { get; set; } + } + public class B + { + public C Foo { get; set; } + } + public class C { } - protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.CreateMap().ConvertUsing()); + protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.CreateMap().ConvertUsing()); - class Converter : ITypeConverter - { - public B Convert(A source, B dest, ResolutionContext context) => new B { Foo = new C() }; - } - [Fact] - public void Validate() => AssertConfigurationIsValid(); + class Converter : ITypeConverter + { + public B Convert(A source, B dest, ResolutionContext context) => new B { Foo = new C() }; } + [Fact] + public void Validate() => AssertConfigurationIsValid(); +} - public class When_skipping_validation : NonValidatingSpecBase +public class When_skipping_validation : NonValidatingSpecBase +{ + public class Source { - public class Source - { - public int Value { get; set; } - } + public int Value { get; set; } + } - public class Dest - { - public int Blarg { get; set; } - } + public class Dest + { + public int Blarg { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.CreateMap(MemberList.None)); + protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.CreateMap(MemberList.None)); - [Fact] - public void Should_skip_validation() - { - typeof(AutoMapperConfigurationException).ShouldNotBeThrownBy(() => Mapper.ConfigurationProvider.AssertConfigurationIsValid()); - } + [Fact] + public void Should_skip_validation() + { + typeof(AutoMapperConfigurationException).ShouldNotBeThrownBy(() => Mapper.ConfigurationProvider.AssertConfigurationIsValid()); } +} - public class When_constructor_does_not_match : NonValidatingSpecBase +public class When_constructor_does_not_match : NonValidatingSpecBase +{ + public class Source { - public class Source - { - public int Value { get; set; } - } + public int Value { get; set; } + } - public class Dest + public class Dest + { + public Dest(int blarg) { - public Dest(int blarg) - { - Value = blarg; - } - public int Value { get; set; } + Value = blarg; } + public int Value { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.CreateMap()); + protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.CreateMap()); - [Fact] - public void Should_throw() - { - typeof(AutoMapperConfigurationException).ShouldBeThrownBy(AssertConfigurationIsValid); - } + [Fact] + public void Should_throw() + { + typeof(AutoMapperConfigurationException).ShouldBeThrownBy(AssertConfigurationIsValid); } +} - public class When_constructor_does_not_match_ForCtorParam : AutoMapperSpecBase +public class When_constructor_does_not_match_ForCtorParam : AutoMapperSpecBase +{ + public class Source { - public class Source - { - } - public class Dest + } + public class Dest + { + public Dest(int value) { - public Dest(int value) - { - Value = value; - } - public int Value { get; } + Value = value; } + public int Value { get; } + } + + protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.CreateMap().ForCtorParam("value", o=>o.MapFrom(s=>4))); - protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.CreateMap().ForCtorParam("value", o=>o.MapFrom(s=>4))); + [Fact] + public void Should_map() => Mapper.Map(new Source()).Value.ShouldBe(4); +} - [Fact] - public void Should_map() => Mapper.Map(new Source()).Value.ShouldBe(4); +public class When_constructor_partially_matches : NonValidatingSpecBase +{ + public class Source + { + public int Value { get; set; } } - public class When_constructor_partially_matches : NonValidatingSpecBase + public class Dest { - public class Source + public Dest(int value, int blarg) { - public int Value { get; set; } + Value = blarg; } - public class Dest - { - public Dest(int value, int blarg) - { - Value = blarg; - } + public int Value { get; } + } - public int Value { get; } - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.CreateMap()); - protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.CreateMap()); + [Fact] + public void Should_throw() + { + typeof(AutoMapperConfigurationException).ShouldBeThrownBy(AssertConfigurationIsValid); + } +} - [Fact] - public void Should_throw() - { - typeof(AutoMapperConfigurationException).ShouldBeThrownBy(AssertConfigurationIsValid); - } +public class When_constructor_partially_matches_and_ctor_param_configured : NonValidatingSpecBase +{ + public class Source + { + public int Value { get; set; } } - public class When_constructor_partially_matches_and_ctor_param_configured : NonValidatingSpecBase + public class Dest { - public class Source + public Dest(int value, int blarg) { - public int Value { get; set; } + Value = blarg; } - public class Dest - { - public Dest(int value, int blarg) - { - Value = blarg; - } + public int Value { get; } + } - public int Value { get; } - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .ForCtorParam("blarg", opt => opt.MapFrom(src => src.Value)); + }); - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ForCtorParam("blarg", opt => opt.MapFrom(src => src.Value)); - }); + [Fact] + public void Should_throw() + { + typeof(AutoMapperConfigurationException).ShouldNotBeThrownBy(AssertConfigurationIsValid); + } +} - [Fact] - public void Should_throw() - { - typeof(AutoMapperConfigurationException).ShouldNotBeThrownBy(AssertConfigurationIsValid); - } +public class When_constructor_partially_matches_and_constructor_validation_skipped : NonValidatingSpecBase +{ + public class Source + { + public int Value { get; set; } } - public class When_constructor_partially_matches_and_constructor_validation_skipped : NonValidatingSpecBase + public class Dest { - public class Source + public Dest(int value, int blarg) { - public int Value { get; set; } + Value = blarg; } - public class Dest - { - public Dest(int value, int blarg) - { - Value = blarg; - } - - public int Value { get; } - } + public int Value { get; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().DisableCtorValidation(); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().DisableCtorValidation(); + }); - [Fact] - public void Should_throw() - { - typeof(AutoMapperConfigurationException).ShouldNotBeThrownBy(AssertConfigurationIsValid); - } + [Fact] + public void Should_throw() + { + typeof(AutoMapperConfigurationException).ShouldNotBeThrownBy(AssertConfigurationIsValid); } +} - public class When_testing_a_dto_with_mismatched_members : NonValidatingSpecBase +public class When_testing_a_dto_with_mismatched_members : NonValidatingSpecBase +{ + public class ModelObject { - public class ModelObject - { - public string Foo { get; set; } - public string Barr { get; set; } - } + public string Foo { get; set; } + public string Barr { get; set; } + } - public class ModelDto - { - public string Foo { get; set; } - public string Bar { get; set; } - } + public class ModelDto + { + public string Foo { get; set; } + public string Bar { get; set; } + } - public class ModelObject2 - { - public string Foo { get; set; } - public string Barr { get; set; } - } + public class ModelObject2 + { + public string Foo { get; set; } + public string Barr { get; set; } + } - public class ModelDto2 - { - public string Foo { get; set; } - public string Bar { get; set; } - public string Bar1 { get; set; } - public string Bar2 { get; set; } - public string Bar3 { get; set; } - public string Bar4 { get; set; } - } + public class ModelDto2 + { + public string Foo { get; set; } + public string Bar { get; set; } + public string Bar1 { get; set; } + public string Bar2 { get; set; } + public string Bar3 { get; set; } + public string Bar4 { get; set; } + } - public class ModelObject3 - { - public string Foo { get; set; } - public string Bar { get; set; } - public string Bar1 { get; set; } - public string Bar2 { get; set; } - public string Bar3 { get; set; } - public string Bar4 { get; set; } - } + public class ModelObject3 + { + public string Foo { get; set; } + public string Bar { get; set; } + public string Bar1 { get; set; } + public string Bar2 { get; set; } + public string Bar3 { get; set; } + public string Bar4 { get; set; } + } - public class ModelDto3 - { - public string Foo { get; set; } - public string Bar { get; set; } - } + public class ModelDto3 + { + public string Foo { get; set; } + public string Bar { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - cfg.CreateMap(); - cfg.CreateMap(MemberList.Source); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + cfg.CreateMap(); + cfg.CreateMap(MemberList.Source); + }); - [Fact] - public void Should_fail_a_configuration_check() - { - typeof(AutoMapperConfigurationException).ShouldBeThrownBy(AssertConfigurationIsValid); - } - } + [Fact] + public void Should_fail_a_configuration_check() + { + typeof(AutoMapperConfigurationException).ShouldBeThrownBy(AssertConfigurationIsValid); + } +} - public class ResolversWithSourceValidation : AutoMapperSpecBase +public class ResolversWithSourceValidation : AutoMapperSpecBase +{ + class Source { - class Source - { - public int Resolved { get; set; } - public int TypedResolved { get; set; } - public int Converted { get; set; } - public int TypedConverted { get; set; } - } - class Destination - { - public int ResolvedDest { get; set; } - public int TypedResolvedDest { get; set; } - public int ConvertedDest { get; set; } - public int TypedConvertedDest { get; set; } - } - class MemberResolver : IMemberValueResolver - { - public int Resolve(Source source, Destination destination, int sourceMember, int destinationMember, ResolutionContext context) => 5; - } - class ValueConverter : IValueConverter - { - public int Convert(int sourceMember, ResolutionContext context) => 5; - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(MemberList.Source) - .ForMember(d => d.ResolvedDest, o => o.MapFrom("Resolved")) - .ForMember(d=>d.TypedResolvedDest, o => o.MapFrom(s => s.TypedResolved)) - .ForMember(d => d.ConvertedDest, o => o.ConvertUsing("Converted")) - .ForMember(d => d.TypedConvertedDest, o => o.ConvertUsing(s => s.TypedConverted)); - }); - [Fact] - public void Should_work() - { - var result = Mapper.Map(new Source()); - result.ResolvedDest.ShouldBe(5); - result.TypedResolvedDest.ShouldBe(5); - result.ConvertedDest.ShouldBe(5); - result.TypedConvertedDest.ShouldBe(5); - } + public int Resolved { get; set; } + public int TypedResolved { get; set; } + public int Converted { get; set; } + public int TypedConverted { get; set; } + } + class Destination + { + public int ResolvedDest { get; set; } + public int TypedResolvedDest { get; set; } + public int ConvertedDest { get; set; } + public int TypedConvertedDest { get; set; } } + class MemberResolver : IMemberValueResolver + { + public int Resolve(Source source, Destination destination, int sourceMember, int destinationMember, ResolutionContext context) => 5; + } + class ValueConverter : IValueConverter + { + public int Convert(int sourceMember, ResolutionContext context) => 5; + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(MemberList.Source) + .ForMember(d => d.ResolvedDest, o => o.MapFrom("Resolved")) + .ForMember(d=>d.TypedResolvedDest, o => o.MapFrom(s => s.TypedResolved)) + .ForMember(d => d.ConvertedDest, o => o.ConvertUsing("Converted")) + .ForMember(d => d.TypedConvertedDest, o => o.ConvertUsing(s => s.TypedConverted)); + }); + [Fact] + public void Should_work() + { + var result = Mapper.Map(new Source()); + result.ResolvedDest.ShouldBe(5); + result.TypedResolvedDest.ShouldBe(5); + result.ConvertedDest.ShouldBe(5); + result.TypedConvertedDest.ShouldBe(5); + } +} - public class NonMemberExpressionWithSourceValidation : NonValidatingSpecBase +public class NonMemberExpressionWithSourceValidation : NonValidatingSpecBase +{ + class Source + { + public string Value { get; set; } + } + class Destination { - class Source - { - public string Value { get; set; } - } - class Destination - { - public string OtherValue { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(c=>c.CreateMap(MemberList.Source) - .ForMember(d=>d.OtherValue, o=>o.MapFrom(s=>s.Value ?? ""))); - [Fact] - public void Should_be_ignored() => new Action(AssertConfigurationIsValid) - .ShouldThrow().Errors[0].UnmappedPropertyNames[0].ShouldBe(nameof(Source.Value)); + public string OtherValue { get; set; } } + protected override MapperConfiguration CreateConfiguration() => new(c=>c.CreateMap(MemberList.Source) + .ForMember(d=>d.OtherValue, o=>o.MapFrom(s=>s.Value ?? ""))); + [Fact] + public void Should_be_ignored() => new Action(AssertConfigurationIsValid) + .ShouldThrow().Errors[0].UnmappedPropertyNames[0].ShouldBe(nameof(Source.Value)); +} - public class MatchingNonMemberExpressionWithSourceValidation : NonValidatingSpecBase +public class MatchingNonMemberExpressionWithSourceValidation : NonValidatingSpecBase +{ + class Source + { + public string Value { get; set; } + } + class Destination { - class Source - { - public string Value { get; set; } - } - class Destination - { - public string Value { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(c => c.CreateMap(MemberList.Source) - .ForMember(d => d.Value, o => o.MapFrom(s => s.Value ?? ""))); - [Fact] - public void Should_be_ignored() => new Action(AssertConfigurationIsValid) - .ShouldThrow().Errors[0].UnmappedPropertyNames[0].ShouldBe(nameof(Source.Value)); + public string Value { get; set; } } + protected override MapperConfiguration CreateConfiguration() => new(c => c.CreateMap(MemberList.Source) + .ForMember(d => d.Value, o => o.MapFrom(s => s.Value ?? ""))); + [Fact] + public void Should_be_ignored() => new Action(AssertConfigurationIsValid) + .ShouldThrow().Errors[0].UnmappedPropertyNames[0].ShouldBe(nameof(Source.Value)); +} + +public class When_testing_a_dto_with_fully_mapped_and_custom_matchers : AutoMapperSpecBase +{ + public class ModelObject + { + public string Foo { get; set; } + public string Barr { get; set; } + } - public class When_testing_a_dto_with_fully_mapped_and_custom_matchers : AutoMapperSpecBase + public class ModelDto { - public class ModelObject - { - public string Foo { get; set; } - public string Barr { get; set; } - } + public string Foo { get; set; } + public string Bar { get; set; } + } - public class ModelDto - { - public string Foo { get; set; } - public string Bar { get; set; } - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .ForMember(dto => dto.Bar, opt => opt.MapFrom(m => m.Barr)); + }); + [Fact] + public void Validate() => AssertConfigurationIsValid(); +} + +public class When_testing_a_dto_with_matching_member_names_but_mismatched_types : NonValidatingSpecBase +{ + public class Source + { + public decimal Value { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ForMember(dto => dto.Bar, opt => opt.MapFrom(m => m.Barr)); - }); - [Fact] - public void Validate() => AssertConfigurationIsValid(); + public class Destination + { + public Type Value { get; set; } } - public class When_testing_a_dto_with_matching_member_names_but_mismatched_types : NonValidatingSpecBase + protected override MapperConfiguration CreateConfiguration() => new(cfg => { - public class Source - { - public decimal Value { get; set; } - } + cfg.CreateMap(); + }); - public class Destination - { - public Type Value { get; set; } - } + [Fact] + public void Should_fail_a_configuration_check() + { + typeof(AutoMapperConfigurationException).ShouldBeThrownBy(AssertConfigurationIsValid); + } +} - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - }); +public class When_testing_a_dto_with_member_type_mapped_mappings : AutoMapperSpecBase +{ + private AutoMapperConfigurationException _exception; - [Fact] - public void Should_fail_a_configuration_check() - { - typeof(AutoMapperConfigurationException).ShouldBeThrownBy(AssertConfigurationIsValid); - } + public class Source + { + public int Value { get; set; } + public OtherSource Other { get; set; } } - public class When_testing_a_dto_with_member_type_mapped_mappings : AutoMapperSpecBase + public class OtherSource { - private AutoMapperConfigurationException _exception; + public int Value { get; set; } + } - public class Source - { - public int Value { get; set; } - public OtherSource Other { get; set; } - } + public class Destination + { + public int Value { get; set; } + public OtherDest Other { get; set; } + } - public class OtherSource - { - public int Value { get; set; } - } + public class OtherDest + { + public int Value { get; set; } + } + + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + cfg.CreateMap(); + }); - public class Destination + protected override void Because_of() + { + try { - public int Value { get; set; } - public OtherDest Other { get; set; } + AssertConfigurationIsValid(); } - - public class OtherDest + catch (AutoMapperConfigurationException ex) { - public int Value { get; set; } + _exception = ex; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - cfg.CreateMap(); - }); + [Fact] + public void Should_pass_a_configuration_check() + { + _exception.ShouldBeNull(); + } +} - protected override void Because_of() - { - try - { - AssertConfigurationIsValid(); - } - catch (AutoMapperConfigurationException ex) - { - _exception = ex; - } - } +public class When_testing_a_dto_with_matched_members_but_mismatched_types_that_are_ignored : AutoMapperSpecBase +{ + private AutoMapperConfigurationException _exception; - [Fact] - public void Should_pass_a_configuration_check() - { - _exception.ShouldBeNull(); - } + public class ModelObject + { + public string Foo { get; set; } + public string Bar { get; set; } } - public class When_testing_a_dto_with_matched_members_but_mismatched_types_that_are_ignored : AutoMapperSpecBase + public class ModelDto { - private AutoMapperConfigurationException _exception; + public string Foo { get; set; } + public int Bar { get; set; } + } - public class ModelObject - { - public string Foo { get; set; } - public string Bar { get; set; } - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .ForMember(dest => dest.Bar, opt => opt.Ignore()); + }); - public class ModelDto + protected override void Because_of() + { + try { - public string Foo { get; set; } - public int Bar { get; set; } + AssertConfigurationIsValid(); } - - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ForMember(dest => dest.Bar, opt => opt.Ignore()); - }); - - protected override void Because_of() + catch (AutoMapperConfigurationException ex) { - try - { - AssertConfigurationIsValid(); - } - catch (AutoMapperConfigurationException ex) - { - _exception = ex; - } + _exception = ex; } + } - [Fact] - public void Should_pass_a_configuration_check() - { - _exception.ShouldBeNull(); - } + [Fact] + public void Should_pass_a_configuration_check() + { + _exception.ShouldBeNull(); } +} - public class When_testing_a_dto_with_array_types_with_mismatched_element_types : NonValidatingSpecBase +public class When_testing_a_dto_with_array_types_with_mismatched_element_types : NonValidatingSpecBase +{ + public class Source { - public class Source - { - public SourceItem[] Items; - } + public SourceItem[] Items; + } - public class Destination - { - public DestinationItem[] Items; - } + public class Destination + { + public DestinationItem[] Items; + } - public class SourceItem - { + public class SourceItem + { - } + } - public class DestinationItem - { + public class DestinationItem + { - } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + }); - [Fact] - public void Should_fail_a_configuration_check() - { - typeof(AutoMapperConfigurationException).ShouldBeThrownBy(AssertConfigurationIsValid); - } + [Fact] + public void Should_fail_a_configuration_check() + { + typeof(AutoMapperConfigurationException).ShouldBeThrownBy(AssertConfigurationIsValid); } +} - public class When_testing_a_dto_with_list_types_with_mismatched_element_types : NonValidatingSpecBase +public class When_testing_a_dto_with_list_types_with_mismatched_element_types : NonValidatingSpecBase +{ + public class Source { - public class Source - { - public List Items; - } + public List Items; + } - public class Destination - { - public List Items; - } + public class Destination + { + public List Items; + } - public class SourceItem - { + public class SourceItem + { - } + } - public class DestinationItem - { + public class DestinationItem + { - } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + }); - [Fact] - public void Should_fail_a_configuration_check() - { - typeof(AutoMapperConfigurationException).ShouldBeThrownBy(AssertConfigurationIsValid); - } + [Fact] + public void Should_fail_a_configuration_check() + { + typeof(AutoMapperConfigurationException).ShouldBeThrownBy(AssertConfigurationIsValid); } +} - public class When_testing_a_dto_with_readonly_members : NonValidatingSpecBase +public class When_testing_a_dto_with_readonly_members : NonValidatingSpecBase +{ + public class Source { - public class Source - { - public int Value { get; set; } - } + public int Value { get; set; } + } - public class Destination - { - public int Value { get; set; } - public string ValuePlusOne { get { return (Value + 1).ToString(); } } - public int ValuePlusTwo { get { return Value + 2; } } - } + public class Destination + { + public int Value { get; set; } + public string ValuePlusOne { get { return (Value + 1).ToString(); } } + public int ValuePlusTwo { get { return Value + 2; } } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + }); - protected override void Because_of() - { - Mapper.Map(new Source { Value = 5 }); - } + protected override void Because_of() + { + Mapper.Map(new Source { Value = 5 }); + } - [Fact] - public void Should_be_valid() - { - typeof(AutoMapperConfigurationException).ShouldNotBeThrownBy(AssertConfigurationIsValid); - } + [Fact] + public void Should_be_valid() + { + typeof(AutoMapperConfigurationException).ShouldNotBeThrownBy(AssertConfigurationIsValid); } +} - public class When_testing_a_dto_in_a_specfic_profile : NonValidatingSpecBase +public class When_testing_a_dto_in_a_specfic_profile : NonValidatingSpecBase +{ + public class GoodSource { - public class GoodSource - { - public int Value { get; set; } - } + public int Value { get; set; } + } - public class GoodDest - { - public int Value { get; set; } - } + public class GoodDest + { + public int Value { get; set; } + } - public class BadDest - { - public int Valufffff { get; set; } - } + public class BadDest + { + public int Valufffff { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateProfile("Good", profile => + { + profile.CreateMap(); + }); + cfg.CreateProfile("Bad", profile => { - cfg.CreateProfile("Good", profile => - { - profile.CreateMap(); - }); - cfg.CreateProfile("Bad", profile => - { - profile.CreateMap(); - }); + profile.CreateMap(); }); + }); - [Fact] - public void Should_ignore_bad_dtos_in_other_profiles() => - typeof(AutoMapperConfigurationException).ShouldNotBeThrownBy(() => AssertConfigurationIsValid("Good")); - [Fact] - public void Should_throw_when_profile_name_does_not_exist() => - typeof(ArgumentOutOfRangeException).ShouldBeThrownBy(() => AssertConfigurationIsValid("Does not exist")); - } + [Fact] + public void Should_ignore_bad_dtos_in_other_profiles() => + typeof(AutoMapperConfigurationException).ShouldNotBeThrownBy(() => AssertConfigurationIsValid("Good")); + [Fact] + public void Should_throw_when_profile_name_does_not_exist() => + typeof(ArgumentOutOfRangeException).ShouldBeThrownBy(() => AssertConfigurationIsValid("Does not exist")); +} - public class When_testing_a_dto_with_mismatched_custom_member_mapping : NonValidatingSpecBase - { - public class SubBarr { } +public class When_testing_a_dto_with_mismatched_custom_member_mapping : NonValidatingSpecBase +{ + public class SubBarr { } - public class SubBar { } + public class SubBar { } - public class ModelObject - { - public string Foo { get; set; } - public SubBarr Barr { get; set; } - } + public class ModelObject + { + public string Foo { get; set; } + public SubBarr Barr { get; set; } + } - public class ModelDto - { - public string Foo { get; set; } - public SubBar Bar { get; set; } - } + public class ModelDto + { + public string Foo { get; set; } + public SubBar Bar { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ForMember(dest => dest.Bar, opt => opt.MapFrom(src => src.Barr)); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .ForMember(dest => dest.Bar, opt => opt.MapFrom(src => src.Barr)); + }); - [Fact] - public void Should_fail_a_configuration_check() - { - typeof(AutoMapperConfigurationException).ShouldBeThrownBy(AssertConfigurationIsValid); - } + [Fact] + public void Should_fail_a_configuration_check() + { + typeof(AutoMapperConfigurationException).ShouldBeThrownBy(AssertConfigurationIsValid); } +} - public class When_testing_a_dto_with_value_specified_members : NonValidatingSpecBase +public class When_testing_a_dto_with_value_specified_members : NonValidatingSpecBase +{ + public class Source { } + public class Destination { - public class Source { } - public class Destination - { - public int Value { get; set; } - } + public int Value { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - object i = 7; - cfg.CreateMap() - .ForMember(dest => dest.Value, opt => opt.MapFrom(src => i)); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + object i = 7; + cfg.CreateMap() + .ForMember(dest => dest.Value, opt => opt.MapFrom(src => i)); + }); - [Fact] - public void Should_validate_successfully() - { - typeof(AutoMapperConfigurationException).ShouldNotBeThrownBy(AssertConfigurationIsValid); - } + [Fact] + public void Should_validate_successfully() + { + typeof(AutoMapperConfigurationException).ShouldNotBeThrownBy(AssertConfigurationIsValid); } +} - public class When_testing_a_dto_with_setter_only_peroperty_member : NonValidatingSpecBase +public class When_testing_a_dto_with_setter_only_peroperty_member : NonValidatingSpecBase +{ + public class Source { - public class Source - { - public string Value { set { } } - } + public string Value { set { } } + } - public class Destination - { - public string Value { get; set; } - } + public class Destination + { + public string Value { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + }); - [Fact] - public void Should_fail_a_configuration_check() - { - typeof(AutoMapperConfigurationException).ShouldBeThrownBy(AssertConfigurationIsValid); - } + [Fact] + public void Should_fail_a_configuration_check() + { + typeof(AutoMapperConfigurationException).ShouldBeThrownBy(AssertConfigurationIsValid); } +} - public class When_testing_a_dto_with_matching_void_method_member : NonValidatingSpecBase +public class When_testing_a_dto_with_matching_void_method_member : NonValidatingSpecBase +{ + public class Source { - public class Source + public void Method() { - public void Method() - { - } } + } - public class Destination - { - public string Method { get; set; } - } + public class Destination + { + public string Method { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + }); - [Fact] - public void Should_fail_a_configuration_check() - { - typeof(AutoMapperConfigurationException).ShouldBeThrownBy(AssertConfigurationIsValid); - } + [Fact] + public void Should_fail_a_configuration_check() + { + typeof(AutoMapperConfigurationException).ShouldBeThrownBy(AssertConfigurationIsValid); } +} - public class When_redirecting_types : NonValidatingSpecBase +public class When_redirecting_types : NonValidatingSpecBase +{ + protected override MapperConfiguration CreateConfiguration() => new(cfg => { - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ForMember(d => d.DifferentName, opt => opt.MapFrom(s => s.Name)); - cfg.CreateMap().As(); - }); + cfg.CreateMap() + .ForMember(d => d.DifferentName, opt => opt.MapFrom(s => s.Name)); + cfg.CreateMap().As(); + }); - [Fact] - public void Should_pass_configuration_check() - { - typeof(AutoMapperConfigurationException).ShouldNotBeThrownBy(AssertConfigurationIsValid); - } + [Fact] + public void Should_pass_configuration_check() + { + typeof(AutoMapperConfigurationException).ShouldNotBeThrownBy(AssertConfigurationIsValid); + } - class ConcreteSource - { - public string Name { get; set; } - } + class ConcreteSource + { + public string Name { get; set; } + } - class ConcreteDest : IAbstractDest - { - public string DifferentName { get; set; } - } + class ConcreteDest : IAbstractDest + { + public string DifferentName { get; set; } + } - interface IAbstractDest - { - string DifferentName { get; set; } - } - } + interface IAbstractDest + { + string DifferentName { get; set; } + } +} - public class When_configuring_a_resolver : AutoMapperSpecBase - { - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().ForMember(d => d.Details, o => o.MapFrom()); - }); - public class DetailsValueResolver : IValueResolver>> - { - public List> Resolve(Query source, Command destination, List> destMember, ResolutionContext context) - { - return source.Details - .Select(d => new KeyValuePair(d.ToString(), d.ToString())) - .ToList(); - } - } - public class Query +public class When_configuring_a_resolver : AutoMapperSpecBase +{ + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().ForMember(d => d.Details, o => o.MapFrom()); + }); + public class DetailsValueResolver : IValueResolver>> + { + public List> Resolve(Query source, Command destination, List> destMember, ResolutionContext context) { - public List Details { get; set; } + return source.Details + .Select(d => new KeyValuePair(d.ToString(), d.ToString())) + .ToList(); } - - public class Command - { - public List> Details { get; private set; } - } - [Fact] - public void Validate() => AssertConfigurationIsValid(); } + public class Query + { + public List Details { get; set; } + } + + public class Command + { + public List> Details { get; private set; } + } + [Fact] + public void Validate() => AssertConfigurationIsValid(); } \ No newline at end of file diff --git a/src/UnitTests/Constructors.cs b/src/UnitTests/Constructors.cs index c5a451479e..dcc51069ec 100644 --- a/src/UnitTests/Constructors.cs +++ b/src/UnitTests/Constructors.cs @@ -4,1826 +4,1825 @@ using Xunit; using Shouldly; using System.Collections.Generic; -namespace AutoMapper.UnitTests.Constructors +namespace AutoMapper.UnitTests.Constructors; + +public class RecordConstructorValidation : AutoMapperSpecBase { - public class RecordConstructorValidation : AutoMapperSpecBase + class Source { - class Source - { - } - record Destination(int Value, int Other){} - protected override MapperConfiguration CreateConfiguration() => new(c => - c.CreateMap().ForCtorParam(nameof(Destination.Value), o => o.MapFrom(s => 0))); - [Fact] - public void Validate() => new Action(AssertConfigurationIsValid).ShouldThrow().Message. - ShouldContainWithoutWhitespace("When mapping to records, consider excluding non-public constructors."); } - public class ConstructorValidation : AutoMapperSpecBase + record Destination(int Value, int Other){} + protected override MapperConfiguration CreateConfiguration() => new(c => + c.CreateMap().ForCtorParam(nameof(Destination.Value), o => o.MapFrom(s => 0))); + [Fact] + public void Validate() => new Action(AssertConfigurationIsValid).ShouldThrow().Message. + ShouldContainWithoutWhitespace("When mapping to records, consider excluding non-public constructors."); +} +public class ConstructorValidation : AutoMapperSpecBase +{ + class Source { - class Source - { - } - class Destination - { - public Destination(int otherValue, int value = 2) { } - public int Value { get; set; } - public int OtherValue { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(c => - c.CreateMap().ForCtorParam("otherValue", o=>o.MapFrom(s=>0))); - [Fact] - public void Validate() => AssertConfigurationIsValid(); } - public class Nullable_enum_default_value : AutoMapperSpecBase + class Destination { - public enum SourceEnum { A, B } - public class Source - { - public SourceEnum? Enum { get; set; } - } - public enum TargetEnum { A, B } - public class Target - { - public TargetEnum? Enum { get; set; } - public Target(TargetEnum? Enum = TargetEnum.A) - { - this.Enum = Enum; - } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg=>cfg.CreateMap()); - [Fact] - void Should_work() => Mapper.Map(new Source { Enum = SourceEnum.B }).Enum.ShouldBe(TargetEnum.B); + public Destination(int otherValue, int value = 2) { } + public int Value { get; set; } + public int OtherValue { get; set; } } - public class Nullable_enum_default_value_null : AutoMapperSpecBase + protected override MapperConfiguration CreateConfiguration() => new(c => + c.CreateMap().ForCtorParam("otherValue", o=>o.MapFrom(s=>0))); + [Fact] + public void Validate() => AssertConfigurationIsValid(); +} +public class Nullable_enum_default_value : AutoMapperSpecBase +{ + public enum SourceEnum { A, B } + public class Source { - public class Source - { - } - public enum TargetEnum { A, B } - public class Target - { - public TargetEnum? Enum { get; } - public Target(TargetEnum? Enum = null) - { - this.Enum = Enum; - } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.CreateMap()); - [Fact] - void Should_work() => Mapper.Map(new Source()).Enum.ShouldBeNull(); + public SourceEnum? Enum { get; set; } } - public class Nullable_enum_default_value_not_null : AutoMapperSpecBase + public enum TargetEnum { A, B } + public class Target { - public class Source + public TargetEnum? Enum { get; set; } + public Target(TargetEnum? Enum = TargetEnum.A) { + this.Enum = Enum; } - public enum TargetEnum { A, B } - public class Target + } + protected override MapperConfiguration CreateConfiguration() => new(cfg=>cfg.CreateMap()); + [Fact] + void Should_work() => Mapper.Map(new Source { Enum = SourceEnum.B }).Enum.ShouldBe(TargetEnum.B); +} +public class Nullable_enum_default_value_null : AutoMapperSpecBase +{ + public class Source + { + } + public enum TargetEnum { A, B } + public class Target + { + public TargetEnum? Enum { get; } + public Target(TargetEnum? Enum = null) { - public TargetEnum? Enum { get; } - public Target(TargetEnum? Enum = TargetEnum.B) - { - this.Enum = Enum; - } + this.Enum = Enum; } - protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.CreateMap()); - [Fact] - void Should_work() => Mapper.Map(new Source()).Enum.ShouldBe(TargetEnum.B); } - public class Dynamic_constructor_mapping : AutoMapperSpecBase + protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.CreateMap()); + [Fact] + void Should_work() => Mapper.Map(new Source()).Enum.ShouldBeNull(); +} +public class Nullable_enum_default_value_not_null : AutoMapperSpecBase +{ + public class Source + { + } + public enum TargetEnum { A, B } + public class Target { - public class ParentDTO + public TargetEnum? Enum { get; } + public Target(TargetEnum? Enum = TargetEnum.B) { - public ChildDTO First => Children[0]; - public List> Children { get; set; } = new List>(); - public int IdParent { get; set; } + this.Enum = Enum; } + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.CreateMap()); + [Fact] + void Should_work() => Mapper.Map(new Source()).Enum.ShouldBe(TargetEnum.B); +} +public class Dynamic_constructor_mapping : AutoMapperSpecBase +{ + public class ParentDTO + { + public ChildDTO First => Children[0]; + public List> Children { get; set; } = new List>(); + public int IdParent { get; set; } + } - public class ChildDTO - { - public int IdChild { get; set; } - public ParentDTO Parent { get; set; } - } + public class ChildDTO + { + public int IdChild { get; set; } + public ParentDTO Parent { get; set; } + } - public class ParentModel + public class ParentModel + { + public ChildModel First { get; set; } + public List> Children { get; set; } = new List>(); + public int IdParent { get; set; } + } + + public class ChildModel + { + int _idChild; + + public ChildModel(ParentModel parent) { - public ChildModel First { get; set; } - public List> Children { get; set; } = new List>(); - public int IdParent { get; set; } + Parent = parent; } - public class ChildModel + public int IdChild { - int _idChild; - - public ChildModel(ParentModel parent) + get => _idChild; + set { - Parent = parent; - } - - public int IdChild - { - get => _idChild; - set + if (_idChild != 0) { - if (_idChild != 0) - { - throw new Exception("Set IdChild again."); - } - _idChild = value; + throw new Exception("Set IdChild again."); } + _idChild = value; } - public ParentModel Parent { get; } } + public ParentModel Parent { get; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(typeof(ParentModel<>), typeof(ParentDTO<>)).ReverseMap(); - cfg.CreateMap(typeof(ChildModel<>), typeof(ChildDTO<>)).ReverseMap(); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(typeof(ParentModel<>), typeof(ParentDTO<>)).ReverseMap(); + cfg.CreateMap(typeof(ChildModel<>), typeof(ChildDTO<>)).ReverseMap(); + }); - [Fact] - public void Should_work() + [Fact] + public void Should_work() + { + var parentDto = new ParentDTO { IdParent = 1 }; + for (var i = 0; i < 5; i++) { - var parentDto = new ParentDTO { IdParent = 1 }; - for (var i = 0; i < 5; i++) - { - parentDto.Children.Add(new ChildDTO { IdChild = i, Parent = parentDto }); - } - var parentModel = Mapper.Map>(parentDto); - var mappedChildren = Mapper.Map>, List>>(parentDto.Children); + parentDto.Children.Add(new ChildDTO { IdChild = i, Parent = parentDto }); } + var parentModel = Mapper.Map>(parentDto); + var mappedChildren = Mapper.Map>, List>>(parentDto.Children); } +} - public class Constructor_mapping_without_preserve_references : AutoMapperSpecBase +public class Constructor_mapping_without_preserve_references : AutoMapperSpecBase +{ + public class ParentDTO { - public class ParentDTO - { - public ChildDTO First => Children[0]; - public List Children { get; set; } = new List(); - public int IdParent { get; set; } - } + public ChildDTO First => Children[0]; + public List Children { get; set; } = new List(); + public int IdParent { get; set; } + } - public class ChildDTO - { - public int IdChild { get; set; } - public ParentDTO Parent { get; set; } - } + public class ChildDTO + { + public int IdChild { get; set; } + public ParentDTO Parent { get; set; } + } + + public class ParentModel + { + public ChildModel First { get; set; } + public List Children { get; set; } = new List(); + public int IdParent { get; set; } + } - public class ParentModel + public class ChildModel + { + int _idChild; + + public ChildModel(ParentModel parent) { - public ChildModel First { get; set; } - public List Children { get; set; } = new List(); - public int IdParent { get; set; } + Parent = parent; } - public class ChildModel + public int IdChild { - int _idChild; - - public ChildModel(ParentModel parent) + get => _idChild; + set { - Parent = parent; - } - - public int IdChild - { - get => _idChild; - set + if(_idChild != 0) { - if(_idChild != 0) - { - throw new Exception("Set IdChild again."); - } - _idChild = value; + throw new Exception("Set IdChild again."); } + _idChild = value; } - public ParentModel Parent { get; set; } } + public ParentModel Parent { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().ForMember(c => c.Parent, o => o.Ignore()); - cfg.CreateMap(); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().ForMember(c => c.Parent, o => o.Ignore()); + cfg.CreateMap(); + }); - [Fact] - public void Should_work() + [Fact] + public void Should_work() + { + var parentDto = new ParentDTO { IdParent = 1 }; + for(var i = 0; i < 5; i++) { - var parentDto = new ParentDTO { IdParent = 1 }; - for(var i = 0; i < 5; i++) - { - parentDto.Children.Add(new ChildDTO { IdChild = i, Parent = parentDto }); - } - - var mappedChildren = Mapper.Map, List>(parentDto.Children); + parentDto.Children.Add(new ChildDTO { IdChild = i, Parent = parentDto }); } + + var mappedChildren = Mapper.Map, List>(parentDto.Children); } +} - public class Preserve_references_with_constructor_mapping : AutoMapperSpecBase +public class Preserve_references_with_constructor_mapping : AutoMapperSpecBase +{ + public class ParentDTO { - public class ParentDTO - { - public ChildDTO First => Children[0]; - public List Children { get; set; } = new List(); - public int IdParent { get; set; } - } + public ChildDTO First => Children[0]; + public List Children { get; set; } = new List(); + public int IdParent { get; set; } + } - public class ChildDTO - { - public int IdChild { get; set; } - public ParentDTO Parent { get; set; } - } + public class ChildDTO + { + public int IdChild { get; set; } + public ParentDTO Parent { get; set; } + } + + public class ParentModel + { + public ChildModel First { get; set; } + public List Children { get; set; } = new List(); + public int IdParent { get; set; } + } + + public class ChildModel + { + int _idChild; - public class ParentModel + public ChildModel(ParentModel parent) { - public ChildModel First { get; set; } - public List Children { get; set; } = new List(); - public int IdParent { get; set; } + Parent = parent; } - public class ChildModel + public int IdChild { - int _idChild; - - public ChildModel(ParentModel parent) + get => _idChild; + set { - Parent = parent; - } - - public int IdChild - { - get => _idChild; - set + if(_idChild != 0) { - if(_idChild != 0) - { - throw new Exception("Set IdChild again."); - } - _idChild = value; + throw new Exception("Set IdChild again."); } + _idChild = value; } - public ParentModel Parent { get; set; } - } - - protected override MapperConfiguration CreateConfiguration() => new(cfg=> - { - cfg.CreateMap().PreserveReferences(); - cfg.CreateMap().ForMember(c => c.Parent, o => o.Ignore()).PreserveReferences(); - }); - - [Fact] - public void Should_work() - { - var parentDto = new ParentDTO { IdParent = 1 }; - for(var i = 0; i < 5; i++) - { - parentDto.Children.Add(new ChildDTO { IdChild = i, Parent = parentDto }); - } - - var mappedChildren = Mapper.Map, List>(parentDto.Children); - var parentModel = mappedChildren.Select(c => c.Parent).Distinct().Single(); - parentModel.First.ShouldBe(mappedChildren[0]); } + public ParentModel Parent { get; set; } } - public class When_construct_mapping_a_struct_with_string : AutoMapperSpecBase + protected override MapperConfiguration CreateConfiguration() => new(cfg=> { - public struct Source - { - public string Property { get; set; } - } + cfg.CreateMap().PreserveReferences(); + cfg.CreateMap().ForMember(c => c.Parent, o => o.Ignore()).PreserveReferences(); + }); - public struct Destination + [Fact] + public void Should_work() + { + var parentDto = new ParentDTO { IdParent = 1 }; + for(var i = 0; i < 5; i++) { - public Destination(string property) - { - Property = property; - } - - public string Property { get; set; } + parentDto.Children.Add(new ChildDTO { IdChild = i, Parent = parentDto }); } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - }); - - [Fact] - public void Should_map_ok() - { - var source = new Source { Property = "value" }; - var destination = Mapper.Map(source); - destination.Property.ShouldBe("value"); - } + var mappedChildren = Mapper.Map, List>(parentDto.Children); + var parentModel = mappedChildren.Select(c => c.Parent).Distinct().Single(); + parentModel.First.ShouldBe(mappedChildren[0]); } +} - public class When_construct_mapping_a_struct : AutoMapperSpecBase +public class When_construct_mapping_a_struct_with_string : AutoMapperSpecBase +{ + public struct Source { - public class Dto - { - public double Value { get; set; } - } + public string Property { get; set; } + } - public class Entity + public struct Destination + { + public Destination(string property) { - public double Value { get; set; } + Property = property; } - public struct Source - { - public Dto Property { get; set; } - } + public string Property { get; set; } + } - public struct Destination - { - public Destination(Entity property) - { - Property = property; - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + }); - public Entity Property { get; } - } + [Fact] + public void Should_map_ok() + { + var source = new Source { Property = "value" }; + var destination = Mapper.Map(source); + destination.Property.ShouldBe("value"); + } +} - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().ReverseMap(); - cfg.CreateMap().ReverseMap(); - }); +public class When_construct_mapping_a_struct : AutoMapperSpecBase +{ + public class Dto + { + public double Value { get; set; } + } - [Fact] - public void Should_map_ok() - { - var source = new Source - { - Property = new Dto { Value = 5.0 } - }; - var destination = Mapper.Map(source); - destination.Property.Value.ShouldBe(5.0); - Mapper.Map(destination).Property.Value.ShouldBe(5.0); - } + public class Entity + { + public double Value { get; set; } } - public class When_mapping_to_an_abstract_type : AutoMapperSpecBase + public struct Source { - class Source - { - public int Value { get; set; } - } + public Dto Property { get; set; } + } - abstract class Destination + public struct Destination + { + public Destination(Entity property) { - public int Value { get; set; } + Property = property; } - protected override MapperConfiguration CreateConfiguration() => new(c=>c.CreateMap()); - - [Fact] - public void Should_throw() - { - new Action(() => Mapper.Map(new Source())).ShouldThrow($"Cannot create an instance of abstract type {typeof(Destination)}."); - } + public Entity Property { get; } } - public class When_a_constructor_with_extra_parameters_doesnt_match : AutoMapperSpecBase + protected override MapperConfiguration CreateConfiguration() => new(cfg => { - PersonTarget _destination; + cfg.CreateMap().ReverseMap(); + cfg.CreateMap().ReverseMap(); + }); - class PersonSource + [Fact] + public void Should_map_ok() + { + var source = new Source { - public int Age { get; set; } - public string Name { get; set; } - } + Property = new Dto { Value = 5.0 } + }; + var destination = Mapper.Map(source); + destination.Property.Value.ShouldBe(5.0); + Mapper.Map(destination).Property.Value.ShouldBe(5.0); + } +} - class PersonTarget - { - public int Age { get; set; } - public string Name { get; set; } +public class When_mapping_to_an_abstract_type : AutoMapperSpecBase +{ + class Source + { + public int Value { get; set; } + } - public PersonTarget(int age, string name) - { - this.Age = age; - this.Name = name; - } + abstract class Destination + { + public int Value { get; set; } + } - public PersonTarget(int age, string firstName, string lastName) - { - this.Age = age; - this.Name = firstName + " " + lastName; - } - } + protected override MapperConfiguration CreateConfiguration() => new(c=>c.CreateMap()); - protected override MapperConfiguration CreateConfiguration() => new(c=>c.CreateMap()); + [Fact] + public void Should_throw() + { + new Action(() => Mapper.Map(new Source())).ShouldThrow($"Cannot create an instance of abstract type {typeof(Destination)}."); + } +} - protected override void Because_of() - { - _destination = Mapper.Map(new PersonSource { Age = 23, Name = "Marc" }); - } +public class When_a_constructor_with_extra_parameters_doesnt_match : AutoMapperSpecBase +{ + PersonTarget _destination; - [Fact] - public void We_should_choose_a_matching_constructor() - { - _destination.Age.ShouldBe(23); - _destination.Name.ShouldBe("Marc"); - } + class PersonSource + { + public int Age { get; set; } + public string Name { get; set; } } - public class When_renaming_class_constructor_parameter : AutoMapperSpecBase + class PersonTarget { - Destination _destination; + public int Age { get; set; } + public string Name { get; set; } - public class Source + public PersonTarget(int age, string name) { - public InnerSource InnerSource { get; set; } + this.Age = age; + this.Name = name; } - public class InnerSource + public PersonTarget(int age, string firstName, string lastName) { - public string Name { get; set; } + this.Age = age; + this.Name = firstName + " " + lastName; } + } - public class Destination - { - public Destination(InnerDestination inner) - { - InnerDestination = inner; - } + protected override MapperConfiguration CreateConfiguration() => new(c=>c.CreateMap()); - public InnerDestination InnerDestination { get; } - } + protected override void Because_of() + { + _destination = Mapper.Map(new PersonSource { Age = 23, Name = "Marc" }); + } - public class InnerDestination - { - public string Name { get; set; } - } + [Fact] + public void We_should_choose_a_matching_constructor() + { + _destination.Age.ShouldBe(23); + _destination.Name.ShouldBe("Marc"); + } +} - protected override MapperConfiguration CreateConfiguration() => new(c => - { - c.CreateMap().ForCtorParam("inner", o=>o.MapFrom(s=>s.InnerSource)); - c.CreateMap(); - }); +public class When_renaming_class_constructor_parameter : AutoMapperSpecBase +{ + Destination _destination; - protected override void Because_of() - { - _destination = Mapper.Map(new Source { InnerSource = new InnerSource { Name = "Core" } }); - } + public class Source + { + public InnerSource InnerSource { get; set; } + } - [Fact] - public void Should_map_ok() + public class InnerSource + { + public string Name { get; set; } + } + + public class Destination + { + public Destination(InnerDestination inner) { - _destination.InnerDestination.Name.ShouldBe("Core"); + InnerDestination = inner; } + + public InnerDestination InnerDestination { get; } } - public class When_constructor_matches_with_prefix_and_postfix : AutoMapperSpecBase + public class InnerDestination { - PersonDto _destination; + public string Name { get; set; } + } - public class Person - { - public string PrefixNamePostfix { get; set; } - } + protected override MapperConfiguration CreateConfiguration() => new(c => + { + c.CreateMap().ForCtorParam("inner", o=>o.MapFrom(s=>s.InnerSource)); + c.CreateMap(); + }); - public class PersonDto - { - string name; + protected override void Because_of() + { + _destination = Mapper.Map(new Source { InnerSource = new InnerSource { Name = "Core" } }); + } - public PersonDto(string name) - { - this.name = name; - } + [Fact] + public void Should_map_ok() + { + _destination.InnerDestination.Name.ShouldBe("Core"); + } +} - public string Name => name; - } +public class When_constructor_matches_with_prefix_and_postfix : AutoMapperSpecBase +{ + PersonDto _destination; - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.RecognizePostfixes("postfix"); - cfg.RecognizePrefixes("prefix"); + public class Person + { + public string PrefixNamePostfix { get; set; } + } - cfg.CreateMap(); - }); + public class PersonDto + { + string name; - protected override void Because_of() + public PersonDto(string name) { - _destination = Mapper.Map(new Person { PrefixNamePostfix = "John" }); + this.name = name; } - [Fact] - public void Should_map_from_the_property() - { - _destination.Name.ShouldBe("John"); - } + public string Name => name; } - public class When_constructor_matches_with_destination_prefix_and_postfix : AutoMapperSpecBase + protected override MapperConfiguration CreateConfiguration() => new(cfg => { - PersonDto _destination; + cfg.RecognizePostfixes("postfix"); + cfg.RecognizePrefixes("prefix"); - public class Person - { - public string Name { get; set; } - } + cfg.CreateMap(); + }); - public class PersonDto - { - string name; + protected override void Because_of() + { + _destination = Mapper.Map(new Person { PrefixNamePostfix = "John" }); + } - public PersonDto(string prefixNamePostfix) - { - name = prefixNamePostfix; - } + [Fact] + public void Should_map_from_the_property() + { + _destination.Name.ShouldBe("John"); + } +} - public string Name => name; - } +public class When_constructor_matches_with_destination_prefix_and_postfix : AutoMapperSpecBase +{ + PersonDto _destination; - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.RecognizeDestinationPostfixes("postfix"); - cfg.RecognizeDestinationPrefixes("prefix"); + public class Person + { + public string Name { get; set; } + } - cfg.CreateMap(); - }); + public class PersonDto + { + string name; - protected override void Because_of() + public PersonDto(string prefixNamePostfix) { - _destination = Mapper.Map(new Person { Name = "John" }); + name = prefixNamePostfix; } - [Fact] - public void Should_map_from_the_property() - { - _destination.Name.ShouldBe("John"); - } + public string Name => name; } - public class When_constructor_matches_but_is_overriden_by_ConstructUsing : AutoMapperSpecBase + protected override MapperConfiguration CreateConfiguration() => new(cfg => { - PersonDto _destination; + cfg.RecognizeDestinationPostfixes("postfix"); + cfg.RecognizeDestinationPrefixes("prefix"); - public class Person - { - public string Name { get; set; } - } + cfg.CreateMap(); + }); - public class PersonDto - { - public PersonDto() - { - } + protected override void Because_of() + { + _destination = Mapper.Map(new Person { Name = "John" }); + } - public PersonDto(string name) - { - Name = name; - } + [Fact] + public void Should_map_from_the_property() + { + _destination.Name.ShouldBe("John"); + } +} - public string Name { get; set; } - } +public class When_constructor_matches_but_is_overriden_by_ConstructUsing : AutoMapperSpecBase +{ + PersonDto _destination; - protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.CreateMap().ConstructUsing(p=>new PersonDto())); + public class Person + { + public string Name { get; set; } + } - protected override void Because_of() + public class PersonDto + { + public PersonDto() { - _destination = Mapper.Map(new Person { Name = "John" }); } - [Fact] - public void Should_map_from_the_property() + public PersonDto(string name) { - var typeMap = FindTypeMapFor(); - _destination.Name.ShouldBe("John"); + Name = name; } + + public string Name { get; set; } } - public class When_constructor_is_match_with_default_value : AutoMapperSpecBase - { - PersonDto _destination; + protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.CreateMap().ConstructUsing(p=>new PersonDto())); - public class Person - { - public string Name { get; set; } - } + protected override void Because_of() + { + _destination = Mapper.Map(new Person { Name = "John" }); + } - public class PersonDto - { - public PersonDto(string name = null) - { - Name = name; - } + [Fact] + public void Should_map_from_the_property() + { + var typeMap = FindTypeMapFor(); + _destination.Name.ShouldBe("John"); + } +} - public string Name { get; set; } - } +public class When_constructor_is_match_with_default_value : AutoMapperSpecBase +{ + PersonDto _destination; - protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.CreateMap()); + public class Person + { + public string Name { get; set; } + } - protected override void Because_of() + public class PersonDto + { + public PersonDto(string name = null) { - _destination = Mapper.Map(new Person { Name = "John" }); + Name = name; } - [Fact] - public void Should_map_from_the_property() - { - _destination.Name.ShouldBe("John"); - } + public string Name { get; set; } } - public class When_constructor_is_partial_match_with_value_type : AutoMapperSpecBase - { - GeoCoordinate _destination; + protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.CreateMap()); - public class GeolocationDTO - { - public double Longitude { get; set; } - public double Latitude { get; set; } - public double? HorizontalAccuracy { get; set; } - } + protected override void Because_of() + { + _destination = Mapper.Map(new Person { Name = "John" }); + } - public struct GeoCoordinate - { - public GeoCoordinate(double longitude, double latitude, double x) - { - Longitude = longitude; - Latitude = latitude; - HorizontalAccuracy = 0; - } - public double Longitude { get; set; } - public double Latitude { get; set; } - public double? HorizontalAccuracy { get; set; } - } + [Fact] + public void Should_map_from_the_property() + { + _destination.Name.ShouldBe("John"); + } +} - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - cfg.CreateMap(); - }); +public class When_constructor_is_partial_match_with_value_type : AutoMapperSpecBase +{ + GeoCoordinate _destination; - protected override void Because_of() - { - var source = new GeolocationDTO - { - Latitude = 34d, - Longitude = -93d, - HorizontalAccuracy = 100 - }; - _destination = Mapper.Map(source); - } + public class GeolocationDTO + { + public double Longitude { get; set; } + public double Latitude { get; set; } + public double? HorizontalAccuracy { get; set; } + } - [Fact] - public void Should_map_ok() + public struct GeoCoordinate + { + public GeoCoordinate(double longitude, double latitude, double x) { - _destination.Latitude.ShouldBe(34); - _destination.Longitude.ShouldBe(-93); - _destination.HorizontalAccuracy.ShouldBe(100); + Longitude = longitude; + Latitude = latitude; + HorizontalAccuracy = 0; } + public double Longitude { get; set; } + public double Latitude { get; set; } + public double? HorizontalAccuracy { get; set; } } - public class When_constructor_is_partial_match : AutoMapperSpecBase + protected override MapperConfiguration CreateConfiguration() => new(cfg => { - GeoCoordinate _destination; + cfg.CreateMap(); + cfg.CreateMap(); + }); - public class GeolocationDTO + protected override void Because_of() + { + var source = new GeolocationDTO { - public double Longitude { get; set; } - public double Latitude { get; set; } - public double? HorizontalAccuracy { get; set; } - } + Latitude = 34d, + Longitude = -93d, + HorizontalAccuracy = 100 + }; + _destination = Mapper.Map(source); + } - public class GeoCoordinate - { - public GeoCoordinate() - { - } - public GeoCoordinate(double longitude, double latitude, double x) - { - Longitude = longitude; - Latitude = latitude; - } - public double Longitude { get; set; } - public double Latitude { get; set; } - public double? HorizontalAccuracy { get; set; } - public double Altitude { get; set; } - public double VerticalAccuracy { get; set; } - public double Speed { get; set; } - public double Course { get; set; } - } + [Fact] + public void Should_map_ok() + { + _destination.Latitude.ShouldBe(34); + _destination.Longitude.ShouldBe(-93); + _destination.HorizontalAccuracy.ShouldBe(100); + } +} - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); +public class When_constructor_is_partial_match : AutoMapperSpecBase +{ + GeoCoordinate _destination; - cfg.CreateMap() - .ForMember(dest => dest.Altitude, opt => opt.Ignore()) - .ForMember(dest => dest.VerticalAccuracy, opt => opt.Ignore()) - .ForMember(dest => dest.Speed, opt => opt.Ignore()) - .ForMember(dest => dest.Course, opt => opt.Ignore()); - }); + public class GeolocationDTO + { + public double Longitude { get; set; } + public double Latitude { get; set; } + public double? HorizontalAccuracy { get; set; } + } - protected override void Because_of() + public class GeoCoordinate + { + public GeoCoordinate() { - var source = new GeolocationDTO - { - Latitude = 34d, - Longitude = -93d, - HorizontalAccuracy = 100 - }; - _destination = Mapper.Map(source); } - - [Fact] - public void Should_map_ok() + public GeoCoordinate(double longitude, double latitude, double x) { - _destination.Latitude.ShouldBe(34); - _destination.Longitude.ShouldBe(-93); - _destination.HorizontalAccuracy.ShouldBe(100); + Longitude = longitude; + Latitude = latitude; } + public double Longitude { get; set; } + public double Latitude { get; set; } + public double? HorizontalAccuracy { get; set; } + public double Altitude { get; set; } + public double VerticalAccuracy { get; set; } + public double Speed { get; set; } + public double Course { get; set; } } - public class When_constructor_matches_but_the_destination_is_passed : AutoMapperSpecBase + protected override MapperConfiguration CreateConfiguration() => new(cfg => { - Destination _destination = new Destination(); + cfg.CreateMap(); - public class Source - { - public int MyTypeId { get; set; } - } + cfg.CreateMap() + .ForMember(dest => dest.Altitude, opt => opt.Ignore()) + .ForMember(dest => dest.VerticalAccuracy, opt => opt.Ignore()) + .ForMember(dest => dest.Speed, opt => opt.Ignore()) + .ForMember(dest => dest.Course, opt => opt.Ignore()); + }); - public class MyType + protected override void Because_of() + { + var source = new GeolocationDTO { - } + Latitude = 34d, + Longitude = -93d, + HorizontalAccuracy = 100 + }; + _destination = Mapper.Map(source); + } - public class Destination - { - private MyType _myType; + [Fact] + public void Should_map_ok() + { + _destination.Latitude.ShouldBe(34); + _destination.Longitude.ShouldBe(-93); + _destination.HorizontalAccuracy.ShouldBe(100); + } +} - public Destination() - { +public class When_constructor_matches_but_the_destination_is_passed : AutoMapperSpecBase +{ + Destination _destination = new Destination(); - } - public Destination(MyType myType) - { - _myType = myType; - } + public class Source + { + public int MyTypeId { get; set; } + } - public MyType MyType - { - get { return _myType; } - set { _myType = value; } - } - } + public class MyType + { + } + + public class Destination + { + private MyType _myType; - protected override MapperConfiguration CreateConfiguration() => new(cfg => + public Destination() { - cfg.RecognizePostfixes("Id"); - cfg.CreateMap(); - cfg.CreateMap(); - }); - protected override void Because_of() + } + public Destination(MyType myType) { - Mapper.Map(new Source(), _destination); + _myType = myType; } - [Fact] - public void Should_map_ok() + public MyType MyType { - _destination.MyType.ShouldNotBeNull(); + get { return _myType; } + set { _myType = value; } } } - public class When_mapping_through_constructor_and_destination_has_setter : AutoMapperSpecBase + protected override MapperConfiguration CreateConfiguration() => new(cfg => { - public class Source - { - public int MyTypeId { get; set; } - } + cfg.RecognizePostfixes("Id"); + cfg.CreateMap(); + cfg.CreateMap(); + }); - public class MyType - { - } + protected override void Because_of() + { + Mapper.Map(new Source(), _destination); + } - Destination _destination; - public class Destination - { - private MyType _myType; + [Fact] + public void Should_map_ok() + { + _destination.MyType.ShouldNotBeNull(); + } +} - private Destination() - { +public class When_mapping_through_constructor_and_destination_has_setter : AutoMapperSpecBase +{ + public class Source + { + public int MyTypeId { get; set; } + } - } - public Destination(MyType myType) - { - _myType = myType; - } + public class MyType + { + } - public MyType MyType - { - get { return _myType; } - private set - { - throw new Exception("Should not set through setter."); - } - } - } + Destination _destination; + public class Destination + { + private MyType _myType; - protected override MapperConfiguration CreateConfiguration() => new(cfg => + private Destination() { - cfg.RecognizePostfixes("Id"); - cfg.CreateMap(); - cfg.CreateMap(); - }); - protected override void Because_of() + } + public Destination(MyType myType) { - _destination = Mapper.Map(new Source()); + _myType = myType; } - [Fact] - public void Should_map_ok() + public MyType MyType { - _destination.MyType.ShouldNotBeNull(); + get { return _myType; } + private set + { + throw new Exception("Should not set through setter."); + } } } - public class When_mapping_an_optional_GUID_constructor : AutoMapperSpecBase + protected override MapperConfiguration CreateConfiguration() => new(cfg => { - Destination _destination; - - public class Destination - { - public Destination(Guid id = default(Guid)) { Id = id; } - public Guid Id { get; set; } - } + cfg.RecognizePostfixes("Id"); + cfg.CreateMap(); + cfg.CreateMap(); + }); - public class Source - { - public Guid Id { get; set; } - } + protected override void Because_of() + { + _destination = Mapper.Map(new Source()); + } - protected override MapperConfiguration CreateConfiguration() => new(c=>c.CreateMap()); + [Fact] + public void Should_map_ok() + { + _destination.MyType.ShouldNotBeNull(); + } +} - protected override void Because_of() - { - _destination = Mapper.Map(new Source()); - } +public class When_mapping_an_optional_GUID_constructor : AutoMapperSpecBase +{ + Destination _destination; - [Fact] - public void Should_map_ok() - { - _destination.Id.ShouldBe(Guid.Empty); - } + public class Destination + { + public Destination(Guid id = default(Guid)) { Id = id; } + public Guid Id { get; set; } } - public class When_mapping_a_constructor_parameter_from_nested_members : AutoMapperSpecBase + public class Source { - private Destination _destination; - - public class Source - { - public NestedSource Nested { get; set; } - } + public Guid Id { get; set; } + } - public class NestedSource - { - public int Foo { get; set; } - } + protected override MapperConfiguration CreateConfiguration() => new(c=>c.CreateMap()); - public class Destination - { - public int Foo { get; } + protected override void Because_of() + { + _destination = Mapper.Map(new Source()); + } - public Destination(int foo) - { - Foo = foo; - } - } + [Fact] + public void Should_map_ok() + { + _destination.Id.ShouldBe(Guid.Empty); + } +} - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().ForCtorParam("foo", opt => opt.MapFrom(s => s.Nested.Foo)); - }); +public class When_mapping_a_constructor_parameter_from_nested_members : AutoMapperSpecBase +{ + private Destination _destination; - protected override void Because_of() - { - _destination = Mapper.Map(new Source { Nested = new NestedSource { Foo = 5 } }); - } + public class Source + { + public NestedSource Nested { get; set; } + } - [Fact] - public void Should_map_the_constructor_argument() - { - _destination.Foo.ShouldBe(5); - } + public class NestedSource + { + public int Foo { get; set; } } - public class When_the_destination_has_a_matching_constructor_with_optional_extra_parameters : AutoMapperSpecBase + public class Destination { - private Destination _destination; + public int Foo { get; } - public class Source + public Destination(int foo) { - public int Foo { get; set; } + Foo = foo; } + } - public class Destination - { - private readonly int _foo; + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().ForCtorParam("foo", opt => opt.MapFrom(s => s.Nested.Foo)); + }); - public int Foo - { - get { return _foo; } - } + protected override void Because_of() + { + _destination = Mapper.Map(new Source { Nested = new NestedSource { Foo = 5 } }); + } + + [Fact] + public void Should_map_the_constructor_argument() + { + _destination.Foo.ShouldBe(5); + } +} - public string Bar { get;} +public class When_the_destination_has_a_matching_constructor_with_optional_extra_parameters : AutoMapperSpecBase +{ + private Destination _destination; - public Destination(int foo, string bar = "bar") - { - _foo = foo; - Bar = bar; - } - } + public class Source + { + public int Foo { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - }); + public class Destination + { + private readonly int _foo; - protected override void Because_of() + public int Foo { - _destination = Mapper.Map(new Source { Foo = 5 }); + get { return _foo; } } - [Fact] - public void Should_map_the_constructor_argument() + public string Bar { get;} + + public Destination(int foo, string bar = "bar") { - _destination.Foo.ShouldBe(5); - _destination.Bar.ShouldBe("bar"); + _foo = foo; + Bar = bar; } } - public class When_mapping_constructor_argument_fails : NonValidatingSpecBase + protected override MapperConfiguration CreateConfiguration() => new(cfg => { - public class Source - { - public int Foo { get; set; } - public int Bar { get; set; } - } + cfg.CreateMap(); + }); - public class Dest - { - private readonly int _foo; + protected override void Because_of() + { + _destination = Mapper.Map(new Source { Foo = 5 }); + } - public int Foo - { - get { return _foo; } - } + [Fact] + public void Should_map_the_constructor_argument() + { + _destination.Foo.ShouldBe(5); + _destination.Bar.ShouldBe("bar"); + } +} - public int Bar { get; set; } +public class When_mapping_constructor_argument_fails : NonValidatingSpecBase +{ + public class Source + { + public int Foo { get; set; } + public int Bar { get; set; } + } - public Dest(Dest foo) - { - } - } + public class Dest + { + private readonly int _foo; - protected override MapperConfiguration CreateConfiguration() => new(cfg => + public int Foo { - cfg.CreateMap(); - }); + get { return _foo; } + } - [Fact] - public void Should_say_what_parameter_fails() + public int Bar { get; set; } + + public Dest(Dest foo) { - var ex = new Action(AssertConfigurationIsValid).ShouldThrow(); - ex.Message.ShouldContain("AutoMapper.UnitTests.Constructors.When_mapping_constructor_argument_fails+Dest Void .ctor(Dest), parameter foo", Case.Sensitive); } } - public class When_mapping_to_an_object_with_a_constructor_with_a_matching_argument : AutoMapperSpecBase + protected override MapperConfiguration CreateConfiguration() => new(cfg => { - private Dest _dest; + cfg.CreateMap(); + }); - public class Source - { - public int Foo { get; set; } - public int Bar { get; set; } - } + [Fact] + public void Should_say_what_parameter_fails() + { + var ex = new Action(AssertConfigurationIsValid).ShouldThrow(); + ex.Message.ShouldContain("AutoMapper.UnitTests.Constructors.When_mapping_constructor_argument_fails+Dest Void .ctor(Dest), parameter foo", Case.Sensitive); + } +} - public class Dest - { - private readonly int _foo; +public class When_mapping_to_an_object_with_a_constructor_with_a_matching_argument : AutoMapperSpecBase +{ + private Dest _dest; - public int Foo - { - get { return _foo; } - } + public class Source + { + public int Foo { get; set; } + public int Bar { get; set; } + } - public int Bar { get; set; } + public class Dest + { + private readonly int _foo; - public Dest(int foo) - { - _foo = foo; - } + public int Foo + { + get { return _foo; } } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - }); + public int Bar { get; set; } - protected override void Because_of() + public Dest(int foo) { - Expression> ctor = (input) => new Dest((int)input); + _foo = foo; + } + } - object o = ctor.Compile()(5); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + }); - _dest = Mapper.Map(new Source { Foo = 5, Bar = 10 }); - } + protected override void Because_of() + { + Expression> ctor = (input) => new Dest((int)input); - [Fact] - public void Should_map_the_constructor_argument() - { - _dest.Foo.ShouldBe(5); - } + object o = ctor.Compile()(5); - [Fact] - public void Should_map_the_existing_properties() - { - _dest.Bar.ShouldBe(10); - } + _dest = Mapper.Map(new Source { Foo = 5, Bar = 10 }); } - public class When_mapping_to_an_object_with_a_private_constructor : AutoMapperSpecBase + [Fact] + public void Should_map_the_constructor_argument() { - private Dest _dest; - - public class Source - { - public int Foo { get; set; } - } + _dest.Foo.ShouldBe(5); + } - public class Dest - { - private readonly int _foo; + [Fact] + public void Should_map_the_existing_properties() + { + _dest.Bar.ShouldBe(10); + } +} - public int Foo - { - get { return _foo; } - } +public class When_mapping_to_an_object_with_a_private_constructor : AutoMapperSpecBase +{ + private Dest _dest; - private Dest(int foo) - { - _foo = foo; - } - } + public class Source + { + public int Foo { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - }); + public class Dest + { + private readonly int _foo; - protected override void Because_of() + public int Foo { - _dest = Mapper.Map(new Source { Foo = 5 }); + get { return _foo; } } - [Fact] - public void Should_map_the_constructor_argument() + private Dest(int foo) { - _dest.Foo.ShouldBe(5); + _foo = foo; } } - public class When_mapping_to_an_object_using_service_location : AutoMapperSpecBase + protected override MapperConfiguration CreateConfiguration() => new(cfg => { - private Dest _dest; + cfg.CreateMap(); + }); - public class Source - { - public int Foo { get; set; } - } + protected override void Because_of() + { + _dest = Mapper.Map(new Source { Foo = 5 }); + } - public class Dest - { - private int _foo; - private readonly int _addend; + [Fact] + public void Should_map_the_constructor_argument() + { + _dest.Foo.ShouldBe(5); + } +} - public int Foo - { - get { return _foo + _addend; } - set { _foo = value; } - } +public class When_mapping_to_an_object_using_service_location : AutoMapperSpecBase +{ + private Dest _dest; - public Dest(int addend) - { - _addend = addend; - } + public class Source + { + public int Foo { get; set; } + } - public Dest() - : this(0) - { - } - } + public class Dest + { + private int _foo; + private readonly int _addend; - protected override MapperConfiguration CreateConfiguration() => new(cfg => + public int Foo { - cfg.ConstructServicesUsing(t => new Dest(5)); - cfg.CreateMap() - .ConstructUsingServiceLocator(); - }); + get { return _foo + _addend; } + set { _foo = value; } + } - protected override void Because_of() + public Dest(int addend) { - _dest = Mapper.Map(new Source { Foo = 5 }); + _addend = addend; } - [Fact] - public void Should_map_with_the_custom_constructor() + public Dest() + : this(0) { - _dest.Foo.ShouldBe(10); } } - public class When_mapping_to_an_object_using_contextual_service_location : AutoMapperSpecBase + protected override MapperConfiguration CreateConfiguration() => new(cfg => { - private Dest _dest; + cfg.ConstructServicesUsing(t => new Dest(5)); + cfg.CreateMap() + .ConstructUsingServiceLocator(); + }); - public class Source - { - public int Foo { get; set; } - } + protected override void Because_of() + { + _dest = Mapper.Map(new Source { Foo = 5 }); + } - public class Dest - { - private int _foo; - private readonly int _addend; + [Fact] + public void Should_map_with_the_custom_constructor() + { + _dest.Foo.ShouldBe(10); + } +} - public int Foo - { - get { return _foo + _addend; } - set { _foo = value; } - } +public class When_mapping_to_an_object_using_contextual_service_location : AutoMapperSpecBase +{ + private Dest _dest; - public Dest(int addend) - { - _addend = addend; - } + public class Source + { + public int Foo { get; set; } + } - public Dest() - : this(0) - { - } - } + public class Dest + { + private int _foo; + private readonly int _addend; - protected override MapperConfiguration CreateConfiguration() => new(cfg => + public int Foo { - cfg.ConstructServicesUsing(t => new Dest(5)); - cfg.CreateMap() - .ConstructUsingServiceLocator(); - }); + get { return _foo + _addend; } + set { _foo = value; } + } - protected override void Because_of() + public Dest(int addend) { - _dest = Mapper.Map(new Source { Foo = 5 }, opt => opt.ConstructServicesUsing(t => new Dest(6))); + _addend = addend; } - [Fact] - public void Should_map_with_the_custom_constructor() + public Dest() + : this(0) { - _dest.Foo.ShouldBe(11); } } - public class When_mapping_to_an_object_with_multiple_constructors_and_constructor_mapping_is_disabled : AutoMapperSpecBase + protected override MapperConfiguration CreateConfiguration() => new(cfg => { - private Dest _dest; + cfg.ConstructServicesUsing(t => new Dest(5)); + cfg.CreateMap() + .ConstructUsingServiceLocator(); + }); - public class Source - { - public int Foo { get; set; } - public int Bar { get; set; } - } + protected override void Because_of() + { + _dest = Mapper.Map(new Source { Foo = 5 }, opt => opt.ConstructServicesUsing(t => new Dest(6))); + } - public class Dest - { - public int Foo { get; set; } + [Fact] + public void Should_map_with_the_custom_constructor() + { + _dest.Foo.ShouldBe(11); + } +} - public int Bar { get; set; } +public class When_mapping_to_an_object_with_multiple_constructors_and_constructor_mapping_is_disabled : AutoMapperSpecBase +{ + private Dest _dest; - public Dest(int foo) - { - throw new NotImplementedException(); - } + public class Source + { + public int Foo { get; set; } + public int Bar { get; set; } + } - public Dest() { } - } + public class Dest + { + public int Foo { get; set; } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.DisableConstructorMapping(); - cfg.CreateMap(); - }); + public int Bar { get; set; } - protected override void Because_of() + public Dest(int foo) { - _dest = Mapper.Map(new Source { Foo = 5, Bar = 10 }); + throw new NotImplementedException(); } - [Fact] - public void Should_map_the_existing_properties() - { - _dest.Foo.ShouldBe(5); - _dest.Bar.ShouldBe(10); - } + public Dest() { } + } + + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.DisableConstructorMapping(); + cfg.CreateMap(); + }); + + protected override void Because_of() + { + _dest = Mapper.Map(new Source { Foo = 5, Bar = 10 }); } - public class When_mapping_with_optional_parameters_and_constructor_mapping_is_disabled : AutoMapperSpecBase + + [Fact] + public void Should_map_the_existing_properties() + { + _dest.Foo.ShouldBe(5); + _dest.Bar.ShouldBe(10); + } +} +public class When_mapping_with_optional_parameters_and_constructor_mapping_is_disabled : AutoMapperSpecBase +{ + public class Destination { - public class Destination + public Destination(Destination destination = null) { - public Destination(Destination destination = null) - { - Dest = destination; - } - public Destination Dest { get; } + Dest = destination; } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.DisableConstructorMapping(); - cfg.CreateMap(); - }); - [Fact] - public void Should_map_ok() => Mapper.Map(new object()).Dest.ShouldBeNull(); + public Destination Dest { get; } } - public class UsingMappingEngineToResolveConstructorArguments + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.DisableConstructorMapping(); + cfg.CreateMap(); + }); + [Fact] + public void Should_map_ok() => Mapper.Map(new object()).Dest.ShouldBeNull(); +} +public class UsingMappingEngineToResolveConstructorArguments +{ + [Fact] + public void Should_resolve_constructor_arguments_using_mapping_engine() { - [Fact] - public void Should_resolve_constructor_arguments_using_mapping_engine() + var config = new MapperConfiguration(cfg => { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap(); - - cfg.CreateMap(); - }); + cfg.CreateMap(); - var sourceBar = new SourceBar("fooBar"); - var sourceFoo = new SourceFoo(sourceBar); + cfg.CreateMap(); + }); - var destinationFoo = config.CreateMapper().Map(sourceFoo); + var sourceBar = new SourceBar("fooBar"); + var sourceFoo = new SourceFoo(sourceBar); - destinationFoo.Bar.FooBar.ShouldBe(sourceBar.FooBar); - } + var destinationFoo = config.CreateMapper().Map(sourceFoo); + destinationFoo.Bar.FooBar.ShouldBe(sourceBar.FooBar); + } - public class DestinationFoo - { - private readonly DestinationBar _bar; - public DestinationBar Bar - { - get { return _bar; } - } + public class DestinationFoo + { + private readonly DestinationBar _bar; - public DestinationFoo(DestinationBar bar) - { - _bar = bar; - } + public DestinationBar Bar + { + get { return _bar; } } - public class DestinationBar + public DestinationFoo(DestinationBar bar) { - private readonly string _fooBar; + _bar = bar; + } + } - public string FooBar - { - get { return _fooBar; } - } + public class DestinationBar + { + private readonly string _fooBar; - public DestinationBar(string fooBar) - { - _fooBar = fooBar; - } + public string FooBar + { + get { return _fooBar; } } - public class SourceFoo + public DestinationBar(string fooBar) { - public SourceBar Bar { get; private set; } - - public SourceFoo(SourceBar bar) - { - Bar = bar; - } + _fooBar = fooBar; } + } - public class SourceBar - { - public string FooBar { get; private set; } + public class SourceFoo + { + public SourceBar Bar { get; private set; } - public SourceBar(string fooBar) - { - FooBar = fooBar; - } + public SourceFoo(SourceBar bar) + { + Bar = bar; } } - public class MappingMultipleConstructorArguments + public class SourceBar { - [Fact] - public void Should_resolve_constructor_arguments_using_mapping_engine() - { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap(); - cfg.CreateMap(); - }); + public string FooBar { get; private set; } - var sourceBar = new SourceBar("fooBar"); - var sourceFoo = new SourceFoo(sourceBar, new SourceBar("fooBar2")); + public SourceBar(string fooBar) + { + FooBar = fooBar; + } + } +} - var destinationFoo = config.CreateMapper().Map(sourceFoo); +public class MappingMultipleConstructorArguments +{ + [Fact] + public void Should_resolve_constructor_arguments_using_mapping_engine() + { + var config = new MapperConfiguration(cfg => + { + cfg.CreateMap(); + cfg.CreateMap(); + }); - destinationFoo.Bar.FooBar.ShouldBe(sourceBar.FooBar); - destinationFoo.Bar2.FooBar.ShouldBe("fooBar2"); - } + var sourceBar = new SourceBar("fooBar"); + var sourceFoo = new SourceFoo(sourceBar, new SourceBar("fooBar2")); + var destinationFoo = config.CreateMapper().Map(sourceFoo); - public class DestinationFoo - { - private readonly DestinationBar _bar; + destinationFoo.Bar.FooBar.ShouldBe(sourceBar.FooBar); + destinationFoo.Bar2.FooBar.ShouldBe("fooBar2"); + } - public DestinationBar Bar - { - get { return _bar; } - } - public DestinationBar Bar2 { get; private set; } + public class DestinationFoo + { + private readonly DestinationBar _bar; - public DestinationFoo(DestinationBar bar, DestinationBar bar2) - { - _bar = bar; - Bar2 = bar2; - } + public DestinationBar Bar + { + get { return _bar; } } - public class DestinationBar + public DestinationBar Bar2 { get; private set; } + + public DestinationFoo(DestinationBar bar, DestinationBar bar2) { - private readonly string _fooBar; + _bar = bar; + Bar2 = bar2; + } + } - public string FooBar - { - get { return _fooBar; } - } + public class DestinationBar + { + private readonly string _fooBar; - public DestinationBar(string fooBar) - { - _fooBar = fooBar; - } + public string FooBar + { + get { return _fooBar; } } - public class SourceFoo + public DestinationBar(string fooBar) { - public SourceBar Bar { get; private set; } - public SourceBar Bar2 { get; private set; } - - public SourceFoo(SourceBar bar, SourceBar bar2) - { - Bar = bar; - Bar2 = bar2; - } + _fooBar = fooBar; } + } - public class SourceBar - { - public string FooBar { get; private set; } + public class SourceFoo + { + public SourceBar Bar { get; private set; } + public SourceBar Bar2 { get; private set; } - public SourceBar(string fooBar) - { - FooBar = fooBar; - } + public SourceFoo(SourceBar bar, SourceBar bar2) + { + Bar = bar; + Bar2 = bar2; } } - public class When_mapping_to_an_object_with_a_constructor_with_multiple_optional_arguments + public class SourceBar { - [Fact] - public void Should_resolve_constructor_when_args_are_optional() + public string FooBar { get; private set; } + + public SourceBar(string fooBar) { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap(); - cfg.CreateMap(); - }); + FooBar = fooBar; + } + } +} - var sourceBar = new SourceBar("fooBar"); - var sourceFoo = new SourceFoo(sourceBar); +public class When_mapping_to_an_object_with_a_constructor_with_multiple_optional_arguments +{ + [Fact] + public void Should_resolve_constructor_when_args_are_optional() + { + var config = new MapperConfiguration(cfg => + { + cfg.CreateMap(); + cfg.CreateMap(); + }); - var destinationFoo = config.CreateMapper().Map(sourceFoo); + var sourceBar = new SourceBar("fooBar"); + var sourceFoo = new SourceFoo(sourceBar); - destinationFoo.Bar.FooBar.ShouldBe("fooBar"); - destinationFoo.Str.ShouldBe("hello"); - } + var destinationFoo = config.CreateMapper().Map(sourceFoo); + destinationFoo.Bar.FooBar.ShouldBe("fooBar"); + destinationFoo.Str.ShouldBe("hello"); + } - public class DestinationFoo - { - private readonly DestinationBar _bar; - private string _str; - public DestinationBar Bar - { - get { return _bar; } - } + public class DestinationFoo + { + private readonly DestinationBar _bar; + private string _str; - public string Str - { - get { return _str; } - } + public DestinationBar Bar + { + get { return _bar; } + } - public DestinationFoo(DestinationBar bar=null,string str="hello") - { - _bar = bar; - _str = str; - } + public string Str + { + get { return _str; } } - public class DestinationBar + public DestinationFoo(DestinationBar bar=null,string str="hello") { - private readonly string _fooBar; + _bar = bar; + _str = str; + } + } - public string FooBar - { - get { return _fooBar; } - } + public class DestinationBar + { + private readonly string _fooBar; - public DestinationBar(string fooBar) - { - _fooBar = fooBar; - } + public string FooBar + { + get { return _fooBar; } } - public class SourceFoo + public DestinationBar(string fooBar) { - public SourceBar Bar { get; private set; } - - public SourceFoo(SourceBar bar) - { - Bar = bar; - } + _fooBar = fooBar; } + } - public class SourceBar + public class SourceFoo + { + public SourceBar Bar { get; private set; } + + public SourceFoo(SourceBar bar) { - public string FooBar { get; private set; } + Bar = bar; + } + } - public SourceBar(string fooBar) - { - FooBar = fooBar; - } + public class SourceBar + { + public string FooBar { get; private set; } + + public SourceBar(string fooBar) + { + FooBar = fooBar; } } +} - public class When_mapping_to_an_object_with_a_constructor_with_single_optional_arguments +public class When_mapping_to_an_object_with_a_constructor_with_single_optional_arguments +{ + [Fact] + public void Should_resolve_constructor_when_arg_is_optional() { - [Fact] - public void Should_resolve_constructor_when_arg_is_optional() + var config = new MapperConfiguration(cfg => { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap(); - cfg.CreateMap(); - }); - - var sourceBar = new SourceBar("fooBar"); - var sourceFoo = new SourceFoo(sourceBar); + cfg.CreateMap(); + cfg.CreateMap(); + }); - var destinationFoo = config.CreateMapper().Map(sourceFoo); + var sourceBar = new SourceBar("fooBar"); + var sourceFoo = new SourceFoo(sourceBar); - destinationFoo.Bar.FooBar.ShouldBe("fooBar"); - } + var destinationFoo = config.CreateMapper().Map(sourceFoo); + destinationFoo.Bar.FooBar.ShouldBe("fooBar"); + } - public class DestinationFoo - { - private readonly DestinationBar _bar; - public DestinationBar Bar - { - get { return _bar; } - } + public class DestinationFoo + { + private readonly DestinationBar _bar; - public DestinationFoo(DestinationBar bar = null) - { - _bar = bar; - } + public DestinationBar Bar + { + get { return _bar; } } - public class DestinationBar + public DestinationFoo(DestinationBar bar = null) { - private readonly string _fooBar; + _bar = bar; + } + } - public string FooBar - { - get { return _fooBar; } - } + public class DestinationBar + { + private readonly string _fooBar; - public DestinationBar(string fooBar) - { - _fooBar = fooBar; - } + public string FooBar + { + get { return _fooBar; } } - public class SourceFoo + public DestinationBar(string fooBar) { - public SourceBar Bar { get; private set; } - - public SourceFoo(SourceBar bar) - { - Bar = bar; - } + _fooBar = fooBar; } + } - public class SourceBar - { - public string FooBar { get; private set; } + public class SourceFoo + { + public SourceBar Bar { get; private set; } - public SourceBar(string fooBar) - { - FooBar = fooBar; - } + public SourceFoo(SourceBar bar) + { + Bar = bar; } } - public class When_mapping_to_an_object_with_a_constructor_with_string_optional_arguments + public class SourceBar { - [Fact] - public void Should_resolve_constructor_when_string_args_are_optional() + public string FooBar { get; private set; } + + public SourceBar(string fooBar) { - var config = new MapperConfiguration(cfg => cfg.CreateMap()); + FooBar = fooBar; + } + } +} - var sourceBar = new SourceBar("fooBar"); - var sourceFoo = new SourceFoo(sourceBar); +public class When_mapping_to_an_object_with_a_constructor_with_string_optional_arguments +{ + [Fact] + public void Should_resolve_constructor_when_string_args_are_optional() + { + var config = new MapperConfiguration(cfg => cfg.CreateMap()); - var destinationFoo = config.CreateMapper().Map(sourceFoo); + var sourceBar = new SourceBar("fooBar"); + var sourceFoo = new SourceFoo(sourceBar); - destinationFoo.A.ShouldBe("a"); - destinationFoo.B.ShouldBe("b"); - destinationFoo.C.ShouldBe(3); - } + var destinationFoo = config.CreateMapper().Map(sourceFoo); + + destinationFoo.A.ShouldBe("a"); + destinationFoo.B.ShouldBe("b"); + destinationFoo.C.ShouldBe(3); + } - public class DestinationFoo + public class DestinationFoo + { + private string _a; + private string _b; + private int _c; + public string A { - private string _a; - private string _b; - private int _c; - public string A - { - get { return _a; } - } - - public string B - { - get { return _b; } - } + get { return _a; } + } - public int C - { - get { return _c; } - } + public string B + { + get { return _b; } + } - public DestinationFoo(string a = "a",string b="b", int c = 3) - { - _a = a; - _b = b; - _c = c; - } + public int C + { + get { return _c; } } - public class DestinationBar + public DestinationFoo(string a = "a",string b="b", int c = 3) { - private readonly string _fooBar; + _a = a; + _b = b; + _c = c; + } + } - public string FooBar - { - get { return _fooBar; } - } + public class DestinationBar + { + private readonly string _fooBar; - public DestinationBar(string fooBar) - { - _fooBar = fooBar; - } + public string FooBar + { + get { return _fooBar; } } - public class SourceFoo + public DestinationBar(string fooBar) { - public SourceBar Bar { get; private set; } - - public SourceFoo(SourceBar bar) - { - Bar = bar; - } + _fooBar = fooBar; } + } - public class SourceBar - { - public string FooBar { get; private set; } + public class SourceFoo + { + public SourceBar Bar { get; private set; } - public SourceBar(string fooBar) - { - FooBar = fooBar; - } + public SourceFoo(SourceBar bar) + { + Bar = bar; } } - public class When_configuring_ctor_param_members : AutoMapperSpecBase + public class SourceBar { - public class Source + public string FooBar { get; private set; } + + public SourceBar(string fooBar) { - public int Value { get; set; } + FooBar = fooBar; } + } +} - public class Dest - { - public Dest(int thing) - { - Value1 = thing; - } +public class When_configuring_ctor_param_members : AutoMapperSpecBase +{ + public class Source + { + public int Value { get; set; } + } - public int Value1 { get; } + public class Dest + { + public Dest(int thing) + { + Value1 = thing; } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().ForCtorParam("thing", opt => opt.MapFrom(src => src.Value)); - }); + public int Value1 { get; } + } - [Fact] - public void Should_redirect_value() - { - var dest = Mapper.Map(new Source {Value = 5}); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().ForCtorParam("thing", opt => opt.MapFrom(src => src.Value)); + }); - dest.Value1.ShouldBe(5); - } + [Fact] + public void Should_redirect_value() + { + var dest = Mapper.Map(new Source {Value = 5}); + + dest.Value1.ShouldBe(5); + } +} + +public class When_configuring_nullable_ctor_param_members : AutoMapperSpecBase +{ + public class Source + { + public int? Value { get; set; } } - public class When_configuring_nullable_ctor_param_members : AutoMapperSpecBase + public class Dest { - public class Source + public Dest(int? thing) { - public int? Value { get; set; } + Value1 = thing; } - public class Dest - { - public Dest(int? thing) - { - Value1 = thing; - } + public int? Value1 { get; } + } - public int? Value1 { get; } - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().ForCtorParam("thing", opt => opt.MapFrom(src => src.Value)); + }); - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().ForCtorParam("thing", opt => opt.MapFrom(src => src.Value)); - }); + [Fact] + public void Should_redirect_value() + { + var dest = Mapper.Map(new Source()); - [Fact] - public void Should_redirect_value() - { - var dest = Mapper.Map(new Source()); + dest.Value1.ShouldBeNull(); + } +} - dest.Value1.ShouldBeNull(); +public class When_configuring_ctor_param_members_without_source_property_1 : AutoMapperSpecBase +{ + public class Source + { + public string Result { get; } + + public Source(string result) + { + Result = result; } } - public class When_configuring_ctor_param_members_without_source_property_1 : AutoMapperSpecBase + public class Dest { - public class Source + public string Result{ get; } + public dynamic Details { get; } + + public Dest(string result, DestInner1 inner1) + { + Result = result; + Details = inner1; + } + public Dest(string result, DestInner2 inner2) + { + Result = result; + Details = inner2; + } + + public class DestInner1 { - public string Result { get; } + public int Value { get; } - public Source(string result) + public DestInner1(int value) { - Result = result; + Value = value; } } - public class Dest + public class DestInner2 { - public string Result{ get; } - public dynamic Details { get; } + public int Value { get; } - public Dest(string result, DestInner1 inner1) - { - Result = result; - Details = inner1; - } - public Dest(string result, DestInner2 inner2) + public DestInner2(int value) { - Result = result; - Details = inner2; + Value = value; } + } + } - public class DestInner1 - { - public int Value { get; } - - public DestInner1(int value) - { - Value = value; - } - } + protected override MapperConfiguration CreateConfiguration() => new(config => + { + config.CreateMap() + .ForCtorParam("inner1", cfg => cfg.MapFrom(_ => new Dest.DestInner1(100))); + }); - public class DestInner2 - { - public int Value { get; } + [Fact] + public void Should_redirect_value() + { + var dest = Mapper.Map(new Source("Success")); - public DestInner2(int value) - { - Value = value; - } - } - } + dest.ShouldNotBeNull(); + Assert.Equal("100", dest.Details.Value.ToString()); + } +} - protected override MapperConfiguration CreateConfiguration() => new(config => - { - config.CreateMap() - .ForCtorParam("inner1", cfg => cfg.MapFrom(_ => new Dest.DestInner1(100))); - }); +public class When_configuring_ctor_param_members_without_source_property_2 : AutoMapperSpecBase +{ + public class Source + { + public string Result { get; } - [Fact] - public void Should_redirect_value() + public Source(string result) { - var dest = Mapper.Map(new Source("Success")); - - dest.ShouldNotBeNull(); - Assert.Equal("100", dest.Details.Value.ToString()); + Result = result; } } - public class When_configuring_ctor_param_members_without_source_property_2 : AutoMapperSpecBase + public class Dest { - public class Source - { - public string Result { get; } + public string Result{ get; } + public dynamic Details { get; } - public Source(string result) - { - Result = result; - } + public Dest(string result, DestInner1 inner1) + { + Result = result; + Details = inner1; + } + public Dest(string result, DestInner2 inner2) + { + Result = result; + Details = inner2; } - public class Dest + public class DestInner1 { - public string Result{ get; } - public dynamic Details { get; } + public int Value { get; } - public Dest(string result, DestInner1 inner1) - { - Result = result; - Details = inner1; - } - public Dest(string result, DestInner2 inner2) + public DestInner1(int value) { - Result = result; - Details = inner2; + Value = value; } + } - public class DestInner1 - { - public int Value { get; } - - public DestInner1(int value) - { - Value = value; - } - } + public class DestInner2 + { + public int Value { get; } - public class DestInner2 + public DestInner2(int value) { - public int Value { get; } - - public DestInner2(int value) - { - Value = value; - } + Value = value; } } + } - protected override MapperConfiguration CreateConfiguration() => new(config => - { - config.CreateMap() - .ForCtorParam("inner2", cfg => cfg.MapFrom(_ => new Dest.DestInner2(100))); - }); + protected override MapperConfiguration CreateConfiguration() => new(config => + { + config.CreateMap() + .ForCtorParam("inner2", cfg => cfg.MapFrom(_ => new Dest.DestInner2(100))); + }); - [Fact] - public void Should_redirect_value() - { - var dest = Mapper.Map(new Source("Success")); + [Fact] + public void Should_redirect_value() + { + var dest = Mapper.Map(new Source("Success")); - dest.ShouldNotBeNull(); - Assert.Equal("100", dest.Details.Value.ToString()); - } + dest.ShouldNotBeNull(); + Assert.Equal("100", dest.Details.Value.ToString()); } - } + diff --git a/src/UnitTests/CustomCollectionTester.cs b/src/UnitTests/CustomCollectionTester.cs index e556f34db3..0bb162567b 100644 --- a/src/UnitTests/CustomCollectionTester.cs +++ b/src/UnitTests/CustomCollectionTester.cs @@ -2,24 +2,23 @@ using System.Collections.Generic; using Xunit; -namespace AutoMapper.UnitTests { - public class CustomCollectionTester { - [Fact] - public void Should_be_able_to_handle_custom_dictionary_with_custom_methods() { - var config = new MapperConfiguration(cfg => cfg.CreateMap()); - var mapper = config.CreateMapper(); - } - - public class BaseClassWithDictionary { - public DataDictionary Data { get; set; } - } +namespace AutoMapper.UnitTests; +public class CustomCollectionTester { + [Fact] + public void Should_be_able_to_handle_custom_dictionary_with_custom_methods() { + var config = new MapperConfiguration(cfg => cfg.CreateMap()); + var mapper = config.CreateMapper(); + } + + public class BaseClassWithDictionary { + public DataDictionary Data { get; set; } + } - public class DerivedClassWithDictionary : BaseClassWithDictionary { } + public class DerivedClassWithDictionary : BaseClassWithDictionary { } - public class DataDictionary : Dictionary { - public string GetString(string name, string @default) { - return null; - } + public class DataDictionary : Dictionary { + public string GetString(string name, string @default) { + return null; } } } \ No newline at end of file diff --git a/src/UnitTests/CustomMapping.cs b/src/UnitTests/CustomMapping.cs index 198aa3c3d3..9f72d33ae7 100644 --- a/src/UnitTests/CustomMapping.cs +++ b/src/UnitTests/CustomMapping.cs @@ -5,1702 +5,1701 @@ using Shouldly; using Xunit; -namespace AutoMapper.UnitTests +namespace AutoMapper.UnitTests; + +public class When_implementing_multiple_IValueResolver_interfaces : AutoMapperSpecBase { - public class When_implementing_multiple_IValueResolver_interfaces : AutoMapperSpecBase - { - public class Source1 { } + public class Source1 { } - public class Source2 { } + public class Source2 { } - public class Destination - { - public string Value { get; set; } - } + public class Destination + { + public string Value { get; set; } + } - public class MyTestResolver : IValueResolver, IValueResolver + public class MyTestResolver : IValueResolver, IValueResolver + { + public string Resolve(Source1 source, Destination destination, string destMember, ResolutionContext context) { - public string Resolve(Source1 source, Destination destination, string destMember, ResolutionContext context) - { - return "source1"; - } - - public string Resolve(Source2 source, Destination destination, string destMember, ResolutionContext context) - { - return "source2"; - } + return "source1"; } - protected override MapperConfiguration CreateConfiguration() => new(cfg => + public string Resolve(Source2 source, Destination destination, string destMember, ResolutionContext context) { - cfg.CreateMap().ForMember(dest => dest.Value, opt => opt.MapFrom()); - cfg.CreateMap().ForMember(dest => dest.Value, opt => opt.MapFrom()); - }); - - [Fact] - public void Should_map_ok() - { - Mapper.Map(new Source1()).Value.ShouldBe("source1"); - Mapper.Map(new Source2()).Value.ShouldBe("source2"); + return "source2"; } } - public class When_using_IMemberResolver_derived_interface : AutoMapperSpecBase + protected override MapperConfiguration CreateConfiguration() => new(cfg => { - Destination _destination; + cfg.CreateMap().ForMember(dest => dest.Value, opt => opt.MapFrom()); + cfg.CreateMap().ForMember(dest => dest.Value, opt => opt.MapFrom()); + }); - class Source - { - public string SValue { get; set; } - } + [Fact] + public void Should_map_ok() + { + Mapper.Map(new Source1()).Value.ShouldBe("source1"); + Mapper.Map(new Source2()).Value.ShouldBe("source2"); + } +} - class Destination - { - public string Value { get; set; } - } +public class When_using_IMemberResolver_derived_interface : AutoMapperSpecBase +{ + Destination _destination; - interface IResolver : IMemberValueResolver - { - } + class Source + { + public string SValue { get; set; } + } - class Resolver : IResolver - { - public string Resolve(Source source, Destination destination, string sourceMember, string destMember, ResolutionContext context) - { - return "Resolved"; - } - } + class Destination + { + public string Value { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().ForMember(d => d.Value, o => o.MapFrom(new Resolver(), s=>s.SValue)); - }); + interface IResolver : IMemberValueResolver + { + } - protected override void Because_of() + class Resolver : IResolver + { + public string Resolve(Source source, Destination destination, string sourceMember, string destMember, ResolutionContext context) { - _destination = Mapper.Map(new Source()); + return "Resolved"; } + } - [Fact] - public void Should_map_ok() - { - _destination.Value.ShouldBe("Resolved"); - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().ForMember(d => d.Value, o => o.MapFrom(new Resolver(), s=>s.SValue)); + }); + + protected override void Because_of() + { + _destination = Mapper.Map(new Source()); } - public class OpenGenericMapForMember : AutoMapperSpecBase + [Fact] + public void Should_map_ok() { - ModelPager _destination; - int[] _items = Enumerable.Range(1, 10).ToArray(); + _destination.Value.ShouldBe("Resolved"); + } +} - public interface IPager : IEnumerable - { - int CurrentPage { get; set; } +public class OpenGenericMapForMember : AutoMapperSpecBase +{ + ModelPager _destination; + int[] _items = Enumerable.Range(1, 10).ToArray(); - int PageCount { get; set; } + public interface IPager : IEnumerable + { + int CurrentPage { get; set; } - int PageSize { get; set; } + int PageCount { get; set; } - int TotalItems { get; set; } - } - public class ModelPager - { - public int CurrentPage { get; set; } + int PageSize { get; set; } - public IEnumerable Items { get; set; } + int TotalItems { get; set; } + } + public class ModelPager + { + public int CurrentPage { get; set; } - public int PageCount { get; set; } + public IEnumerable Items { get; set; } - public int PageSize { get; set; } + public int PageCount { get; set; } - public int TotalItems { get; set; } + public int PageSize { get; set; } + + public int TotalItems { get; set; } + } + public class Pager : IPager + { + private readonly IEnumerable _items; + + public Pager(IEnumerable items) :this(items, 0, 0, 0) + { } - public class Pager : IPager + public Pager(IEnumerable items, + int currentPage, + int pageSize, + int totalItems) { - private readonly IEnumerable _items; - - public Pager(IEnumerable items) :this(items, 0, 0, 0) - { - } - public Pager(IEnumerable items, - int currentPage, - int pageSize, - int totalItems) - { - _items = items ?? Enumerable.Empty(); - CurrentPage = currentPage; - PageSize = pageSize; - TotalItems = totalItems; - } + _items = items ?? Enumerable.Empty(); + CurrentPage = currentPage; + PageSize = pageSize; + TotalItems = totalItems; + } - public int CurrentPage { get; set; } + public int CurrentPage { get; set; } - public int PageCount { get; set; } + public int PageCount { get; set; } - public int PageSize { get; set; } + public int PageSize { get; set; } - public int TotalItems { get; set; } + public int TotalItems { get; set; } - IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } + IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } - public IEnumerator GetEnumerator() { return _items.GetEnumerator(); } - } - - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(typeof(IPager<>), typeof(ModelPager<>)).ForMember("Items", e => e.MapFrom(o => (IEnumerable)o)); - }); + public IEnumerator GetEnumerator() { return _items.GetEnumerator(); } + } - protected override void Because_of() - { - _destination = Mapper.Map>(new Pager(_items)); - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(typeof(IPager<>), typeof(ModelPager<>)).ForMember("Items", e => e.MapFrom(o => (IEnumerable)o)); + }); - [Fact] - public void Should_map_ok() - { - _destination.Items.SequenceEqual(_items).ShouldBeTrue(); - } + protected override void Because_of() + { + _destination = Mapper.Map>(new Pager(_items)); } - public class IntToNullableIntConverter : AutoMapperSpecBase + [Fact] + public void Should_map_ok() { - Destination _destination; + _destination.Items.SequenceEqual(_items).ShouldBeTrue(); + } +} + +public class IntToNullableIntConverter : AutoMapperSpecBase +{ + Destination _destination; - public class IntToNullableConverter : ITypeConverter + public class IntToNullableConverter : ITypeConverter + { + public int? Convert(int source, int? destination, ResolutionContext context) { - public int? Convert(int source, int? destination, ResolutionContext context) + if(source == default(int)) { - if(source == default(int)) - { - return null; - } - return source; + return null; } + return source; } + } - public class Source - { - public int Id { get; set; } - } + public class Source + { + public int Id { get; set; } + } - public class Destination - { - public int? Id { get; set; } - } + public class Destination + { + public int? Id { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().ConvertUsing(); - cfg.CreateMap(); - }); - - protected override void Because_of() - { - _destination = Mapper.Map(new Source()); - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().ConvertUsing(); + cfg.CreateMap(); + }); + + protected override void Because_of() + { + _destination = Mapper.Map(new Source()); + } - [Fact] - public void Should_use_the_converter() - { - _destination.Id.ShouldBeNull(); - } + [Fact] + public void Should_use_the_converter() + { + _destination.Id.ShouldBeNull(); } +} - public class When_throwing_NRE_from_MapFrom_value_types : AutoMapperSpecBase +public class When_throwing_NRE_from_MapFrom_value_types : AutoMapperSpecBase +{ + ViewModel _viewModel; + + public class Model { - ViewModel _viewModel; + public List SubModels { get; set; } + } - public class Model - { - public List SubModels { get; set; } - } + public class SubModel + { + public List SubSubModels { get; set; } + } - public class SubModel - { - public List SubSubModels { get; set; } - } + public class SubSubModel + { + public int Id { get; set; } + } - public class SubSubModel - { - public int Id { get; set; } - } + public class ViewModel + { + public int SubModelId { get; set; } + } - public class ViewModel - { - public int SubModelId { get; set; } - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .ForMember(x => x.SubModelId, + opts => opts.MapFrom(src => src.SubModels.FirstOrDefault().SubSubModels.FirstOrDefault().Id)); + }); - protected override MapperConfiguration CreateConfiguration() => new(cfg => + protected override void Because_of() + { + var model = new Model { - cfg.CreateMap() - .ForMember(x => x.SubModelId, - opts => opts.MapFrom(src => src.SubModels.FirstOrDefault().SubSubModels.FirstOrDefault().Id)); - }); + SubModels = new List() + }; + _viewModel = Mapper.Map(model); + } - protected override void Because_of() - { - var model = new Model - { - SubModels = new List() - }; - _viewModel = Mapper.Map(model); - } + [Fact] + public void Should_map_ok() + { + _viewModel.SubModelId.ShouldBe(0); + } +} - [Fact] - public void Should_map_ok() - { - _viewModel.SubModelId.ShouldBe(0); - } +public class When_throwing_NRE_from_MapFrom : AutoMapperSpecBase +{ + class Source + { } - public class When_throwing_NRE_from_MapFrom : AutoMapperSpecBase + class Destination { - class Source - { - } + public string Value { get; set; } + } - class Destination - { - public string Value { get; set; } - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + string x = null; + cfg.CreateMap().ForMember(d=>d.Value, o=>o.MapFrom(s=>x.ToString())); + }); - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - string x = null; - cfg.CreateMap().ForMember(d=>d.Value, o=>o.MapFrom(s=>x.ToString())); - }); + [Fact] + public void We_should_catch_it() + { + Mapper.Map(new Source()).Value.ShouldBeNull(); + } +} - [Fact] - public void We_should_catch_it() - { - Mapper.Map(new Source()).Value.ShouldBeNull(); - } +public class When_using_value_with_mismatched_properties : AutoMapperSpecBase +{ + Destination _destination; + static Guid _guid = Guid.NewGuid(); + + class Source + { + public int Value { get; set; } } - public class When_using_value_with_mismatched_properties : AutoMapperSpecBase + class Destination { - Destination _destination; - static Guid _guid = Guid.NewGuid(); + public Guid Value { get; set; } + } - class Source - { - public int Value { get; set; } - } + protected override MapperConfiguration CreateConfiguration() => new(c => c.CreateMap().ForMember(d => d.Value, o => o.MapFrom(src => _guid))); - class Destination - { - public Guid Value { get; set; } - } + protected override void Because_of() + { + _destination = Mapper.Map(new Source()); + } - protected override MapperConfiguration CreateConfiguration() => new(c => c.CreateMap().ForMember(d => d.Value, o => o.MapFrom(src => _guid))); + [Fact] + public void Should_map_ok() + { + _destination.Value.ShouldBe(_guid); + } +} - protected override void Because_of() - { - _destination = Mapper.Map(new Source()); - } +public class When_custom_resolving_mismatched_properties : AutoMapperSpecBase +{ + Destination _destination; + static Guid _guid = Guid.NewGuid(); - [Fact] - public void Should_map_ok() - { - _destination.Value.ShouldBe(_guid); - } + class Source + { + public int Value { get; set; } } - public class When_custom_resolving_mismatched_properties : AutoMapperSpecBase + class Destination { - Destination _destination; - static Guid _guid = Guid.NewGuid(); + public Guid Value { get; set; } + } - class Source - { - public int Value { get; set; } - } + protected override MapperConfiguration CreateConfiguration() => new(c => c.CreateMap().ForMember(d => d.Value, o => o.MapFrom())); - class Destination + class Resolver : IValueResolver + { + public Guid Resolve(Source model, Destination d, Guid dest, ResolutionContext context) { - public Guid Value { get; set; } + return _guid; } + } - protected override MapperConfiguration CreateConfiguration() => new(c => c.CreateMap().ForMember(d => d.Value, o => o.MapFrom())); + protected override void Because_of() + { + _destination = Mapper.Map(new Source()); + } - class Resolver : IValueResolver - { - public Guid Resolve(Source model, Destination d, Guid dest, ResolutionContext context) - { - return _guid; - } - } + [Fact] + public void Should_map_ok() + { + _destination.Value.ShouldBe(_guid); + } +} - protected override void Because_of() - { - _destination = Mapper.Map(new Source()); - } +public class When_resolve_throws : NonValidatingSpecBase +{ + Exception _ex = new Exception(); - [Fact] - public void Should_map_ok() - { - _destination.Value.ShouldBe(_guid); - } + class Source + { } - public class When_resolve_throws : NonValidatingSpecBase + class Destination { - Exception _ex = new Exception(); + public int Value { get; set; } + } - class Source - { - } + protected override MapperConfiguration CreateConfiguration() => new(c => c.CreateMap().ForMember(d => d.Value, o => o.MapFrom((s, d) => { Throw(); return 0; }))); + private void Throw() + { + throw _ex; + } - class Destination - { - public int Value { get; set; } - } + [Fact] + public void Should_propagate_exception() + { + new Action(()=>Mapper.Map(new Source())).ShouldThrowException(e=>e.InnerException.ShouldBe(_ex)); + } +} - protected override MapperConfiguration CreateConfiguration() => new(c => c.CreateMap().ForMember(d => d.Value, o => o.MapFrom((s, d) => { Throw(); return 0; }))); - private void Throw() - { - throw _ex; - } +public class When_mapping_different_types_with_explicit_value : AutoMapperSpecBase +{ + Destination _destination; - [Fact] - public void Should_propagate_exception() - { - new Action(()=>Mapper.Map(new Source())).ShouldThrowException(e=>e.InnerException.ShouldBe(_ex)); - } + class InnerSource + { + public int IntValue { get; set; } } - public class When_mapping_different_types_with_explicit_value : AutoMapperSpecBase + class InnerDestination { - Destination _destination; + public int IntValue { get; set; } + } - class InnerSource - { - public int IntValue { get; set; } - } + class Source + { + } - class InnerDestination - { - public int IntValue { get; set; } - } + class Destination + { + public InnerDestination Value { get; set; } + } - class Source - { - } + protected override MapperConfiguration CreateConfiguration() => new(c => + { + c.CreateMap(); + c.CreateMap().ForMember(d => d.Value, o => o.MapFrom(src => new InnerSource { IntValue = 15 })); + }); - class Destination - { - public InnerDestination Value { get; set; } - } + protected override void Because_of() + { + _destination = Mapper.Map(new Source()); + } - protected override MapperConfiguration CreateConfiguration() => new(c => - { - c.CreateMap(); - c.CreateMap().ForMember(d => d.Value, o => o.MapFrom(src => new InnerSource { IntValue = 15 })); - }); + [Fact] + public void Should_work() + { + _destination.Value.IntValue.ShouldBe(15); + } +} - protected override void Because_of() - { - _destination = Mapper.Map(new Source()); - } +public class When_mapping_different_types_with_ResolveUsing : AutoMapperSpecBase +{ + Destination _destination; - [Fact] - public void Should_work() - { - _destination.Value.IntValue.ShouldBe(15); - } + class InnerSource + { + public int IntValue { get; set; } } - public class When_mapping_different_types_with_ResolveUsing : AutoMapperSpecBase + class InnerDestination { - Destination _destination; + public int IntValue { get; set; } + } - class InnerSource - { - public int IntValue { get; set; } - } + class Source + { + public InnerSource ObjectValue { get; set; } + } - class InnerDestination - { - public int IntValue { get; set; } - } + class Destination + { + public InnerDestination Value { get; set; } + } - class Source - { - public InnerSource ObjectValue { get; set; } - } + protected override MapperConfiguration CreateConfiguration() => new(c => + { + c.CreateMap(); + c.CreateMap().ForMember(d => d.Value, o => o.MapFrom(s => s.ObjectValue)); + }); - class Destination - { - public InnerDestination Value { get; set; } - } + protected override void Because_of() + { + _destination = Mapper.Map(new Source { ObjectValue = new InnerSource { IntValue = 15 } }); + } - protected override MapperConfiguration CreateConfiguration() => new(c => - { - c.CreateMap(); - c.CreateMap().ForMember(d => d.Value, o => o.MapFrom(s => s.ObjectValue)); - }); + [Fact] + public void Should_work() + { + _destination.Value.IntValue.ShouldBe(15); + } +} - protected override void Because_of() - { - _destination = Mapper.Map(new Source { ObjectValue = new InnerSource { IntValue = 15 } }); - } +public class When_mapping_from_object_to_string_with_use_value : AutoMapperSpecBase +{ + Destination _destination; - [Fact] - public void Should_work() - { - _destination.Value.IntValue.ShouldBe(15); - } + class Source + { } - public class When_mapping_from_object_to_string_with_use_value : AutoMapperSpecBase + class Destination { - Destination _destination; + public string Value { get; set; } + } - class Source - { - } + protected override MapperConfiguration CreateConfiguration() => + new(c => c.CreateMap().ForMember(d => d.Value, o => o.MapFrom(src => new object()))); - class Destination - { - public string Value { get; set; } - } + protected override void Because_of() + { + _destination = Mapper.Map(new Source { }); + } - protected override MapperConfiguration CreateConfiguration() => - new(c => c.CreateMap().ForMember(d => d.Value, o => o.MapFrom(src => new object()))); + [Fact] + public void Should_use_to_string() + { + _destination.Value.ShouldBe("System.Object"); + } +} - protected override void Because_of() - { - _destination = Mapper.Map(new Source { }); - } +public class When_mapping_from_object_to_string : AutoMapperSpecBase +{ + Destination _destination; - [Fact] - public void Should_use_to_string() - { - _destination.Value.ShouldBe("System.Object"); - } + class Source + { + public object ObjectValue { get; set; } } - public class When_mapping_from_object_to_string : AutoMapperSpecBase + class Destination { - Destination _destination; + public string Value { get; set; } + } - class Source - { - public object ObjectValue { get; set; } - } + protected override MapperConfiguration CreateConfiguration() => + new(c => c.CreateMap().ForMember(d=>d.Value, o=>o.MapFrom(s=>s.ObjectValue))); - class Destination - { - public string Value { get; set; } - } + protected override void Because_of() + { + _destination = Mapper.Map(new Source { ObjectValue = new object() }); + } - protected override MapperConfiguration CreateConfiguration() => - new(c => c.CreateMap().ForMember(d=>d.Value, o=>o.MapFrom(s=>s.ObjectValue))); + [Fact] + public void Should_use_to_string() + { + _destination.Value.ShouldBe("System.Object"); + } +} - protected override void Because_of() - { - _destination = Mapper.Map(new Source { ObjectValue = new object() }); - } +public class When_mapping_to_a_dto_member_with_custom_mapping : AutoMapperSpecBase +{ + private ModelDto _result; - [Fact] - public void Should_use_to_string() - { - _destination.Value.ShouldBe("System.Object"); - } + public class ModelObject + { + public int Value { get; set; } + public int Value2fff { get; set; } + public int Value3 { get; set; } + public int Value4 { get; set; } + public int Value5 { get; set; } } - public class When_mapping_to_a_dto_member_with_custom_mapping : AutoMapperSpecBase + public class ModelDto { - private ModelDto _result; + public int Value { get; set; } + public int Value2 { get; set; } + public int Value3 { get; set; } + public int Value4 { get; set; } + public int Value5 { get; set; } + } - public class ModelObject + public class CustomResolver : IValueResolver + { + public int Resolve(ModelObject source, ModelDto d, int dest, ResolutionContext context) { - public int Value { get; set; } - public int Value2fff { get; set; } - public int Value3 { get; set; } - public int Value4 { get; set; } - public int Value5 { get; set; } + return source.Value + 1; } + } - public class ModelDto + public class CustomResolver2 : IValueResolver + { + public int Resolve(ModelObject source, ModelDto d, int dest, ResolutionContext context) { - public int Value { get; set; } - public int Value2 { get; set; } - public int Value3 { get; set; } - public int Value4 { get; set; } - public int Value5 { get; set; } + return source.Value2fff + 2; } + } - public class CustomResolver : IValueResolver - { - public int Resolve(ModelObject source, ModelDto d, int dest, ResolutionContext context) - { - return source.Value + 1; - } - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .ForMember(dto => dto.Value, opt => opt.MapFrom()) + .ForMember(dto => dto.Value2, opt => opt.MapFrom(new CustomResolver2())) + .ForMember(dto => dto.Value5, opt => opt.MapFrom(src => src.Value5 + 5)); - public class CustomResolver2 : IValueResolver - { - public int Resolve(ModelObject source, ModelDto d, int dest, ResolutionContext context) - { - return source.Value2fff + 2; - } - } + }); - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ForMember(dto => dto.Value, opt => opt.MapFrom()) - .ForMember(dto => dto.Value2, opt => opt.MapFrom(new CustomResolver2())) - .ForMember(dto => dto.Value5, opt => opt.MapFrom(src => src.Value5 + 5)); + protected override void Because_of() + { + var model = new ModelObject {Value = 42, Value2fff = 42, Value3 = 42, Value4 = 42, Value5 = 42}; + _result = Mapper.Map(model); + } - }); + [Fact] + public void Should_ignore_the_mapping_for_normal_members() + { + _result.Value3.ShouldBe(42); + } - protected override void Because_of() - { - var model = new ModelObject {Value = 42, Value2fff = 42, Value3 = 42, Value4 = 42, Value5 = 42}; - _result = Mapper.Map(model); - } + [Fact] + public void Should_use_the_custom_generic_mapping_for_custom_dto_members() + { + _result.Value.ShouldBe(43); + } - [Fact] - public void Should_ignore_the_mapping_for_normal_members() - { - _result.Value3.ShouldBe(42); - } + [Fact] + public void Should_use_the_instance_based_mapping_for_custom_dto_members() + { + _result.Value2.ShouldBe(44); + } - [Fact] - public void Should_use_the_custom_generic_mapping_for_custom_dto_members() - { - _result.Value.ShouldBe(43); - } + [Fact] + public void Should_use_the_func_based_mapping_for_custom_dto_members() + { + _result.Value5.ShouldBe(47); + } +} - [Fact] - public void Should_use_the_instance_based_mapping_for_custom_dto_members() - { - _result.Value2.ShouldBe(44); - } +public class When_using_a_custom_resolver_for_a_child_model_property_instead_of_the_model : AutoMapperSpecBase +{ + private ModelDto _result; - [Fact] - public void Should_use_the_func_based_mapping_for_custom_dto_members() - { - _result.Value5.ShouldBe(47); - } + public class ModelObject + { + public ModelSubObject Sub { get; set; } } - public class When_using_a_custom_resolver_for_a_child_model_property_instead_of_the_model : AutoMapperSpecBase + public class ModelSubObject { - private ModelDto _result; + public int SomeValue { get; set; } + } - public class ModelObject - { - public ModelSubObject Sub { get; set; } - } + public class ModelDto + { + public int SomeValue { get; set; } + } - public class ModelSubObject + public class CustomResolver : IMemberValueResolver + { + public int Resolve(object s, object d, ModelSubObject source, int ignored, ResolutionContext context) { - public int SomeValue { get; set; } + return source.SomeValue + 1; } + } - public class ModelDto - { - public int SomeValue { get; set; } - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .ForMember(dto => dto.SomeValue, opt => opt.MapFrom(m => m.Sub)); + }); - public class CustomResolver : IMemberValueResolver + [Fact] + public void Should_use_the_specified_model_member_to_resolve_from() + { + var model = new ModelObject { - public int Resolve(object s, object d, ModelSubObject source, int ignored, ResolutionContext context) + Sub = new ModelSubObject { - return source.SomeValue + 1; + SomeValue = 46 } - } + }; - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ForMember(dto => dto.SomeValue, opt => opt.MapFrom(m => m.Sub)); - }); + _result = Mapper.Map(model); + _result.SomeValue.ShouldBe(47); + } +} - [Fact] - public void Should_use_the_specified_model_member_to_resolve_from() - { - var model = new ModelObject - { - Sub = new ModelSubObject - { - SomeValue = 46 - } - }; +public class When_reseting_a_mapping_to_use_a_resolver_to_a_different_member : AutoMapperSpecBase +{ + private Dest _result; - _result = Mapper.Map(model); - _result.SomeValue.ShouldBe(47); - } + public class Source + { + public int SomeValue { get; set; } + public int SomeOtherValue { get; set; } } - public class When_reseting_a_mapping_to_use_a_resolver_to_a_different_member : AutoMapperSpecBase + public class Dest { - private Dest _result; + public int SomeValue { get; set; } + } - public class Source + public class CustomResolver : IMemberValueResolver + { + public int Resolve(object s, object d, int source, int dest, ResolutionContext context) { - public int SomeValue { get; set; } - public int SomeOtherValue { get; set; } + return source + 5; } + } - public class Dest - { - public int SomeValue { get; set; } - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .ForMember(dto => dto.SomeValue, + opt => opt.MapFrom(m => m.SomeOtherValue)); - public class CustomResolver : IMemberValueResolver - { - public int Resolve(object s, object d, int source, int dest, ResolutionContext context) - { - return source + 5; - } - } + }); - protected override MapperConfiguration CreateConfiguration() => new(cfg => + protected override void Because_of() + { + var model = new Source { - cfg.CreateMap() - .ForMember(dto => dto.SomeValue, - opt => opt.MapFrom(m => m.SomeOtherValue)); + SomeValue = 36, + SomeOtherValue = 53 + }; - }); + _result = Mapper.Map(model); + } - protected override void Because_of() - { - var model = new Source - { - SomeValue = 36, - SomeOtherValue = 53 - }; + [Fact] + public void Should_override_the_existing_match_to_the_new_custom_resolved_member() + { + _result.SomeValue.ShouldBe(58); + } +} - _result = Mapper.Map(model); - } +public class When_reseting_a_mapping_from_a_property_to_a_method : AutoMapperSpecBase +{ + private Dest _result; - [Fact] - public void Should_override_the_existing_match_to_the_new_custom_resolved_member() - { - _result.SomeValue.ShouldBe(58); - } + public class Source + { + public int Type { get; set; } } - public class When_reseting_a_mapping_from_a_property_to_a_method : AutoMapperSpecBase + public class Dest { - private Dest _result; + public int Type { get; set; } + } - public class Source - { - public int Type { get; set; } - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .ForMember(dto => dto.Type, opt => opt.MapFrom(m => m.Type)); - public class Dest - { - public int Type { get; set; } - } + }); - protected override MapperConfiguration CreateConfiguration() => new(cfg => + protected override void Because_of() + { + var model = new Source { - cfg.CreateMap() - .ForMember(dto => dto.Type, opt => opt.MapFrom(m => m.Type)); + Type = 5 + }; - }); + _result = Mapper.Map(model); + } - protected override void Because_of() - { - var model = new Source - { - Type = 5 - }; + [Fact] + public void Should_override_the_existing_match_to_the_new_custom_resolved_member() + { + _result.Type.ShouldBe(5); + } +} - _result = Mapper.Map(model); - } +public class When_specifying_a_custom_constructor_and_member_resolver : AutoMapperSpecBase +{ + private Source _source; + private Destination _dest; - [Fact] - public void Should_override_the_existing_match_to_the_new_custom_resolved_member() - { - _result.Type.ShouldBe(5); - } + public class Source + { + public int Value { get; set; } + } + + public class Destination + { + public int Value { get; set; } } - public class When_specifying_a_custom_constructor_and_member_resolver : AutoMapperSpecBase + public class CustomResolver : IMemberValueResolver { - private Source _source; - private Destination _dest; + private readonly int _toAdd; - public class Source + public CustomResolver(int toAdd) { - public int Value { get; set; } + _toAdd = toAdd; } - public class Destination + public CustomResolver() { - public int Value { get; set; } + _toAdd = 10; } - public class CustomResolver : IMemberValueResolver + public int Resolve(object s, object d, int source, int dest, ResolutionContext context) { - private readonly int _toAdd; + return source + _toAdd; + } + } - public CustomResolver(int toAdd) - { - _toAdd = toAdd; - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .ForMember(s => s.Value, + opt => opt.MapFrom(new CustomResolver(15), src => src.Value)); - public CustomResolver() - { - _toAdd = 10; - } + }); - public int Resolve(object s, object d, int source, int dest, ResolutionContext context) - { - return source + _toAdd; - } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => + protected override void Because_of() + { + _source = new Source { - cfg.CreateMap() - .ForMember(s => s.Value, - opt => opt.MapFrom(new CustomResolver(15), src => src.Value)); + Value = 10 + }; + _dest = Mapper.Map(_source); + } - }); + [Fact] + public void Should_use_the_custom_constructor() + { + _dest.Value.ShouldBe(25); + } +} +public class When_specifying_a_member_resolver_and_custom_constructor : AutoMapperSpecBase +{ + private Source _source; + private Destination _dest; - protected override void Because_of() - { - _source = new Source - { - Value = 10 - }; - _dest = Mapper.Map(_source); - } + public class Source + { + public int Value { get; set; } + } - [Fact] - public void Should_use_the_custom_constructor() - { - _dest.Value.ShouldBe(25); - } + public class Destination + { + public int Value { get; set; } } - public class When_specifying_a_member_resolver_and_custom_constructor : AutoMapperSpecBase + public class CustomResolver : IMemberValueResolver { - private Source _source; - private Destination _dest; + private readonly int _toAdd; - public class Source + public CustomResolver(int toAdd) { - public int Value { get; set; } + _toAdd = toAdd; } - public class Destination + public CustomResolver() { - public int Value { get; set; } + _toAdd = 10; } - public class CustomResolver : IMemberValueResolver + public int Resolve(object s, object d, int source, int dest, ResolutionContext context) { - private readonly int _toAdd; + return source + _toAdd; + } + } - public CustomResolver(int toAdd) - { - _toAdd = toAdd; - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .ForMember(s => s.Value, + opt => opt.MapFrom(new CustomResolver(15), s => s.Value) + ); - public CustomResolver() - { - _toAdd = 10; - } + }); - public int Resolve(object s, object d, int source, int dest, ResolutionContext context) + protected override void Because_of() + { + _source = new Source { - return source + _toAdd; - } - } - - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ForMember(s => s.Value, - opt => opt.MapFrom(new CustomResolver(15), s => s.Value) - ); + Value = 10 + }; + _dest = Mapper.Map(_source); + } - }); + [Fact] + public void Should_use_the_custom_constructor() + { + _dest.Value.ShouldBe(25); + } +} - protected override void Because_of() - { - _source = new Source - { - Value = 10 - }; - _dest = Mapper.Map(_source); - } +public class When_specifying_a_custom_translator +{ + private Source _source; + private Destination _dest; - [Fact] - public void Should_use_the_custom_constructor() - { - _dest.Value.ShouldBe(25); - } + public class Source + { + public int Value { get; set; } + public int AnotherValue { get; set; } } - public class When_specifying_a_custom_translator + public class Destination { - private Source _source; - private Destination _dest; + public int Value { get; set; } + } - public class Source + public When_specifying_a_custom_translator() + { + _source = new Source { - public int Value { get; set; } - public int AnotherValue { get; set; } - } + Value = 10, + AnotherValue = 1000 + }; + } - public class Destination - { - public int Value { get; set; } - } + [Fact] + public void Should_use_the_custom_translator() + { + var config = new MapperConfiguration(cfg => cfg.CreateMap() + .ConvertUsing(s => new Destination { Value = s.Value + 10 })); - public When_specifying_a_custom_translator() - { - _source = new Source - { - Value = 10, - AnotherValue = 1000 - }; - } + _dest = config.CreateMapper().Map(_source); + _dest.Value.ShouldBe(20); + } - [Fact] - public void Should_use_the_custom_translator() - { - var config = new MapperConfiguration(cfg => cfg.CreateMap() - .ConvertUsing(s => new Destination { Value = s.Value + 10 })); + [Fact] + public void Should_ignore_other_mapping_rules() + { + var config = new MapperConfiguration(cfg => cfg.CreateMap() + .ForMember(dest => dest.Value, opt => opt.MapFrom(src => src.AnotherValue)) + .ConvertUsing(s => new Destination { Value = s.Value + 10 })); - _dest = config.CreateMapper().Map(_source); - _dest.Value.ShouldBe(20); - } + _dest = config.CreateMapper().Map(_source); + _dest.Value.ShouldBe(20); + } +} - [Fact] - public void Should_ignore_other_mapping_rules() - { - var config = new MapperConfiguration(cfg => cfg.CreateMap() - .ForMember(dest => dest.Value, opt => opt.MapFrom(src => src.AnotherValue)) - .ConvertUsing(s => new Destination { Value = s.Value + 10 })); +public class When_specifying_a_custom_translator_using_projection +{ + private Source _source; + private Destination _dest; - _dest = config.CreateMapper().Map(_source); - _dest.Value.ShouldBe(20); - } + public class Source + { + public int Value { get; set; } + public int AnotherValue { get; set; } } - public class When_specifying_a_custom_translator_using_projection + public class Destination { - private Source _source; - private Destination _dest; + public int Value { get; set; } + } - public class Source + public When_specifying_a_custom_translator_using_projection() + { + _source = new Source { - public int Value { get; set; } - public int AnotherValue { get; set; } - } + Value = 10, + AnotherValue = 1000 + }; + } - public class Destination - { - public int Value { get; set; } - } + [Fact] + public void Should_use_the_custom_translator() + { + var config = new MapperConfiguration(cfg => cfg.CreateMap() + .ConvertUsing(s => new Destination { Value = s.Value + 10 })); - public When_specifying_a_custom_translator_using_projection() - { - _source = new Source - { - Value = 10, - AnotherValue = 1000 - }; - } + _dest = config.CreateMapper().Map(_source); + _dest.Value.ShouldBe(20); + } - [Fact] - public void Should_use_the_custom_translator() - { - var config = new MapperConfiguration(cfg => cfg.CreateMap() - .ConvertUsing(s => new Destination { Value = s.Value + 10 })); + [Fact] + public void Should_ignore_other_mapping_rules() + { + var config = new MapperConfiguration(cfg => cfg.CreateMap() + .ForMember(dest => dest.Value, opt => opt.MapFrom(src => src.AnotherValue)) + .ConvertUsing(s => new Destination { Value = s.Value + 10 })); - _dest = config.CreateMapper().Map(_source); - _dest.Value.ShouldBe(20); - } + _dest = config.CreateMapper().Map(_source); + _dest.Value.ShouldBe(20); + } +} - [Fact] - public void Should_ignore_other_mapping_rules() - { - var config = new MapperConfiguration(cfg => cfg.CreateMap() - .ForMember(dest => dest.Value, opt => opt.MapFrom(src => src.AnotherValue)) - .ConvertUsing(s => new Destination { Value = s.Value + 10 })); +public class When_specifying_a_custom_translator_and_passing_in_the_destination_object +{ + private Source _source; + private Destination _dest; - _dest = config.CreateMapper().Map(_source); - _dest.Value.ShouldBe(20); - } + public class Source + { + public int Value { get; set; } + public int AnotherValue { get; set; } } - public class When_specifying_a_custom_translator_and_passing_in_the_destination_object + public class Destination { - private Source _source; - private Destination _dest; + public int Value { get; set; } + } - public class Source + public When_specifying_a_custom_translator_and_passing_in_the_destination_object() + { + _source = new Source { - public int Value { get; set; } - public int AnotherValue { get; set; } - } + Value = 10, + AnotherValue = 1000 + }; - public class Destination - { - public int Value { get; set; } - } + _dest = new Destination + { + Value = 2 + }; + } - public When_specifying_a_custom_translator_and_passing_in_the_destination_object() - { - _source = new Source - { - Value = 10, - AnotherValue = 1000 - }; + [Fact] + public void Should_resolve_to_the_destination_object_from_the_custom_translator() + { + var config = new MapperConfiguration(cfg => cfg.CreateMap() + .ConvertUsing(s => new Destination { Value = s.Value + 10 })); - _dest = new Destination - { - Value = 2 - }; - } + _dest = config.CreateMapper().Map(_source, _dest); + _dest.Value.ShouldBe(20); + } - [Fact] - public void Should_resolve_to_the_destination_object_from_the_custom_translator() - { - var config = new MapperConfiguration(cfg => cfg.CreateMap() - .ConvertUsing(s => new Destination { Value = s.Value + 10 })); + [Fact] + public void Should_ignore_other_mapping_rules() + { + var config = new MapperConfiguration(cfg => cfg.CreateMap() + .ForMember(dest => dest.Value, opt => opt.MapFrom(src => src.AnotherValue)) + .ConvertUsing(s => new Destination { Value = s.Value + 10 })); - _dest = config.CreateMapper().Map(_source, _dest); - _dest.Value.ShouldBe(20); - } + _dest = config.CreateMapper().Map(_source, _dest); + _dest.Value.ShouldBe(20); + } +} - [Fact] - public void Should_ignore_other_mapping_rules() - { - var config = new MapperConfiguration(cfg => cfg.CreateMap() - .ForMember(dest => dest.Value, opt => opt.MapFrom(src => src.AnotherValue)) - .ConvertUsing(s => new Destination { Value = s.Value + 10 })); +public class When_specifying_a_custom_translator_using_generics +{ + private Source _source; + private Destination _dest; - _dest = config.CreateMapper().Map(_source, _dest); - _dest.Value.ShouldBe(20); - } + public class Source + { + public int Value { get; set; } + public int AnotherValue { get; set; } } - public class When_specifying_a_custom_translator_using_generics + public class Destination { - private Source _source; - private Destination _dest; + public int Value { get; set; } + } - public class Source + public When_specifying_a_custom_translator_using_generics() + { + _source = new Source { - public int Value { get; set; } - public int AnotherValue { get; set; } - } + Value = 10, + AnotherValue = 1000 + }; + } - public class Destination + public class Converter : ITypeConverter + { + public Destination Convert(Source source, Destination destination, ResolutionContext context) { - public int Value { get; set; } + return new Destination { Value = source.Value + 10 }; } + } - public When_specifying_a_custom_translator_using_generics() - { - _source = new Source - { - Value = 10, - AnotherValue = 1000 - }; - } + [Fact] + public void Should_use_the_custom_translator() + { + var config = new MapperConfiguration(cfg => cfg.CreateMap() + .ConvertUsing()); - public class Converter : ITypeConverter - { - public Destination Convert(Source source, Destination destination, ResolutionContext context) - { - return new Destination { Value = source.Value + 10 }; - } - } + _dest = config.CreateMapper().Map(_source); + _dest.Value.ShouldBe(20); + } - [Fact] - public void Should_use_the_custom_translator() - { - var config = new MapperConfiguration(cfg => cfg.CreateMap() - .ConvertUsing()); + [Fact] + public void Should_ignore_other_mapping_rules() + { + var config = new MapperConfiguration(cfg => cfg.CreateMap() + .ForMember(dest => dest.Value, opt => opt.MapFrom(src => src.AnotherValue)) + .ConvertUsing(s => new Destination { Value = s.Value + 10 })); - _dest = config.CreateMapper().Map(_source); - _dest.Value.ShouldBe(20); - } + _dest = config.CreateMapper().Map(_source); + _dest.Value.ShouldBe(20); + } +} - [Fact] - public void Should_ignore_other_mapping_rules() - { - var config = new MapperConfiguration(cfg => cfg.CreateMap() - .ForMember(dest => dest.Value, opt => opt.MapFrom(src => src.AnotherValue)) - .ConvertUsing(s => new Destination { Value = s.Value + 10 })); +public class When_specifying_a_custom_constructor_function_for_custom_converters : AutoMapperSpecBase +{ + private Destination _result; - _dest = config.CreateMapper().Map(_source); - _dest.Value.ShouldBe(20); - } + public class Source + { + public int Value { get; set; } + } + + public class Destination + { + public int Value { get; set; } } - public class When_specifying_a_custom_constructor_function_for_custom_converters : AutoMapperSpecBase + public class CustomConverter : ITypeConverter { - private Destination _result; + private readonly int _value; - public class Source + public CustomConverter() + : this(5) { - public int Value { get; set; } } - public class Destination + public CustomConverter(int value) { - public int Value { get; set; } + _value = value; } - public class CustomConverter : ITypeConverter + public Destination Convert(Source source, Destination destination, ResolutionContext context) { - private readonly int _value; + return new Destination { Value = source.Value + _value }; + } + } - public CustomConverter() - : this(5) - { - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.ConstructServicesUsing(t => new CustomConverter(10)); + cfg.CreateMap() + .ConvertUsing(); + }); - public CustomConverter(int value) - { - _value = value; - } + protected override void Because_of() + { + _result = Mapper.Map(new Source { Value = 5 }); + } - public Destination Convert(Source source, Destination destination, ResolutionContext context) - { - return new Destination { Value = source.Value + _value }; - } - } + [Fact] + public void Should_use_the_custom_constructor_function() + { + _result.Value.ShouldBe(15); + } +} - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.ConstructServicesUsing(t => new CustomConverter(10)); - cfg.CreateMap() - .ConvertUsing(); - }); - protected override void Because_of() - { - _result = Mapper.Map(new Source { Value = 5 }); - } +public class When_specifying_a_custom_translator_with_mismatched_properties : AutoMapperSpecBase +{ + public class Source + { + public int Value1 { get; set; } + public int AnotherValue { get; set; } + } - [Fact] - public void Should_use_the_custom_constructor_function() - { - _result.Value.ShouldBe(15); - } + public class Destination + { + public int Value2 { get; set; } } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .ConvertUsing(s => new Destination {Value2 = s.Value1 + 10}); + }); - public class When_specifying_a_custom_translator_with_mismatched_properties : AutoMapperSpecBase + [Fact] + public void Should_pass_all_configuration_checks() { - public class Source + Exception thrown = null; + try { - public int Value1 { get; set; } - public int AnotherValue { get; set; } - } + AssertConfigurationIsValid(); - public class Destination + } + catch (Exception ex) { - public int Value2 { get; set; } + thrown = ex; } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ConvertUsing(s => new Destination {Value2 = s.Value1 + 10}); - }); + thrown.ShouldBeNull(); + } +} - [Fact] - public void Should_pass_all_configuration_checks() - { - Exception thrown = null; - try - { - AssertConfigurationIsValid(); +public class When_configuring_a_global_constructor_function_for_resolvers : AutoMapperSpecBase +{ + private Destination _result; - } - catch (Exception ex) - { - thrown = ex; - } + public class Source + { + public int Value { get; set; } + } - thrown.ShouldBeNull(); - } + public class Destination + { + public int Value { get; set; } } - public class When_configuring_a_global_constructor_function_for_resolvers : AutoMapperSpecBase + public class CustomValueResolver : IMemberValueResolver { - private Destination _result; + private readonly int _toAdd; + public CustomValueResolver() { _toAdd = 11; } - public class Source + public CustomValueResolver(int toAdd) { - public int Value { get; set; } + _toAdd = toAdd; } - public class Destination + public int Resolve(object s, object d, int source, int dest, ResolutionContext context) { - public int Value { get; set; } + return source + _toAdd; } + } - public class CustomValueResolver : IMemberValueResolver - { - private readonly int _toAdd; - public CustomValueResolver() { _toAdd = 11; } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.ConstructServicesUsing(type => new CustomValueResolver(5)); - public CustomValueResolver(int toAdd) - { - _toAdd = toAdd; - } + cfg.CreateMap() + .ForMember(d => d.Value, opt => opt.MapFrom(src => src.Value)); + }); - public int Resolve(object s, object d, int source, int dest, ResolutionContext context) - { - return source + _toAdd; - } - } + protected override void Because_of() + { + _result = Mapper.Map(new Source { Value = 5 }); + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.ConstructServicesUsing(type => new CustomValueResolver(5)); + [Fact] + public void Should_use_the_specified_constructor() + { + _result.Value.ShouldBe(10); + } +} - cfg.CreateMap() - .ForMember(d => d.Value, opt => opt.MapFrom(src => src.Value)); - }); - protected override void Because_of() - { - _result = Mapper.Map(new Source { Value = 5 }); - } +public class When_custom_resolver_requests_property_to_be_ignored : AutoMapperSpecBase +{ + private Destination _result = new Destination() { Value = 55 }; - [Fact] - public void Should_use_the_specified_constructor() - { - _result.Value.ShouldBe(10); - } + public class Source + { + public int Value { get; set; } } - - public class When_custom_resolver_requests_property_to_be_ignored : AutoMapperSpecBase + public class Destination { - private Destination _result = new Destination() { Value = 55 }; + public int Value { get; set; } + } - public class Source + public class CustomValueResolver : IMemberValueResolver + { + public int Resolve(object s, object d, int source, int dest, ResolutionContext context) { - public int Value { get; set; } + return dest; } + } - public class Destination - { - public int Value { get; set; } - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .ForMember(d => d.Value, opt => opt.MapFrom(src => src.Value)); + }); - public class CustomValueResolver : IMemberValueResolver - { - public int Resolve(object s, object d, int source, int dest, ResolutionContext context) - { - return dest; - } - } + protected override void Because_of() + { + _result = Mapper.Map(new Source { Value = 5 }, _result); + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ForMember(d => d.Value, opt => opt.MapFrom(src => src.Value)); - }); + [Fact] + public void Should_not_overwrite_destination_value() + { + _result.Value.ShouldBe(55); + } +} - protected override void Because_of() - { - _result = Mapper.Map(new Source { Value = 5 }, _result); - } +public class When_using_inheritance_with_value_resoluvers : AutoMapperSpecBase +{ + public class SourceDto + { + public int Id { get; set; } + public string NumberValue { get; set; } + } - [Fact] - public void Should_not_overwrite_destination_value() - { - _result.Value.ShouldBe(55); - } + public class SourceChildDto : SourceDto + { + public string ChildField { get; set; } } - public class When_using_inheritance_with_value_resoluvers : AutoMapperSpecBase + public class DestinationDto { - public class SourceDto - { - public int Id { get; set; } - public string NumberValue { get; set; } - } + public int Ident { get; set; } + public int Number { get; set; } + } - public class SourceChildDto : SourceDto - { - public string ChildField { get; set; } - } + public class DestinationChildDto : DestinationDto + { + public string ChildField { get; set; } + } - public class DestinationDto + public class CustomResolver : IMemberValueResolver + { + public int Resolve(SourceDto src, object dest, string source, int member, ResolutionContext context) { - public int Ident { get; set; } - public int Number { get; set; } + return int.Parse(source); } + } - public class DestinationChildDto : DestinationDto + protected override MapperConfiguration CreateConfiguration() => new(cfg => { + cfg.CreateMap() + .ForMember(dest => dest.Ident, opt => opt.MapFrom(x => x.Id)) + .ForMember(dest => dest.Number, opt => opt.MapFrom(src => src.NumberValue)) + ; + cfg.CreateMap() + .IncludeBase() + ; + }); + + [Fact] + public void Should_inherit_value_resolver() + { + var sourceChild = new SourceChildDto { - public string ChildField { get; set; } - } + Id = 1, + NumberValue = "13", + ChildField = "alpha" + }; - public class CustomResolver : IMemberValueResolver - { - public int Resolve(SourceDto src, object dest, string source, int member, ResolutionContext context) - { - return int.Parse(source); - } - } + // destination = { Ident: 1, Number: 0 /* should be 13 */, ChildField: "alpha" } + var destination = Mapper.Map(sourceChild); + destination.Number.ShouldBe(13); + } +} - protected override MapperConfiguration CreateConfiguration() => new(cfg => { - cfg.CreateMap() - .ForMember(dest => dest.Ident, opt => opt.MapFrom(x => x.Id)) - .ForMember(dest => dest.Number, opt => opt.MapFrom(src => src.NumberValue)) - ; - cfg.CreateMap() - .IncludeBase() - ; - }); - [Fact] - public void Should_inherit_value_resolver() - { - var sourceChild = new SourceChildDto - { - Id = 1, - NumberValue = "13", - ChildField = "alpha" - }; +public class When_specifying_member_and_member_resolver_using_string_property_names : AutoMapperSpecBase +{ + private Destination _result; - // destination = { Ident: 1, Number: 0 /* should be 13 */, ChildField: "alpha" } - var destination = Mapper.Map(sourceChild); - destination.Number.ShouldBe(13); - } + public class Source + { + public int SourceValue { get; set; } } - - public class When_specifying_member_and_member_resolver_using_string_property_names : AutoMapperSpecBase + public class Destination { - private Destination _result; + public int DestinationValue { get; set; } + } - public class Source + public class CustomValueResolver : IMemberValueResolver + { + public CustomValueResolver() { - public int SourceValue { get; set; } } - public class Destination + public object Resolve(object s, object d, int source, object dest, ResolutionContext context) { - public int DestinationValue { get; set; } + return source + 5; } + } - public class CustomValueResolver : IMemberValueResolver - { - public CustomValueResolver() - { - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.ConstructServicesUsing(type => new CustomValueResolver()); - public object Resolve(object s, object d, int source, object dest, ResolutionContext context) - { - return source + 5; - } - } + cfg.CreateMap() + .ForMember("DestinationValue", + opt => opt.MapFrom("SourceValue")); + }); - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.ConstructServicesUsing(type => new CustomValueResolver()); + protected override void Because_of() + { + _result = Mapper.Map(new Source { SourceValue = 5 }); + } - cfg.CreateMap() - .ForMember("DestinationValue", - opt => opt.MapFrom("SourceValue")); - }); + [Fact] + public void Should_translate_the_property() + { + _result.DestinationValue.ShouldBe(10); + } +} - protected override void Because_of() - { - _result = Mapper.Map(new Source { SourceValue = 5 }); - } +public class When_specifying_a_custom_member_mapping_to_a_nested_object +{ + public class Source + { + public int Value { get; set; } + } - [Fact] - public void Should_translate_the_property() - { - _result.DestinationValue.ShouldBe(10); - } + public class Destination + { + public SubDest Dest { get; set; } } - public class When_specifying_a_custom_member_mapping_to_a_nested_object + public class SubDest { - public class Source - { - public int Value { get; set; } - } + public int Value { get; set; } + } - public class Destination + [Fact] + public void Should_fail_with_an_exception_during_configuration() + { + typeof(ArgumentException).ShouldBeThrownBy(() => { - public SubDest Dest { get; set; } - } + var config = new MapperConfiguration(cfg => cfg.CreateMap() + .ForMember(dest => dest.Dest.Value, opt => opt.MapFrom(src => src.Value))); + }); + } +} - public class SubDest - { - public int Value { get; set; } - } +public class When_specifying_a_custom_member_mapping_with_a_cast : NonValidatingSpecBase +{ + private Source _source; + private Destination _dest; - [Fact] - public void Should_fail_with_an_exception_during_configuration() - { - typeof(ArgumentException).ShouldBeThrownBy(() => - { - var config = new MapperConfiguration(cfg => cfg.CreateMap() - .ForMember(dest => dest.Dest.Value, opt => opt.MapFrom(src => src.Value))); - }); - } + public class Source + { + public string MyName { get; set; } } - public class When_specifying_a_custom_member_mapping_with_a_cast : NonValidatingSpecBase + public class Destination : ISomeInterface { - private Source _source; - private Destination _dest; + public string Name { get; set; } + } - public class Source - { - public string MyName { get; set; } - } + public interface ISomeInterface + { + string Name { get; set; } + } - public class Destination : ISomeInterface - { - public string Name { get; set; } - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .ForMember(dest => ((ISomeInterface) dest).Name, opt => opt.MapFrom(src => src.MyName)); - public interface ISomeInterface - { - string Name { get; set; } - } + }); - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ForMember(dest => ((ISomeInterface) dest).Name, opt => opt.MapFrom(src => src.MyName)); + protected override void Because_of() + { + _source = new Source {MyName = "jon"}; + _dest = Mapper.Map(_source); + } - }); + [Fact] + public void Should_perform_the_translation() + { + _dest.Name.ShouldBe("jon"); + } +} - protected override void Because_of() - { - _source = new Source {MyName = "jon"}; - _dest = Mapper.Map(_source); - } +public class When_destination_property_does_not_have_a_setter : AutoMapperSpecBase +{ + private Source _source; + private Destination _dest; - [Fact] - public void Should_perform_the_translation() - { - _dest.Name.ShouldBe("jon"); - } + public class Source + { + public string Name { get; set; } + public string Value { get; set; } + public string Foo { get; set; } } - public class When_destination_property_does_not_have_a_setter : AutoMapperSpecBase + public class Destination { - private Source _source; - private Destination _dest; + private DateTime _today; - public class Source + public string Name { get; private set; } + public string Foo { get; protected set; } + public DateTime Today { get { return _today; } } + public string Value { get; set; } + + public Destination() { - public string Name { get; set; } - public string Value { get; set; } - public string Foo { get; set; } + _today = DateTime.Today; + Name = "name"; } + } - public class Destination - { - private DateTime _today; + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); - public string Name { get; private set; } - public string Foo { get; protected set; } - public DateTime Today { get { return _today; } } - public string Value { get; set; } + }); - public Destination() - { - _today = DateTime.Today; - Name = "name"; - } - } + protected override void Because_of() + { + _source = new Source {Name = "jon", Value = "value", Foo = "bar"}; + _dest = new Destination(); + _dest = Mapper.Map(_source); + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); + [Fact] + public void Should_copy_to_properties_that_have_setters() + { + _dest.Value.ShouldBe("value"); + } - }); + [Fact] + public void Should_not_attempt_to_translate_to_properties_that_do_not_have_a_setter() + { + _dest.Today.ShouldBe(DateTime.Today); + } - protected override void Because_of() - { - _source = new Source {Name = "jon", Value = "value", Foo = "bar"}; - _dest = new Destination(); - _dest = Mapper.Map(_source); - } + [Fact] + public void Should_translate_to_properties_that_have_a_private_setters() + { + _dest.Name.ShouldBe("jon"); + } - [Fact] - public void Should_copy_to_properties_that_have_setters() - { - _dest.Value.ShouldBe("value"); - } + [Fact] + public void Should_translate_to_properties_that_have_a_protected_setters() + { + _dest.Foo.ShouldBe("bar"); + } +} - [Fact] - public void Should_not_attempt_to_translate_to_properties_that_do_not_have_a_setter() - { - _dest.Today.ShouldBe(DateTime.Today); - } +public class When_destination_property_does_not_have_a_getter : AutoMapperSpecBase +{ + private Source _source; + private Destination _dest; + private SourceWithList _sourceWithList; + private DestinationWithList _destWithList; - [Fact] - public void Should_translate_to_properties_that_have_a_private_setters() - { - _dest.Name.ShouldBe("jon"); - } + public class Source + { + public string Value { get; set; } - [Fact] - public void Should_translate_to_properties_that_have_a_protected_setters() - { - _dest.Foo.ShouldBe("bar"); - } } - public class When_destination_property_does_not_have_a_getter : AutoMapperSpecBase + public class Destination { - private Source _source; - private Destination _dest; - private SourceWithList _sourceWithList; - private DestinationWithList _destWithList; + private string _value; - public class Source + public string Value { - public string Value { get; set; } - + set { _value = value; } } - public class Destination + public string GetValue() { - private string _value; + return _value; + } + } - public string Value - { - set { _value = value; } - } + public class SourceWithList + { + public IList SomeList { get; set; } + } - public string GetValue() - { - return _value; - } - } + public class DestinationWithList + { + private IList _someList; - public class SourceWithList + public IList SomeList { - public IList SomeList { get; set; } + set { _someList = value; } } - public class DestinationWithList + public IList GetSomeList() { - private IList _someList; - - public IList SomeList - { - set { _someList = value; } - } - - public IList GetSomeList() - { - return _someList; - } + return _someList; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - cfg.CreateMap(); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + cfg.CreateMap(); - }); + }); - protected override void Because_of() - { - _source = new Source { Value = "jon" }; - _dest = new Destination(); + protected override void Because_of() + { + _source = new Source { Value = "jon" }; + _dest = new Destination(); - _sourceWithList = new SourceWithList { SomeList = new[] { 1, 2 } }; - _destWithList = new DestinationWithList(); - _dest = Mapper.Map(_source); - _destWithList = Mapper.Map(_sourceWithList); - } + _sourceWithList = new SourceWithList { SomeList = new[] { 1, 2 } }; + _destWithList = new DestinationWithList(); + _dest = Mapper.Map(_source); + _destWithList = Mapper.Map(_sourceWithList); + } - [Fact] - public void Should_translate_to_properties_that_doesnt_have_a_getter() - { - _dest.GetValue().ShouldBe("jon"); - } + [Fact] + public void Should_translate_to_properties_that_doesnt_have_a_getter() + { + _dest.GetValue().ShouldBe("jon"); + } - [Fact] - public void Should_translate_to_enumerable_properties_that_doesnt_have_a_getter() - { - new[] { 1, 2 }.ShouldBe(_destWithList.GetSomeList()); - } + [Fact] + public void Should_translate_to_enumerable_properties_that_doesnt_have_a_getter() + { + new[] { 1, 2 }.ShouldBe(_destWithList.GetSomeList()); } +} - public class When_destination_type_requires_a_constructor : AutoMapperSpecBase - { - private Destination _destination; +public class When_destination_type_requires_a_constructor : AutoMapperSpecBase +{ + private Destination _destination; - public class Source - { - public int Value { get; set; } - } + public class Source + { + public int Value { get; set; } + } - public class Destination + public class Destination + { + public Destination(int otherValue) { - public Destination(int otherValue) - { - OtherValue = otherValue; - } - - public int Value { get; set; } - public int OtherValue { get; set; } + OtherValue = otherValue; } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ConstructUsing(src => new Destination(src.Value + 4)) - .ForMember(dest => dest.OtherValue, opt => opt.Ignore()); - }); + public int Value { get; set; } + public int OtherValue { get; set; } + } - protected override void Because_of() - { - _destination = Mapper.Map(new Source { Value = 5 }); - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .ConstructUsing(src => new Destination(src.Value + 4)) + .ForMember(dest => dest.OtherValue, opt => opt.Ignore()); + }); - [Fact] - public void Should_use_supplied_constructor_to_map() - { - _destination.OtherValue.ShouldBe(9); - } + protected override void Because_of() + { + _destination = Mapper.Map(new Source { Value = 5 }); + } - [Fact] - public void Should_map_other_members() - { - _destination.Value.ShouldBe(5); - } + [Fact] + public void Should_use_supplied_constructor_to_map() + { + _destination.OtherValue.ShouldBe(9); } - public class When_mapping_from_a_constant_value : AutoMapperSpecBase + [Fact] + public void Should_map_other_members() { - private Dest _dest; + _destination.Value.ShouldBe(5); + } +} - public class Source - { +public class When_mapping_from_a_constant_value : AutoMapperSpecBase +{ + private Dest _dest; - } + public class Source + { - public class Dest - { - public int Value { get; set; } - } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ForMember(dest => dest.Value, opt => opt.MapFrom(src => 5)); - }); + public class Dest + { + public int Value { get; set; } + } - protected override void Because_of() - { - _dest = Mapper.Map(new Source()); - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .ForMember(dest => dest.Value, opt => opt.MapFrom(src => 5)); + }); - [Fact] - public void Should_map_from_that_constant_value() - { - _dest.Value.ShouldBe(5); - } + protected override void Because_of() + { + _dest = Mapper.Map(new Source()); } - public class When_building_custom_configuration_mapping_to_itself + [Fact] + public void Should_map_from_that_constant_value() { - private Exception _e; + _dest.Value.ShouldBe(5); + } +} - public class Source - { +public class When_building_custom_configuration_mapping_to_itself +{ + private Exception _e; - } + public class Source + { + + } + + public class Dest + { + public int Value { get; set; } + } - public class Dest + [Fact] + public void Should_map_from_that_constant_value() + { + try { - public int Value { get; set; } + var config = new MapperConfiguration(cfg => cfg.CreateMap() + .ForMember(dest => dest, opt => opt.MapFrom(src => 5))); } - - [Fact] - public void Should_map_from_that_constant_value() + catch (Exception e) { - try - { - var config = new MapperConfiguration(cfg => cfg.CreateMap() - .ForMember(dest => dest, opt => opt.MapFrom(src => 5))); - } - catch (Exception e) - { - _e = e; - } - _e.ShouldNotBeNull(); + _e = e; } + _e.ShouldNotBeNull(); } +} + +public class When_mapping_from_one_type_to_another : AutoMapperSpecBase +{ + private Dest _dest; - public class When_mapping_from_one_type_to_another : AutoMapperSpecBase + public class Source { - private Dest _dest; + public string Value { get; set; } + } - public class Source + public class Dest + { + // AutoMapper tries to map source to this constructor's parameter, + // but does not take its member configuration into account + public Dest(int value) { - public string Value { get; set; } + Value = value; } - - public class Dest + public Dest() { - // AutoMapper tries to map source to this constructor's parameter, - // but does not take its member configuration into account - public Dest(int value) - { - Value = value; - } - public Dest() - { - } - - public int Value { get; set; } } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.DisableConstructorMapping(); - cfg.CreateMap() - .ForMember(dest => dest.Value, opt => opt.MapFrom(s => ParseValue(s.Value))); - }); + public int Value { get; set; } + } - protected override void Because_of() - { - var source = new Source { Value = "a1" }; - _dest = Mapper.Map(source); - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.DisableConstructorMapping(); + cfg.CreateMap() + .ForMember(dest => dest.Value, opt => opt.MapFrom(s => ParseValue(s.Value))); + }); - [Fact] - public void Should_use_member_configuration() - { - _dest.Value.ShouldBe(1); - } + protected override void Because_of() + { + var source = new Source { Value = "a1" }; + _dest = Mapper.Map(source); + } - private static int ParseValue(string value) - { - return int.Parse(value.Substring(1)); - } + [Fact] + public void Should_use_member_configuration() + { + _dest.Value.ShouldBe(1); + } + + private static int ParseValue(string value) + { + return int.Parse(value.Substring(1)); } } \ No newline at end of file diff --git a/src/UnitTests/CustomValidations.cs b/src/UnitTests/CustomValidations.cs index 90c6c59034..834d3ef406 100644 --- a/src/UnitTests/CustomValidations.cs +++ b/src/UnitTests/CustomValidations.cs @@ -6,219 +6,218 @@ using Shouldly; using Xunit; -namespace AutoMapper.UnitTests +namespace AutoMapper.UnitTests; + +public class CustomValidations { - public class CustomValidations + public class Source + { + } + + public class Destination + { + } + + public class When_using_custom_validation { + bool _calledForRoot = false; + bool _calledForValues = false; + bool _calledForInt = false; + public class Source { + public int[] Values { get; set; } } - public class Destination + public class Dest { + public int[] Values { get; set; } } - public class When_using_custom_validation + [Fact] + public void Should_call_the_validator() { - bool _calledForRoot = false; - bool _calledForValues = false; - bool _calledForInt = false; - - public class Source - { - public int[] Values { get; set; } - } - - public class Dest + var config = new MapperConfiguration(cfg => { - public int[] Values { get; set; } - } + cfg.Internal().Validator(Validator); + cfg.CreateMap(); + }); - [Fact] - public void Should_call_the_validator() - { - var config = new MapperConfiguration(cfg => - { - cfg.Internal().Validator(Validator); - cfg.CreateMap(); - }); + config.AssertConfigurationIsValid(); - config.AssertConfigurationIsValid(); + _calledForRoot.ShouldBeTrue(); + _calledForValues.ShouldBeTrue(); + _calledForInt.ShouldBeTrue(); + } - _calledForRoot.ShouldBeTrue(); - _calledForValues.ShouldBeTrue(); - _calledForInt.ShouldBeTrue(); + private void Validator(ValidationContext context) + { + if (context.TypeMap != null) + { + _calledForRoot = true; + context.TypeMap.Types.ShouldBe(context.Types); + context.Types.SourceType.ShouldBe(typeof(Source)); + context.Types.DestinationType.ShouldBe(typeof(Dest)); + context.ObjectMapper.ShouldBeNull(); + context.MemberMap.ShouldBeNull(); } - - private void Validator(ValidationContext context) + else { - if (context.TypeMap != null) + context.MemberMap.SourceMember.Name.ShouldBe("Values"); + context.MemberMap.DestinationName.ShouldBe("Values"); + if (context.Types.Equals(new TypePair(typeof(int), typeof(int)))) { - _calledForRoot = true; - context.TypeMap.Types.ShouldBe(context.Types); - context.Types.SourceType.ShouldBe(typeof(Source)); - context.Types.DestinationType.ShouldBe(typeof(Dest)); - context.ObjectMapper.ShouldBeNull(); - context.MemberMap.ShouldBeNull(); + _calledForInt = true; + context.ObjectMapper.ShouldBeOfType(); } else { - context.MemberMap.SourceMember.Name.ShouldBe("Values"); - context.MemberMap.DestinationName.ShouldBe("Values"); - if (context.Types.Equals(new TypePair(typeof(int), typeof(int)))) - { - _calledForInt = true; - context.ObjectMapper.ShouldBeOfType(); - } - else - { - _calledForValues = true; - context.ObjectMapper.ShouldBeOfType(); - context.Types.SourceType.ShouldBe(typeof(int[])); - context.Types.DestinationType.ShouldBe(typeof(int[])); - } + _calledForValues = true; + context.ObjectMapper.ShouldBeOfType(); + context.Types.SourceType.ShouldBe(typeof(int[])); + context.Types.DestinationType.ShouldBe(typeof(int[])); } } } + } - public class When_using_custom_validation_for_convertusing_with_mappingfunction : NonValidatingSpecBase - { - // Nullable so can see a false state - private static bool? _validated; + public class When_using_custom_validation_for_convertusing_with_mappingfunction : NonValidatingSpecBase + { + // Nullable so can see a false state + private static bool? _validated; - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - Func mappingFunction = (source, destination) => new Destination(); - cfg.CreateMap().ConvertUsing(mappingFunction); - cfg.Internal().Validator(SetValidated); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + Func mappingFunction = (source, destination) => new Destination(); + cfg.CreateMap().ConvertUsing(mappingFunction); + cfg.Internal().Validator(SetValidated); + }); - private static void SetValidated(ValidationContext context) + private static void SetValidated(ValidationContext context) + { + if (context.TypeMap.SourceType == typeof(Source) && + context.TypeMap.DestinationType == typeof(Destination)) { - if (context.TypeMap.SourceType == typeof(Source) && - context.TypeMap.DestinationType == typeof(Destination)) - { - _validated = true; - } + _validated = true; } + } - [Fact] - public void Validator_should_be_called_by_AssertConfigurationIsValid() - { - _validated.ShouldBeNull(); + [Fact] + public void Validator_should_be_called_by_AssertConfigurationIsValid() + { + _validated.ShouldBeNull(); - AssertConfigurationIsValid(); + AssertConfigurationIsValid(); - _validated.ShouldBe(true); - } + _validated.ShouldBe(true); } + } - public class When_using_custom_validation_for_convertusing_with_typeconvertertype : NonValidatingSpecBase - { - // Nullable so can see a false state - private static bool? _validated; + public class When_using_custom_validation_for_convertusing_with_typeconvertertype : NonValidatingSpecBase + { + // Nullable so can see a false state + private static bool? _validated; - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().ConvertUsing(); - cfg.Internal().Validator(SetValidated); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().ConvertUsing(); + cfg.Internal().Validator(SetValidated); + }); - private static void SetValidated(ValidationContext context) + private static void SetValidated(ValidationContext context) + { + if (context.TypeMap.SourceType == typeof(Source) && + context.TypeMap.DestinationType == typeof(Destination)) { - if (context.TypeMap.SourceType == typeof(Source) && - context.TypeMap.DestinationType == typeof(Destination)) - { - _validated = true; - } + _validated = true; } + } - [Fact] - public void Validator_should_be_called_by_AssertConfigurationIsValid() - { - _validated.ShouldBeNull(); + [Fact] + public void Validator_should_be_called_by_AssertConfigurationIsValid() + { + _validated.ShouldBeNull(); - AssertConfigurationIsValid(); + AssertConfigurationIsValid(); - _validated.ShouldBe(true); - } + _validated.ShouldBe(true); + } - internal class CustomTypeConverter : ITypeConverter + internal class CustomTypeConverter : ITypeConverter + { + public Destination Convert(Source source, Destination destination, ResolutionContext context) { - public Destination Convert(Source source, Destination destination, ResolutionContext context) - { - return new Destination(); - } + return new Destination(); } } + } - public class When_using_custom_validation_for_convertusing_with_typeconverter_instance : NonValidatingSpecBase - { - // Nullable so can see a false state - private static bool? _validated; + public class When_using_custom_validation_for_convertusing_with_typeconverter_instance : NonValidatingSpecBase + { + // Nullable so can see a false state + private static bool? _validated; - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().ConvertUsing(new CustomTypeConverter()); - cfg.Internal().Validator(SetValidated); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().ConvertUsing(new CustomTypeConverter()); + cfg.Internal().Validator(SetValidated); + }); - private static void SetValidated(ValidationContext context) + private static void SetValidated(ValidationContext context) + { + if (context.TypeMap.SourceType == typeof(Source) && + context.TypeMap.DestinationType == typeof(Destination)) { - if (context.TypeMap.SourceType == typeof(Source) && - context.TypeMap.DestinationType == typeof(Destination)) - { - _validated = true; - } + _validated = true; } + } - [Fact] - public void Validator_should_be_called_by_AssertConfigurationIsValid() - { - _validated.ShouldBeNull(); + [Fact] + public void Validator_should_be_called_by_AssertConfigurationIsValid() + { + _validated.ShouldBeNull(); - AssertConfigurationIsValid(); + AssertConfigurationIsValid(); - _validated.ShouldBe(true); - } + _validated.ShouldBe(true); + } - internal class CustomTypeConverter : ITypeConverter + internal class CustomTypeConverter : ITypeConverter + { + public Destination Convert(Source source, Destination destination, ResolutionContext context) { - public Destination Convert(Source source, Destination destination, ResolutionContext context) - { - return new Destination(); - } + return new Destination(); } } + } - public class When_using_custom_validation_for_convertusing_with_mappingexpression : NonValidatingSpecBase - { - // Nullable so can see a false state - private static bool? _validated; + public class When_using_custom_validation_for_convertusing_with_mappingexpression : NonValidatingSpecBase + { + // Nullable so can see a false state + private static bool? _validated; - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - Expression> mappingExpression = source => new Destination(); - cfg.CreateMap().ConvertUsing(mappingExpression); - cfg.Internal().Validator(SetValidated); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + Expression> mappingExpression = source => new Destination(); + cfg.CreateMap().ConvertUsing(mappingExpression); + cfg.Internal().Validator(SetValidated); + }); - private static void SetValidated(ValidationContext context) + private static void SetValidated(ValidationContext context) + { + if (context.TypeMap.SourceType == typeof(Source) && + context.TypeMap.DestinationType == typeof(Destination)) { - if (context.TypeMap.SourceType == typeof(Source) && - context.TypeMap.DestinationType == typeof(Destination)) - { - _validated = true; - } + _validated = true; } + } - [Fact] - public void Validator_should_be_called_by_AssertConfigurationIsValid() - { - _validated.ShouldBeNull(); - AssertConfigurationIsValid(); - _validated.ShouldBe(true); - } + [Fact] + public void Validator_should_be_called_by_AssertConfigurationIsValid() + { + _validated.ShouldBeNull(); + AssertConfigurationIsValid(); + _validated.ShouldBe(true); } } } \ No newline at end of file diff --git a/src/UnitTests/EnumToNullableEnum.cs b/src/UnitTests/EnumToNullableEnum.cs index b6933bb6c5..7e2e111592 100644 --- a/src/UnitTests/EnumToNullableEnum.cs +++ b/src/UnitTests/EnumToNullableEnum.cs @@ -1,37 +1,36 @@ using Shouldly; using Xunit; -namespace AutoMapper.UnitTests +namespace AutoMapper.UnitTests; + +public class EnumToNullableEnum : AutoMapperSpecBase { - public class EnumToNullableEnum : AutoMapperSpecBase - { - Destination _destination; - public enum SomeEnum { Foo, Bar } + Destination _destination; + public enum SomeEnum { Foo, Bar } - public class Source - { - public SomeEnum EnumValue { get; set; } - } + public class Source + { + public SomeEnum EnumValue { get; set; } + } - public class Destination - { - public SomeEnum? EnumValue { get; set; } - } + public class Destination + { + public SomeEnum? EnumValue { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + }); - protected override void Because_of() - { - _destination = Mapper.Map(new Source{ EnumValue = SomeEnum.Bar }); - } + protected override void Because_of() + { + _destination = Mapper.Map(new Source{ EnumValue = SomeEnum.Bar }); + } - [Fact] - public void Should_map_enum_to_nullable_enum() - { - _destination.EnumValue.ShouldBe(SomeEnum.Bar); - } + [Fact] + public void Should_map_enum_to_nullable_enum() + { + _destination.EnumValue.ShouldBe(SomeEnum.Bar); } } diff --git a/src/UnitTests/Enumerations.cs b/src/UnitTests/Enumerations.cs index 15b982f5d5..f5644ca72f 100644 --- a/src/UnitTests/Enumerations.cs +++ b/src/UnitTests/Enumerations.cs @@ -4,697 +4,696 @@ using Shouldly; using Xunit; -namespace AutoMapper.Tests +namespace AutoMapper.Tests; + +public class InvalidStringToEnum : AutoMapperSpecBase +{ + protected override MapperConfiguration CreateConfiguration() => new(_=> { }); + [Fact] + public void Should_throw() => new Action(()=>Map("d")).ShouldThrow().InnerException.Message.ShouldBe( + "Requested value 'd' was not found."); +} +public class DefaultEnumValueToString : AutoMapperSpecBase { - public class InvalidStringToEnum : AutoMapperSpecBase + Destination _destination; + + class Source { - protected override MapperConfiguration CreateConfiguration() => new(_=> { }); - [Fact] - public void Should_throw() => new Action(()=>Map("d")).ShouldThrow().InnerException.Message.ShouldBe( - "Requested value 'd' was not found."); + public ConsoleColor Color { get; set; } } - public class DefaultEnumValueToString : AutoMapperSpecBase - { - Destination _destination; - - class Source - { - public ConsoleColor Color { get; set; } - } - - class Destination - { - public string Color { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - }); - - protected override void Because_of() - { - _destination = Mapper.Map(new Source()); - } - - [Fact] - public void Should_map_ok() - { - _destination.Color.ShouldBe("Black"); - } + class Destination + { + public string Color { get; set; } } - public class StringToNullableEnum : AutoMapperSpecBase + protected override MapperConfiguration CreateConfiguration() => new(cfg => { - Destination _destination; + cfg.CreateMap(); + }); - class Source - { - public string Color { get; set; } - } - - class Destination - { - public ConsoleColor? Color { get; set; } - } + protected override void Because_of() + { + _destination = Mapper.Map(new Source()); + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - }); + [Fact] + public void Should_map_ok() + { + _destination.Color.ShouldBe("Black"); + } +} - protected override void Because_of() - { - _destination = Mapper.Map(new Source { Color = "Red" }); - } +public class StringToNullableEnum : AutoMapperSpecBase +{ + Destination _destination; - [Fact] - public void Should_map_with_underlying_type() - { - _destination.Color.ShouldBe(ConsoleColor.Red); - } + class Source + { + public string Color { get; set; } } - public class NullableEnumToString : AutoMapperSpecBase + class Destination { - Destination _destination; + public ConsoleColor? Color { get; set; } + } - class Source - { - public ConsoleColor? Color { get; set; } - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + }); - class Destination - { - public string Color { get; set; } - } + protected override void Because_of() + { + _destination = Mapper.Map(new Source { Color = "Red" }); + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - cfg.CreateMap().ConvertUsing((Enum src) => "Test"); - }); + [Fact] + public void Should_map_with_underlying_type() + { + _destination.Color.ShouldBe(ConsoleColor.Red); + } +} - protected override void Because_of() - { - _destination = Mapper.Map(new Source { Color = ConsoleColor.Black }); - } +public class NullableEnumToString : AutoMapperSpecBase +{ + Destination _destination; - [Fact] - public void Should_map_with_underlying_type() - { - _destination.Color.ShouldBe("Test"); - } + class Source + { + public ConsoleColor? Color { get; set; } } - public class EnumMappingFixture + class Destination { - [Fact] - public void ShouldMapSharedEnum() - { - var config = new MapperConfiguration(cfg => cfg.CreateMap()); + public string Color { get; set; } + } - var order = new Order - { - Status = Status.InProgress - }; + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + cfg.CreateMap().ConvertUsing((Enum src) => "Test"); + }); - var mapper = config.CreateMapper(); - var dto = mapper.Map(order); + protected override void Because_of() + { + _destination = Mapper.Map(new Source { Color = ConsoleColor.Black }); + } - dto.Status.ShouldBe(Status.InProgress); - } + [Fact] + public void Should_map_with_underlying_type() + { + _destination.Color.ShouldBe("Test"); + } +} - [Fact] - public void ShouldMapToUnderlyingType() { - var config = new MapperConfiguration(cfg => cfg.CreateMap()); +public class EnumMappingFixture +{ + [Fact] + public void ShouldMapSharedEnum() + { + var config = new MapperConfiguration(cfg => cfg.CreateMap()); - var order = new Order { + var order = new Order + { Status = Status.InProgress }; - var mapper = config.CreateMapper(); - var dto = mapper.Map(order); + var mapper = config.CreateMapper(); + var dto = mapper.Map(order); - dto.Status.ShouldBe(1); - } + dto.Status.ShouldBe(Status.InProgress); + } - [Fact] - public void ShouldMapToStringType() { - var config = new MapperConfiguration(cfg => cfg.CreateMap()); + [Fact] + public void ShouldMapToUnderlyingType() { + var config = new MapperConfiguration(cfg => cfg.CreateMap()); - var order = new Order { - Status = Status.InProgress - }; + var order = new Order { + Status = Status.InProgress + }; - var mapper = config.CreateMapper(); - var dto = mapper.Map(order); + var mapper = config.CreateMapper(); + var dto = mapper.Map(order); - dto.Status.ShouldBe("InProgress"); - } + dto.Status.ShouldBe(1); + } - [Fact] - public void ShouldMapFromUnderlyingType() { - var config = new MapperConfiguration(cfg => cfg.CreateMap()); + [Fact] + public void ShouldMapToStringType() { + var config = new MapperConfiguration(cfg => cfg.CreateMap()); - var order = new OrderDtoInt { - Status = 1 - }; + var order = new Order { + Status = Status.InProgress + }; - var mapper = config.CreateMapper(); - var dto = mapper.Map(order); + var mapper = config.CreateMapper(); + var dto = mapper.Map(order); - dto.Status.ShouldBe(Status.InProgress); - } + dto.Status.ShouldBe("InProgress"); + } - [Fact] - public void ShouldMapFromStringType() { - var config = new MapperConfiguration(cfg => cfg.CreateMap()); + [Fact] + public void ShouldMapFromUnderlyingType() { + var config = new MapperConfiguration(cfg => cfg.CreateMap()); - var order = new OrderDtoString { - Status = "InProgress" - }; + var order = new OrderDtoInt { + Status = 1 + }; - var mapper = config.CreateMapper(); - var dto = mapper.Map(order); + var mapper = config.CreateMapper(); + var dto = mapper.Map(order); - dto.Status.ShouldBe(Status.InProgress); - } - - [Fact] - public void ShouldMapEnumByMatchingNames() - { - var config = new MapperConfiguration(cfg => cfg.CreateMap()); + dto.Status.ShouldBe(Status.InProgress); + } - var order = new Order - { - Status = Status.InProgress - }; + [Fact] + public void ShouldMapFromStringType() { + var config = new MapperConfiguration(cfg => cfg.CreateMap()); - var mapper = config.CreateMapper(); - var dto = mapper.Map(order); + var order = new OrderDtoString { + Status = "InProgress" + }; - dto.Status.ShouldBe(StatusForDto.InProgress); - } + var mapper = config.CreateMapper(); + var dto = mapper.Map(order); - [Fact] - public void ShouldMapEnumByMatchingValues() - { - var config = new MapperConfiguration(cfg => cfg.CreateMap()); + dto.Status.ShouldBe(Status.InProgress); + } + + [Fact] + public void ShouldMapEnumByMatchingNames() + { + var config = new MapperConfiguration(cfg => cfg.CreateMap()); - var order = new Order - { - Status = Status.InProgress - }; + var order = new Order + { + Status = Status.InProgress + }; - var mapper = config.CreateMapper(); - var dto = mapper.Map(order); + var mapper = config.CreateMapper(); + var dto = mapper.Map(order); - dto.Status.ShouldBe(StatusForDto.InProgress); - } + dto.Status.ShouldBe(StatusForDto.InProgress); + } - [Fact] - public void ShouldMapSharedNullableEnum() - { - var config = new MapperConfiguration(cfg => cfg.CreateMap()); + [Fact] + public void ShouldMapEnumByMatchingValues() + { + var config = new MapperConfiguration(cfg => cfg.CreateMap()); - var order = new OrderWithNullableStatus { + var order = new Order + { Status = Status.InProgress }; - var mapper = config.CreateMapper(); - var dto = mapper.Map(order); + var mapper = config.CreateMapper(); + var dto = mapper.Map(order); - dto.Status.ShouldBe(Status.InProgress); - } + dto.Status.ShouldBe(StatusForDto.InProgress); + } - [Fact] - public void ShouldMapNullableEnumByMatchingValues() - { - var config = new MapperConfiguration(cfg => cfg.CreateMap()); + [Fact] + public void ShouldMapSharedNullableEnum() + { + var config = new MapperConfiguration(cfg => cfg.CreateMap()); - var order = new OrderWithNullableStatus { - Status = Status.InProgress - }; + var order = new OrderWithNullableStatus { + Status = Status.InProgress + }; - var mapper = config.CreateMapper(); - var dto = mapper.Map(order); + var mapper = config.CreateMapper(); + var dto = mapper.Map(order); - dto.Status.ShouldBe(StatusForDto.InProgress); - } + dto.Status.ShouldBe(Status.InProgress); + } - [Fact] - public void ShouldMapNullableEnumToNullWhenSourceEnumIsNullAndDestinationWasNotNull() - { - var config = new MapperConfiguration(cfg => - { - cfg.AllowNullDestinationValues = true; - cfg.CreateMap(); - }); + [Fact] + public void ShouldMapNullableEnumByMatchingValues() + { + var config = new MapperConfiguration(cfg => cfg.CreateMap()); - var dto = new OrderDtoWithOwnNullableStatus() - { - Status = StatusForDto.Complete - }; + var order = new OrderWithNullableStatus { + Status = Status.InProgress + }; - var order = new OrderWithNullableStatus - { - Status = null - }; + var mapper = config.CreateMapper(); + var dto = mapper.Map(order); - var mapper = config.CreateMapper(); - mapper.Map(order, dto); + dto.Status.ShouldBe(StatusForDto.InProgress); + } - dto.Status.ShouldBeNull(); - } + [Fact] + public void ShouldMapNullableEnumToNullWhenSourceEnumIsNullAndDestinationWasNotNull() + { + var config = new MapperConfiguration(cfg => + { + cfg.AllowNullDestinationValues = true; + cfg.CreateMap(); + }); - [Fact] - public void ShouldMapNullableEnumToNullWhenSourceEnumIsNull() + var dto = new OrderDtoWithOwnNullableStatus() { - var config = new MapperConfiguration(cfg => cfg.CreateMap()); + Status = StatusForDto.Complete + }; - var order = new OrderWithNullableStatus { - Status = null - }; + var order = new OrderWithNullableStatus + { + Status = null + }; - var mapper = config.CreateMapper(); - var dto = mapper.Map(order); + var mapper = config.CreateMapper(); + mapper.Map(order, dto); - dto.Status.ShouldBeNull(); - } + dto.Status.ShouldBeNull(); + } - [Fact] - public void ShouldMapEnumUsingCustomResolver() - { - var config = new MapperConfiguration(cfg => cfg.CreateMap() - .ForMember(dto => dto.Status, options => options.MapFrom())); + [Fact] + public void ShouldMapNullableEnumToNullWhenSourceEnumIsNull() + { + var config = new MapperConfiguration(cfg => cfg.CreateMap()); - var order = new Order - { - Status = Status.InProgress - }; + var order = new OrderWithNullableStatus { + Status = null + }; - var mapper = config.CreateMapper(); - var mappedDto = mapper.Map(order); + var mapper = config.CreateMapper(); + var dto = mapper.Map(order); - mappedDto.Status.ShouldBe(StatusForDto.InProgress); - } + dto.Status.ShouldBeNull(); + } - [Fact] - public void ShouldMapEnumUsingGenericEnumResolver() - { - var config = new MapperConfiguration(cfg => cfg.CreateMap() - .ForMember(dto => dto.Status, options => options.MapFrom, Status>(m => m.Status))); + [Fact] + public void ShouldMapEnumUsingCustomResolver() + { + var config = new MapperConfiguration(cfg => cfg.CreateMap() + .ForMember(dto => dto.Status, options => options.MapFrom())); - var order = new Order - { - Status = Status.InProgress - }; + var order = new Order + { + Status = Status.InProgress + }; - var mapper = config.CreateMapper(); - var mappedDto = mapper.Map(order); + var mapper = config.CreateMapper(); + var mappedDto = mapper.Map(order); - mappedDto.Status.ShouldBe(StatusForDto.InProgress); - } + mappedDto.Status.ShouldBe(StatusForDto.InProgress); + } - [Fact] - public void ShouldMapEnumWithInvalidValue() - { - var config = new MapperConfiguration(cfg => cfg.CreateMap()); + [Fact] + public void ShouldMapEnumUsingGenericEnumResolver() + { + var config = new MapperConfiguration(cfg => cfg.CreateMap() + .ForMember(dto => dto.Status, options => options.MapFrom, Status>(m => m.Status))); - var order = new Order + var order = new Order { - Status = 0 + Status = Status.InProgress }; - var mapper = config.CreateMapper(); - var dto = mapper.Map(order); + var mapper = config.CreateMapper(); + var mappedDto = mapper.Map(order); - var expected = (StatusForDto)0; + mappedDto.Status.ShouldBe(StatusForDto.InProgress); + } - dto.Status.ShouldBe(expected); - } + [Fact] + public void ShouldMapEnumWithInvalidValue() + { + var config = new MapperConfiguration(cfg => cfg.CreateMap()); - public enum Status + var order = new Order { - InProgress = 1, - Complete = 2 - } + Status = 0 + }; - public enum StatusForDto - { - InProgress = 1, - Complete = 2 - } + var mapper = config.CreateMapper(); + var dto = mapper.Map(order); - public class Order - { - public Status Status { get; set; } - } + var expected = (StatusForDto)0; - public class OrderDto - { - public Status Status { get; set; } - } + dto.Status.ShouldBe(expected); + } - public class OrderDtoInt { - public int Status { get; set; } - } + public enum Status + { + InProgress = 1, + Complete = 2 + } - public class OrderDtoString { - public string Status { get; set; } - } + public enum StatusForDto + { + InProgress = 1, + Complete = 2 + } - public class OrderDtoWithOwnStatus - { - public StatusForDto Status { get; set; } - } + public class Order + { + public Status Status { get; set; } + } - public class OrderWithNullableStatus - { - public Status? Status { get; set; } - } + public class OrderDto + { + public Status Status { get; set; } + } - public class OrderDtoWithNullableStatus - { - public Status? Status { get; set; } - } + public class OrderDtoInt { + public int Status { get; set; } + } - public class OrderDtoWithOwnNullableStatus - { - public StatusForDto? Status { get; set; } - } + public class OrderDtoString { + public string Status { get; set; } + } - public class DtoStatusValueResolver : IValueResolver - { - public StatusForDto Resolve(Order source, object d, StatusForDto dest, ResolutionContext context) - { - return context.Mapper.Map(source.Status); - } - } + public class OrderDtoWithOwnStatus + { + public StatusForDto Status { get; set; } + } - public class EnumValueResolver : IMemberValueResolver - { - public TOutputEnum Resolve(object s, object d, TInputEnum source, TOutputEnum dest, ResolutionContext context) - { - return ((TOutputEnum)Enum.Parse(typeof(TOutputEnum), Enum.GetName(typeof(TInputEnum), source), false)); - } - } + public class OrderWithNullableStatus + { + public Status? Status { get; set; } } - public class When_mapping_from_a_null_object_with_an_enum : AutoMapperSpecBase + + public class OrderDtoWithNullableStatus { - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.AllowNullDestinationValues = false; - cfg.CreateMap(); - }); + public Status? Status { get; set; } + } - public enum EnumValues - { - One, Two, Three - } + public class OrderDtoWithOwnNullableStatus + { + public StatusForDto? Status { get; set; } + } - public class DestinationClass + public class DtoStatusValueResolver : IValueResolver + { + public StatusForDto Resolve(Order source, object d, StatusForDto dest, ResolutionContext context) { - public EnumValues Values { get; set; } + return context.Mapper.Map(source.Status); } + } - public class SourceClass + public class EnumValueResolver : IMemberValueResolver + { + public TOutputEnum Resolve(object s, object d, TInputEnum source, TOutputEnum dest, ResolutionContext context) { - public EnumValues Values { get; set; } + return ((TOutputEnum)Enum.Parse(typeof(TOutputEnum), Enum.GetName(typeof(TInputEnum), source), false)); } + } +} +public class When_mapping_from_a_null_object_with_an_enum : AutoMapperSpecBase +{ + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.AllowNullDestinationValues = false; + cfg.CreateMap(); + }); - [Fact] - public void Should_set_the_target_enum_to_the_default_value() - { - SourceClass sourceClass = null; - var dest = Mapper.Map(sourceClass); - dest.Values.ShouldBe(default(EnumValues)); - } + public enum EnumValues + { + One, Two, Three } - public class When_mapping_to_a_nullable_flags_enum : AutoMapperSpecBase + public class DestinationClass { - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - }); + public EnumValues Values { get; set; } + } - [Flags] - public enum EnumValues - { - One, Two = 2, Three = 4 - } + public class SourceClass + { + public EnumValues Values { get; set; } + } - public class SourceClass - { - public EnumValues Values { get; set; } - } + [Fact] + public void Should_set_the_target_enum_to_the_default_value() + { + SourceClass sourceClass = null; + var dest = Mapper.Map(sourceClass); + dest.Values.ShouldBe(default(EnumValues)); + } +} - public class DestinationClass - { - public EnumValues? Values { get; set; } - } +public class When_mapping_to_a_nullable_flags_enum : AutoMapperSpecBase +{ + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + }); - [Fact] - public void Should_set_the_target_enum_to_the_default_value() - { - var values = EnumValues.Two | EnumValues.Three; - var dest = Mapper.Map(new SourceClass { Values = values }); - dest.Values.ShouldBe(values); - } + [Flags] + public enum EnumValues + { + One, Two = 2, Three = 4 } - public class When_mapping_from_a_null_object_with_a_nullable_enum : AutoMapperSpecBase + public class SourceClass { - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.AllowNullDestinationValues = false; - cfg.CreateMap(); - }); + public EnumValues Values { get; set; } + } - public enum EnumValues - { - One, Two, Three - } + public class DestinationClass + { + public EnumValues? Values { get; set; } + } - public class DestinationClass - { - public EnumValues Values { get; set; } - } + [Fact] + public void Should_set_the_target_enum_to_the_default_value() + { + var values = EnumValues.Two | EnumValues.Three; + var dest = Mapper.Map(new SourceClass { Values = values }); + dest.Values.ShouldBe(values); + } +} - public class SourceClass - { - public EnumValues? Values { get; set; } - } +public class When_mapping_from_a_null_object_with_a_nullable_enum : AutoMapperSpecBase +{ + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.AllowNullDestinationValues = false; + cfg.CreateMap(); + }); - [Fact] - public void Should_set_the_target_enum_to_the_default_value() - { - SourceClass sourceClass = null; - var dest = Mapper.Map(sourceClass); - dest.Values.ShouldBe(default(EnumValues)); - } - } - public class When_mapping_from_a_null_object_with_a_nullable_enum_as_string : AutoMapperSpecBase + public enum EnumValues { - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - }); + One, Two, Three + } - public enum EnumValues - { - One, Two, Three - } + public class DestinationClass + { + public EnumValues Values { get; set; } + } - public class DestinationClass - { - public EnumValues Values1 { get; set; } - public EnumValues? Values2 { get; set; } - public EnumValues Values3 { get; set; } - } + public class SourceClass + { + public EnumValues? Values { get; set; } + } - public class SourceClass - { - public string Values1 { get; set; } - public string Values2 { get; set; } - public string Values3 { get; set; } - } + [Fact] + public void Should_set_the_target_enum_to_the_default_value() + { + SourceClass sourceClass = null; + var dest = Mapper.Map(sourceClass); + dest.Values.ShouldBe(default(EnumValues)); + } +} +public class When_mapping_from_a_null_object_with_a_nullable_enum_as_string : AutoMapperSpecBase +{ + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + }); - [Fact] - public void Should_set_the_target_enum_to_the_default_value() - { - var sourceClass = new SourceClass(); - var dest = Mapper.Map(sourceClass); - dest.Values1.ShouldBe(default(EnumValues)); - } + public enum EnumValues + { + One, Two, Three + } - [Fact] - public void Should_set_the_target_nullable_to_null() - { - var sourceClass = new SourceClass(); - var dest = Mapper.Map(sourceClass); - dest.Values2.ShouldBeNull(); - } + public class DestinationClass + { + public EnumValues Values1 { get; set; } + public EnumValues? Values2 { get; set; } + public EnumValues Values3 { get; set; } + } - [Fact] - public void Should_set_the_target_empty_to_null() - { - var sourceClass = new SourceClass - { - Values3 = "" - }; - var dest = Mapper.Map(sourceClass); - dest.Values3.ShouldBe(default(EnumValues)); - } + public class SourceClass + { + public string Values1 { get; set; } + public string Values2 { get; set; } + public string Values3 { get; set; } } + [Fact] + public void Should_set_the_target_enum_to_the_default_value() + { + var sourceClass = new SourceClass(); + var dest = Mapper.Map(sourceClass); + dest.Values1.ShouldBe(default(EnumValues)); + } - public class When_mapping_a_flags_enum : NonValidatingSpecBase + [Fact] + public void Should_set_the_target_nullable_to_null() { - private DestinationFlags _result; + var sourceClass = new SourceClass(); + var dest = Mapper.Map(sourceClass); + dest.Values2.ShouldBeNull(); + } - [Flags] - private enum SourceFlags + [Fact] + public void Should_set_the_target_empty_to_null() + { + var sourceClass = new SourceClass { - None = 0, - One = 1, - Two = 2, - Four = 4, - Eight = 8 - } + Values3 = "" + }; + var dest = Mapper.Map(sourceClass); + dest.Values3.ShouldBe(default(EnumValues)); + } +} - [Flags] - private enum DestinationFlags - { - None = 0, - One = 1, - Two = 2, - Four = 4, - Eight = 8 - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => { }); +public class When_mapping_a_flags_enum : NonValidatingSpecBase +{ + private DestinationFlags _result; - protected override void Because_of() - { - _result = Mapper.Map(SourceFlags.One | SourceFlags.Four | SourceFlags.Eight); - } + [Flags] + private enum SourceFlags + { + None = 0, + One = 1, + Two = 2, + Four = 4, + Eight = 8 + } - [Fact] - public void Should_include_all_source_enum_values() - { - _result.ShouldBe(DestinationFlags.One | DestinationFlags.Four | DestinationFlags.Eight); - } + [Flags] + private enum DestinationFlags + { + None = 0, + One = 1, + Two = 2, + Four = 4, + Eight = 8 } - public class When_the_target_has_an_enummemberattribute_value : AutoMapperSpecBase + protected override MapperConfiguration CreateConfiguration() => new(cfg => { }); + + protected override void Because_of() { - public enum EnumWithEnumMemberAttribute - { - Null, - [EnumMember(Value = "Eins")] - One - } + _result = Mapper.Map(SourceFlags.One | SourceFlags.Four | SourceFlags.Eight); + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => { }); + [Fact] + public void Should_include_all_source_enum_values() + { + _result.ShouldBe(DestinationFlags.One | DestinationFlags.Four | DestinationFlags.Eight); + } +} - [Fact] - public void Should_return_the_enum_from_defined_enummemberattribute_value() - { - var dest = Mapper.Map("Eins"); - dest.ShouldBe(EnumWithEnumMemberAttribute.One); - } +public class When_the_target_has_an_enummemberattribute_value : AutoMapperSpecBase +{ + public enum EnumWithEnumMemberAttribute + { + Null, + [EnumMember(Value = "Eins")] + One + } - [Fact] - public void Should_return_the_enum_from_undefined_enummemberattribute_value() - { - var dest = Mapper.Map("Null"); - dest.ShouldBe(EnumWithEnumMemberAttribute.Null); - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => { }); - [Fact] - public void Should_return_the_nullable_enum_from_defined_enummemberattribute_value() - { - var dest = Mapper.Map("Eins"); - dest.ShouldBe(EnumWithEnumMemberAttribute.One); - } + [Fact] + public void Should_return_the_enum_from_defined_enummemberattribute_value() + { + var dest = Mapper.Map("Eins"); + dest.ShouldBe(EnumWithEnumMemberAttribute.One); + } - [Fact] - public void Should_return_the_enum_from_undefined_enummemberattribute_value_mixedcase() - { - var dest = Mapper.Map("NuLl"); - dest.ShouldBe(EnumWithEnumMemberAttribute.Null); - } + [Fact] + public void Should_return_the_enum_from_undefined_enummemberattribute_value() + { + var dest = Mapper.Map("Null"); + dest.ShouldBe(EnumWithEnumMemberAttribute.Null); + } - [Fact] - public void Should_return_the_enum_from_defined_enummemberattribute_value_mixedcase() - { - var dest = Mapper.Map("eInS"); - dest.ShouldBe(EnumWithEnumMemberAttribute.One); - } + [Fact] + public void Should_return_the_nullable_enum_from_defined_enummemberattribute_value() + { + var dest = Mapper.Map("Eins"); + dest.ShouldBe(EnumWithEnumMemberAttribute.One); + } - [Fact] - public void Should_return_the_nullable_enum_from_null_value() - { - var dest = Mapper.Map(null); - dest.ShouldBe(null); - } + [Fact] + public void Should_return_the_enum_from_undefined_enummemberattribute_value_mixedcase() + { + var dest = Mapper.Map("NuLl"); + dest.ShouldBe(EnumWithEnumMemberAttribute.Null); + } - [Fact] - public void Should_return_the_nullable_enum_from_undefined_enummemberattribute_value() - { - var dest = Mapper.Map("Null"); - dest.ShouldBe(EnumWithEnumMemberAttribute.Null); - } + [Fact] + public void Should_return_the_enum_from_defined_enummemberattribute_value_mixedcase() + { + var dest = Mapper.Map("eInS"); + dest.ShouldBe(EnumWithEnumMemberAttribute.One); } + [Fact] + public void Should_return_the_nullable_enum_from_null_value() + { + var dest = Mapper.Map(null); + dest.ShouldBe(null); + } - public class When_the_source_has_an_enummemberattribute_value : AutoMapperSpecBase + [Fact] + public void Should_return_the_nullable_enum_from_undefined_enummemberattribute_value() { - public enum EnumWithEnumMemberAttribute - { - Null, - [EnumMember(Value = "Eins")] - One - } + var dest = Mapper.Map("Null"); + dest.ShouldBe(EnumWithEnumMemberAttribute.Null); + } +} - protected override MapperConfiguration CreateConfiguration() => new(cfg => { }); - [Fact] - public void Should_return_the_defined_enummemberattribute_value() - { - var dest = Mapper.Map(EnumWithEnumMemberAttribute.One); - dest.ShouldBe("Eins"); - } +public class When_the_source_has_an_enummemberattribute_value : AutoMapperSpecBase +{ + public enum EnumWithEnumMemberAttribute + { + Null, + [EnumMember(Value = "Eins")] + One + } - [Fact] - public void Should_return_the_enum_value() - { - var dest = Mapper.Map(EnumWithEnumMemberAttribute.Null); - dest.ShouldBe("Null"); - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => { }); - [Fact] - public void Should_return_the_defined_enummemberattribute_value_nullable() - { - var dest = Mapper.Map(EnumWithEnumMemberAttribute.One); - dest.ShouldBe("Eins"); - } + [Fact] + public void Should_return_the_defined_enummemberattribute_value() + { + var dest = Mapper.Map(EnumWithEnumMemberAttribute.One); + dest.ShouldBe("Eins"); + } - [Fact] - public void Should_return_the_enum_value_nullable() - { - var dest = Mapper.Map(EnumWithEnumMemberAttribute.Null); - dest.ShouldBe("Null"); - } + [Fact] + public void Should_return_the_enum_value() + { + var dest = Mapper.Map(EnumWithEnumMemberAttribute.Null); + dest.ShouldBe("Null"); + } - [Fact] - public void Should_return_null() - { - var dest = Mapper.Map(null); - dest.ShouldBe(null); - } + [Fact] + public void Should_return_the_defined_enummemberattribute_value_nullable() + { + var dest = Mapper.Map(EnumWithEnumMemberAttribute.One); + dest.ShouldBe("Eins"); + } + + [Fact] + public void Should_return_the_enum_value_nullable() + { + var dest = Mapper.Map(EnumWithEnumMemberAttribute.Null); + dest.ShouldBe("Null"); + } + + [Fact] + public void Should_return_null() + { + var dest = Mapper.Map(null); + dest.ShouldBe(null); } } diff --git a/src/UnitTests/ExtensionMethods.cs b/src/UnitTests/ExtensionMethods.cs index 7da97be38d..8916453005 100644 --- a/src/UnitTests/ExtensionMethods.cs +++ b/src/UnitTests/ExtensionMethods.cs @@ -5,305 +5,304 @@ using System; using AutoMapper.Internal; -namespace AutoMapper.UnitTests +namespace AutoMapper.UnitTests; + +interface IGeneric { } +public class When_an_extension_methods_contraints_fail : NonValidatingSpecBase { - interface IGeneric { } - public class When_an_extension_methods_contraints_fail : NonValidatingSpecBase + class Source : IGeneric { - class Source : IGeneric - { - } - class Destination - { - public int Count { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(c => - { - c.IncludeSourceExtensionMethods(typeof(GenericExtensions)); - c.CreateMap(); - }); - [Fact] - public void It_should_fail_validation() => new Action(AssertConfigurationIsValid).ShouldThrow() - .Errors[0].UnmappedPropertyNames[0].ShouldBe(nameof(Destination.Count)); } - public class When_an_extension_method_is_for_a_base_interface : AutoMapperSpecBase + class Destination { - class Source : IGeneric - { - } - class Destination - { - public int Value { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(c => - { - c.IncludeSourceExtensionMethods(typeof(GenericExtensions)); - c.CreateMap(); - }); - [Fact] - public void It_should_be_used() => Map(new Source()).Value.ShouldBe(12); + public int Count { get; set; } } - public static class GenericExtensions + protected override MapperConfiguration CreateConfiguration() => new(c => + { + c.IncludeSourceExtensionMethods(typeof(GenericExtensions)); + c.CreateMap(); + }); + [Fact] + public void It_should_fail_validation() => new Action(AssertConfigurationIsValid).ShouldThrow() + .Errors[0].UnmappedPropertyNames[0].ShouldBe(nameof(Destination.Count)); +} +public class When_an_extension_method_is_for_a_base_interface : AutoMapperSpecBase +{ + class Source : IGeneric { - private static int GetValue(this IGeneric _) => 12; - private static int Count(this IGeneric _) where T : IDisposable => 12; } - public class When_an_extension_method_is_for_a_base_class : AutoMapperSpecBase + class Destination { - class Source - { - } - class Destination - { - public int Value { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(c=> - { - c.IncludeSourceExtensionMethods(typeof(BarExtensions)); - c.CreateMap(); - }); - [Fact] - public void It_should_be_used() => Map(new Source()).Value.ShouldBe(12); + public int Value { get; set; } } - public static class BarExtensions + protected override MapperConfiguration CreateConfiguration() => new(c => + { + c.IncludeSourceExtensionMethods(typeof(GenericExtensions)); + c.CreateMap(); + }); + [Fact] + public void It_should_be_used() => Map(new Source()).Value.ShouldBe(12); +} +public static class GenericExtensions +{ + private static int GetValue(this IGeneric _) => 12; + private static int Count(this IGeneric _) where T : IDisposable => 12; +} +public class When_an_extension_method_is_for_a_base_class : AutoMapperSpecBase +{ + class Source { - public static int GetValue(this object obj) => 12; - public static string GetSimpleName(this When_null_is_passed_to_an_extension_method.Bar source) - { - if(source == null) - throw new ArgumentNullException("source"); - return "SimpleName"; - } } - - public class When_null_is_passed_to_an_extension_method : AutoMapperSpecBase + class Destination { - public class Foo - { - public Bar Bar { get; set; } - } - - public class Bar - { - public string Name { get; set; } - } - - public class FooDto - { - public string BarSimpleName { get; set; } - public Guid Value { get; set; } - } + public int Value { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(c=> + { + c.IncludeSourceExtensionMethods(typeof(BarExtensions)); + c.CreateMap(); + }); + [Fact] + public void It_should_be_used() => Map(new Source()).Value.ShouldBe(12); +} +public static class BarExtensions +{ + public static int GetValue(this object obj) => 12; + public static string GetSimpleName(this When_null_is_passed_to_an_extension_method.Bar source) + { + if(source == null) + throw new ArgumentNullException("source"); + return "SimpleName"; + } +} - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.IncludeSourceExtensionMethods(typeof(BarExtensions)); - cfg.CreateMap().ForMember(d=>d.Value, o=>o.MapFrom(s=>Guid.NewGuid())); - }); +public class When_null_is_passed_to_an_extension_method : AutoMapperSpecBase +{ + public class Foo + { + public Bar Bar { get; set; } + } - [Fact] - public void Should_work() - { - Mapper.Map(new Foo()).BarSimpleName.ShouldBeNull(); - } + public class Bar + { + public string Name { get; set; } } - public static class When_extension_method_returns_value_type_SourceExtensions + public class FooDto { - public static string GetValue2(this When_extension_method_returns_value_type.Source source) { return "hello from extension"; } + public string BarSimpleName { get; set; } + public Guid Value { get; set; } } - public class When_extension_method_returns_value_type : AutoMapperSpecBase + protected override MapperConfiguration CreateConfiguration() => new(cfg => { - private Destination _destination; + cfg.IncludeSourceExtensionMethods(typeof(BarExtensions)); + cfg.CreateMap().ForMember(d=>d.Value, o=>o.MapFrom(s=>Guid.NewGuid())); + }); - public class Source - { - public int Value1 { get; set; } - } + [Fact] + public void Should_work() + { + Mapper.Map(new Foo()).BarSimpleName.ShouldBeNull(); + } +} - public struct Destination - { - public int Value1 { get; set; } - public string Value2 { get; set; } - } +public static class When_extension_method_returns_value_type_SourceExtensions +{ + public static string GetValue2(this When_extension_method_returns_value_type.Source source) { return "hello from extension"; } +} - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.IncludeSourceExtensionMethods(typeof(When_extension_method_returns_value_type_SourceExtensions)); - cfg.CreateMap(); - }); +public class When_extension_method_returns_value_type : AutoMapperSpecBase +{ + private Destination _destination; - protected override void Because_of() - { - _destination = Mapper.Map(new Source { Value1 = 3 }); - } + public class Source + { + public int Value1 { get; set; } + } - [Fact] - public void Should_use_extension_method() - { - _destination.Value2.ShouldBe("hello from extension"); - } + public struct Destination + { + public int Value1 { get; set; } + public string Value2 { get; set; } + } - [Fact] - public void Should_still_map_value_type() - { - _destination.Value1.ShouldBe(3); - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.IncludeSourceExtensionMethods(typeof(When_extension_method_returns_value_type_SourceExtensions)); + cfg.CreateMap(); + }); + + protected override void Because_of() + { + _destination = Mapper.Map(new Source { Value1 = 3 }); } - public static class When_extension_method_returns_object_SourceExtensions + [Fact] + public void Should_use_extension_method() { - public static When_extension_method_returns_object.Nested GetInsideThing(this When_extension_method_returns_object.Source source) - { - return new When_extension_method_returns_object.Nested { Property = source.Value1 + 10 }; - } + _destination.Value2.ShouldBe("hello from extension"); } - public class When_extension_method_returns_object : AutoMapperSpecBase + [Fact] + public void Should_still_map_value_type() { - private Destination _destination; + _destination.Value1.ShouldBe(3); + } +} - public class Source - { - public int Value1 { get; set; } - } +public static class When_extension_method_returns_object_SourceExtensions +{ + public static When_extension_method_returns_object.Nested GetInsideThing(this When_extension_method_returns_object.Source source) + { + return new When_extension_method_returns_object.Nested { Property = source.Value1 + 10 }; + } +} - public struct Destination - { - public int Value1 { get; set; } - public int InsideThingProperty { get; set; } - } +public class When_extension_method_returns_object : AutoMapperSpecBase +{ + private Destination _destination; - public class Nested - { - public int Property { get; set; } - } + public class Source + { + public int Value1 { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.IncludeSourceExtensionMethods(typeof(When_extension_method_returns_object_SourceExtensions)); - cfg.CreateMap(); - }); + public struct Destination + { + public int Value1 { get; set; } + public int InsideThingProperty { get; set; } + } - protected override void Because_of() - { - _destination = Mapper.Map(new Source { Value1 = 7 }); - } + public class Nested + { + public int Property { get; set; } + } - [Fact] - public void Should_flatten_using_extension_method() - { - _destination.InsideThingProperty.ShouldBe(17); - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.IncludeSourceExtensionMethods(typeof(When_extension_method_returns_object_SourceExtensions)); + cfg.CreateMap(); + }); - [Fact] - public void Should_still_map_value_type() - { - _destination.Value1.ShouldBe(7); - } + protected override void Because_of() + { + _destination = Mapper.Map(new Source { Value1 = 7 }); } - public class When_extension_contains_LINQ_methods : AutoMapperSpecBase + [Fact] + public void Should_flatten_using_extension_method() { - private Destination _destination; + _destination.InsideThingProperty.ShouldBe(17); + } - public class Source - { - public IEnumerable Values { get; set; } - } + [Fact] + public void Should_still_map_value_type() + { + _destination.Value1.ShouldBe(7); + } +} - public class Destination - { - public int ValuesCount { get; set; } - } +public class When_extension_contains_LINQ_methods : AutoMapperSpecBase +{ + private Destination _destination; - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - }); + public class Source + { + public IEnumerable Values { get; set; } + } - protected override void Because_of() - { - _destination = Mapper.Map(new Source { Values = Enumerable.Repeat(1, 10) }); - } + public class Destination + { + public int ValuesCount { get; set; } + } - [Fact] - public void Should_resolve_LINQ_method_automatically() - { - _destination.ValuesCount.ShouldBe(10); - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + }); + + protected override void Because_of() + { + _destination = Mapper.Map(new Source { Values = Enumerable.Repeat(1, 10) }); } - public class When_disabling_method_maping : NonValidatingSpecBase + [Fact] + public void Should_resolve_LINQ_method_automatically() { - public class Source - { - public IEnumerable Values { get; set; } - public int OtherValue() => 42; - public string StringValue; - } - public class Destination - { - public int ValuesCount { get; set; } - public int OtherValue { get; set; } - public string StringValue; - public string AnotherStringValue; - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.Internal().FieldMappingEnabled = false; - cfg.Internal().MethodMappingEnabled = false; - cfg.CreateMap(); - }); - [Fact] - public void Should_fail_validation() - { - new Action(AssertConfigurationIsValid).ShouldThrow().Errors[0] - .UnmappedPropertyNames.ShouldBe(new[] { "ValuesCount", "OtherValue" }); - Mapper.Map(new Source { StringValue = "42" }).StringValue.ShouldBeNull(); - } + _destination.ValuesCount.ShouldBe(10); } +} - public class When_a_static_method_has_first_parameter_null : AutoMapperSpecBase +public class When_disabling_method_maping : NonValidatingSpecBase +{ + public class Source { - class FirstName - { - public string Name; - } + public IEnumerable Values { get; set; } + public int OtherValue() => 42; + public string StringValue; + } + public class Destination + { + public int ValuesCount { get; set; } + public int OtherValue { get; set; } + public string StringValue; + public string AnotherStringValue; + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.Internal().FieldMappingEnabled = false; + cfg.Internal().MethodMappingEnabled = false; + cfg.CreateMap(); + }); + [Fact] + public void Should_fail_validation() + { + new Action(AssertConfigurationIsValid).ShouldThrow().Errors[0] + .UnmappedPropertyNames.ShouldBe(new[] { "ValuesCount", "OtherValue" }); + Mapper.Map(new Source { StringValue = "42" }).StringValue.ShouldBeNull(); + } +} - class LastName - { - public string Name; - } +public class When_a_static_method_has_first_parameter_null : AutoMapperSpecBase +{ + class FirstName + { + public string Name; + } - class FullName - { - public string Name; - } + class LastName + { + public string Name; + } - class CombinedNames - { - public FirstName First; + class FullName + { + public string Name; + } - public LastName Last; - } + class CombinedNames + { + public FirstName First; - protected override MapperConfiguration CreateConfiguration() => new(cfg=> - { - cfg.CreateMap() - .ForMember(dst => dst.Name, o => o.MapFrom(src => string.Concat(src.First.Name, src.Last.Name))); - }); + public LastName Last; + } - [Fact] - public void It_should_not_be_null_checked() + protected override MapperConfiguration CreateConfiguration() => new(cfg=> + { + cfg.CreateMap() + .ForMember(dst => dst.Name, o => o.MapFrom(src => string.Concat(src.First.Name, src.Last.Name))); + }); + + [Fact] + public void It_should_not_be_null_checked() + { + var combinedNames = new CombinedNames { - var combinedNames = new CombinedNames - { - First = new FirstName { Name = null }, - Last = new LastName { Name = "Doe" } - }; - var fullName = Mapper.Map(combinedNames); - fullName.Name.ShouldBe("Doe"); - } + First = new FirstName { Name = null }, + Last = new LastName { Name = "Doe" } + }; + var fullName = Mapper.Map(combinedNames); + fullName.Name.ShouldBe("Doe"); } } diff --git a/src/UnitTests/FillingExistingDestination.cs b/src/UnitTests/FillingExistingDestination.cs index 743fd07e1f..5b2beb9154 100644 --- a/src/UnitTests/FillingExistingDestination.cs +++ b/src/UnitTests/FillingExistingDestination.cs @@ -3,245 +3,244 @@ using Xunit; using System.Linq; -namespace AutoMapper.UnitTests +namespace AutoMapper.UnitTests; + +public class When_a_source_child_object_is_null : AutoMapperSpecBase { - public class When_a_source_child_object_is_null : AutoMapperSpecBase + public class Source { - public class Source - { - public Child Child { get; set; } - } + public Child Child { get; set; } + } - public class Destination - { - public Child Child { get; set; } = new Child(); - } + public class Destination + { + public Child Child { get; set; } = new Child(); + } - public class Child - { - public int Value { get; set; } - } + public class Child + { + public int Value { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().ForMember(d => d.Child, o => o.MapAtRuntime()); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().ForMember(d => d.Child, o => o.MapAtRuntime()); + }); - [Fact] - public void Should_overwrite_the_existing_child_destination() - { - var destination = new Destination(); - Mapper.Map(new Source(), destination); - destination.Child.ShouldBeNull(); - } + [Fact] + public void Should_overwrite_the_existing_child_destination() + { + var destination = new Destination(); + Mapper.Map(new Source(), destination); + destination.Child.ShouldBeNull(); } +} - public class When_the_destination_object_is_specified : AutoMapperSpecBase - { - private Source _source; - private Destination _originalDest; - private Destination _dest; +public class When_the_destination_object_is_specified : AutoMapperSpecBase +{ + private Source _source; + private Destination _originalDest; + private Destination _dest; - public class Source - { - public int Value { get; set; } - } + public class Source + { + public int Value { get; set; } + } - public class Destination - { - public int Value { get; set; } - } + public class Destination + { + public int Value { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); - }); + }); - protected override void Because_of() - { - _source = new Source - { - Value = 10, - }; - _originalDest = new Destination { Value = 1111 }; - _dest = Mapper.Map(_source, _originalDest); - } - - [Fact] - public void Should_do_the_translation() + protected override void Because_of() + { + _source = new Source { - _dest.Value.ShouldBe(10); - } + Value = 10, + }; + _originalDest = new Destination { Value = 1111 }; + _dest = Mapper.Map(_source, _originalDest); + } - [Fact] - public void Should_return_the_destination_object_that_was_passed_in() - { - _originalDest.ShouldBeSameAs(_dest); - } + [Fact] + public void Should_do_the_translation() + { + _dest.Value.ShouldBe(10); } - - public class When_the_destination_object_is_specified_with_child_objects : AutoMapperSpecBase + + [Fact] + public void Should_return_the_destination_object_that_was_passed_in() { - private Source _source; - private Destination _originalDest; - private Destination _dest; + _originalDest.ShouldBeSameAs(_dest); + } +} + +public class When_the_destination_object_is_specified_with_child_objects : AutoMapperSpecBase +{ + private Source _source; + private Destination _originalDest; + private Destination _dest; - public class Source - { - public int Value { get; set; } - public ChildSource Child { get; set; } - } + public class Source + { + public int Value { get; set; } + public ChildSource Child { get; set; } + } - public class Destination - { - public int Value { get; set; } - public string Name { get; set; } - public ChildDestination Child { get; set; } - } + public class Destination + { + public int Value { get; set; } + public string Name { get; set; } + public ChildDestination Child { get; set; } + } - public class ChildSource - { - public int Value { get; set; } - } + public class ChildSource + { + public int Value { get; set; } + } - public class ChildDestination - { - public int Value { get; set; } - public string Name { get; set; } - } + public class ChildDestination + { + public int Value { get; set; } + public string Name { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(MemberList.Source) - .ForMember(d => d.Child, opt => opt.UseDestinationValue()); - cfg.CreateMap(MemberList.Source) - .ForMember(d => d.Name, opt => opt.UseDestinationValue()); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(MemberList.Source) + .ForMember(d => d.Child, opt => opt.UseDestinationValue()); + cfg.CreateMap(MemberList.Source) + .ForMember(d => d.Name, opt => opt.UseDestinationValue()); + }); - protected override void Because_of() + protected override void Because_of() + { + _source = new Source { - _source = new Source + Value = 10, + Child = new ChildSource { - Value = 10, - Child = new ChildSource - { - Value = 20 - } - }; - _originalDest = new Destination + Value = 20 + } + }; + _originalDest = new Destination + { + Value = 1111, + Name = "foo", + Child = new ChildDestination { - Value = 1111, - Name = "foo", - Child = new ChildDestination - { - Name = "bar" - } - }; - _dest = Mapper.Map(_source, _originalDest); - } - - [Fact] - public void Should_do_the_translation() - { - _dest.Value.ShouldBe(10); - _dest.Child.Value.ShouldBe(20); - } + Name = "bar" + } + }; + _dest = Mapper.Map(_source, _originalDest); + } - [Fact] - public void Should_return_the_destination_object_that_was_passed_in() - { - _dest.Name.ShouldBe("foo"); - _dest.Child.Name.ShouldBe("bar"); - } + [Fact] + public void Should_do_the_translation() + { + _dest.Value.ShouldBe(10); + _dest.Child.Value.ShouldBe(20); } - public class When_the_destination_object_has_child_objects : AutoMapperSpecBase + [Fact] + public void Should_return_the_destination_object_that_was_passed_in() { - private Source _source; - private Destination _originalDest; - private ChildDestination _originalDestChild; - private Destination _dest; + _dest.Name.ShouldBe("foo"); + _dest.Child.Name.ShouldBe("bar"); + } +} - public class Source - { - public ChildSource Child { get; set; } - } +public class When_the_destination_object_has_child_objects : AutoMapperSpecBase +{ + private Source _source; + private Destination _originalDest; + private ChildDestination _originalDestChild; + private Destination _dest; - public class Destination - { - public ChildDestination Child { get; set; } - } + public class Source + { + public ChildSource Child { get; set; } + } - public class ChildSource - { - public int Value { get; set; } - } + public class Destination + { + public ChildDestination Child { get; set; } + } - public class ChildDestination - { - public int Value { get; set; } - } + public class ChildSource + { + public int Value { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - cfg.CreateMap(); - }); + public class ChildDestination + { + public int Value { get; set; } + } - protected override void Because_of() + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + cfg.CreateMap(); + }); + + protected override void Because_of() + { + _source = new Source { - _source = new Source + Child = new ChildSource { - Child = new ChildSource - { - Value = 20 - } - }; - _originalDestChild = new ChildDestination - { - Value = 10 - }; - _originalDest = new Destination - { - Child = _originalDestChild - }; - _dest = Mapper.Map(_source, _originalDest); - } + Value = 20 + } + }; + _originalDestChild = new ChildDestination + { + Value = 10 + }; + _originalDest = new Destination + { + Child = _originalDestChild + }; + _dest = Mapper.Map(_source, _originalDest); + } - [Fact] - public void Should_return_the_destination_object_that_was_passed_in() - { - _dest.ShouldBeSameAs(_originalDest); - _dest.Child.ShouldBeSameAs(_originalDestChild); - _dest.Child.Value.ShouldBe(20); - } + [Fact] + public void Should_return_the_destination_object_that_was_passed_in() + { + _dest.ShouldBeSameAs(_originalDest); + _dest.Child.ShouldBeSameAs(_originalDestChild); + _dest.Child.Value.ShouldBe(20); } +} - public class When_the_destination_object_is_specified_and_you_are_converting_an_enum : NonValidatingSpecBase - { - private string _result; +public class When_the_destination_object_is_specified_and_you_are_converting_an_enum : NonValidatingSpecBase +{ + private string _result; - public enum SomeEnum - { - One, - Two, - Three - } + public enum SomeEnum + { + One, + Two, + Three + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => { }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => { }); - protected override void Because_of() - { - _result = Mapper.Map(SomeEnum.Two, "test"); - } + protected override void Because_of() + { + _result = Mapper.Map(SomeEnum.Two, "test"); + } - [Fact] - public void Should_return_the_enum_as_a_string() - { - _result.ShouldBe("Two"); - } + [Fact] + public void Should_return_the_enum_as_a_string() + { + _result.ShouldBe("Two"); } } \ No newline at end of file diff --git a/src/UnitTests/ForAllMaps.cs b/src/UnitTests/ForAllMaps.cs index 36b866705e..a6bf37cf6e 100644 --- a/src/UnitTests/ForAllMaps.cs +++ b/src/UnitTests/ForAllMaps.cs @@ -2,98 +2,97 @@ using Shouldly; using System; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class ForAllMaps : AutoMapperSpecBase { - public class ForAllMaps : AutoMapperSpecBase - { - private Destination _destination; - private Destination1 _destination1; - private Destination2 _destination2; + private Destination _destination; + private Destination1 _destination1; + private Destination2 _destination2; - class Source - { - public int Number { get; set; } - } - class Destination - { - public int Number { get; set; } - } + class Source + { + public int Number { get; set; } + } + class Destination + { + public int Number { get; set; } + } - class Source1 - { - public int Number { get; set; } - } - class Destination1 - { - public int Number { get; set; } - } + class Source1 + { + public int Number { get; set; } + } + class Destination1 + { + public int Number { get; set; } + } - class Source2 - { - public int Number { get; set; } - } - class Destination2 - { - public int Number { get; set; } - } + class Source2 + { + public int Number { get; set; } + } + class Destination2 + { + public int Number { get; set; } + } - public class MinusOneResolver : IValueResolver + public class MinusOneResolver : IValueResolver + { + public object Resolve(object source, object dest, object destMember, ResolutionContext context) { - public object Resolve(object source, object dest, object destMember, ResolutionContext context) - { - return -1; - } + return -1; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - cfg.CreateMap(); - cfg.CreateMap(); - cfg.ForAllMaps((tm, map) => map.ForMember("Number", o => o.MapFrom())); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + cfg.CreateMap(); + cfg.CreateMap(); + cfg.ForAllMaps((tm, map) => map.ForMember("Number", o => o.MapFrom())); + }); - protected override void Because_of() - { - _destination = Mapper.Map(new Source()); - _destination1 = Mapper.Map(new Source1()); - _destination2 = Mapper.Map(new Source2()); - } + protected override void Because_of() + { + _destination = Mapper.Map(new Source()); + _destination1 = Mapper.Map(new Source1()); + _destination2 = Mapper.Map(new Source2()); + } - [Fact] - public void Should_configure_all_maps() - { - _destination.Number.ShouldBe(-1); - _destination1.Number.ShouldBe(-1); - _destination2.Number.ShouldBe(-1); - } + [Fact] + public void Should_configure_all_maps() + { + _destination.Number.ShouldBe(-1); + _destination1.Number.ShouldBe(-1); + _destination2.Number.ShouldBe(-1); } - public class ForAllMapsWithConstructors : AutoMapperSpecBase +} +public class ForAllMapsWithConstructors : AutoMapperSpecBase +{ + class Source { - class Source - { - } - class Destination - { - public Destination(int first, int second) - { - First = first; - Second = second; - } - public int First { get; } - public int Second { get; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg=> - { - cfg.ForAllMaps((_, c) => c.ForCtorParam("second", o => o.MapFrom(s => 2))); - cfg.CreateMap().ForCtorParam("first", o => o.MapFrom(s => 1)); - }); - [Fact] - public void Should_map_ok() + } + class Destination + { + public Destination(int first, int second) { - var result = Map(new Source()); - result.First.ShouldBe(1); - result.Second.ShouldBe(2); + First = first; + Second = second; } + public int First { get; } + public int Second { get; } + } + protected override MapperConfiguration CreateConfiguration() => new(cfg=> + { + cfg.ForAllMaps((_, c) => c.ForCtorParam("second", o => o.MapFrom(s => 2))); + cfg.CreateMap().ForCtorParam("first", o => o.MapFrom(s => 1)); + }); + [Fact] + public void Should_map_ok() + { + var result = Map(new Source()); + result.First.ShouldBe(1); + result.Second.ShouldBe(2); } } \ No newline at end of file diff --git a/src/UnitTests/ForAllMembers.cs b/src/UnitTests/ForAllMembers.cs index 22f640a3fd..97ad1ee7c1 100644 --- a/src/UnitTests/ForAllMembers.cs +++ b/src/UnitTests/ForAllMembers.cs @@ -2,85 +2,84 @@ using Shouldly; using Xunit; -namespace AutoMapper.UnitTests.ForAllMembers +namespace AutoMapper.UnitTests.ForAllMembers; + +using Internal; +public class When_conditionally_applying_a_resolver_globally : AutoMapperSpecBase { - using Internal; - public class When_conditionally_applying_a_resolver_globally : AutoMapperSpecBase + public class Source { - public class Source - { - public DateTime SomeDate { get; set; } - public DateTime OtherDate { get; set; } - } + public DateTime SomeDate { get; set; } + public DateTime OtherDate { get; set; } + } - public class Dest - { - public DateTime SomeDate { get; set; } - public DateTime OtherDate { get; set; } - } + public class Dest + { + public DateTime SomeDate { get; set; } + public DateTime OtherDate { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.ForAllPropertyMaps(pm => pm.DestinationName.StartsWith("Other"), - (pm, opt) => opt.MapFrom(typeof(ConditionalValueResolver), pm.SourceMember.Name)); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.ForAllPropertyMaps(pm => pm.DestinationName.StartsWith("Other"), + (pm, opt) => opt.MapFrom(typeof(ConditionalValueResolver), pm.SourceMember.Name)); - cfg.CreateMap(); - }); + cfg.CreateMap(); + }); - public class ConditionalValueResolver : IMemberValueResolver + public class ConditionalValueResolver : IMemberValueResolver + { + public DateTime Resolve(object s, object d, DateTime source, DateTime destination, ResolutionContext context) { - public DateTime Resolve(object s, object d, DateTime source, DateTime destination, ResolutionContext context) - { - return source.AddDays(1); - } + return source.AddDays(1); } + } - [Fact] - public void Should_use_resolver() + [Fact] + public void Should_use_resolver() + { + var source = new Source { - var source = new Source - { - SomeDate = new DateTime(2000, 1, 1), - OtherDate = new DateTime(2000, 1, 1), - }; - var dest = Mapper.Map(source); + SomeDate = new DateTime(2000, 1, 1), + OtherDate = new DateTime(2000, 1, 1), + }; + var dest = Mapper.Map(source); - dest.SomeDate.ShouldBe(source.SomeDate); - dest.OtherDate.ShouldBe(source.OtherDate.AddDays(1)); - } + dest.SomeDate.ShouldBe(source.SomeDate); + dest.OtherDate.ShouldBe(source.OtherDate.AddDays(1)); } - public class When_conditionally_applying_a_resolver_per_profile : AutoMapperSpecBase +} +public class When_conditionally_applying_a_resolver_per_profile : AutoMapperSpecBase +{ + public class Source { - public class Source - { - public DateTime SomeDate { get; set; } - public DateTime OtherDate { get; set; } - } - public class Dest - { - public DateTime SomeDate { get; set; } - public DateTime OtherDate { get; set; } - } - class MyProfile : Profile - { - public MyProfile() - { - CreateMap(); - this.Internal().ForAllPropertyMaps(pm => pm.DestinationName.StartsWith("Other"), (pm, opt) => opt.MapFrom(typeof(ConditionalValueResolver), pm.SourceMember.Name)); - } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.AddProfile()); - public class ConditionalValueResolver : IMemberValueResolver - { - public DateTime Resolve(object s, object d, DateTime source, DateTime destination, ResolutionContext context) => source.AddDays(1); - } - [Fact] - public void Should_use_resolver() + public DateTime SomeDate { get; set; } + public DateTime OtherDate { get; set; } + } + public class Dest + { + public DateTime SomeDate { get; set; } + public DateTime OtherDate { get; set; } + } + class MyProfile : Profile + { + public MyProfile() { - var source = new Source { SomeDate = new DateTime(2000, 1, 1), OtherDate = new DateTime(2000, 1, 1) }; - var dest = Mapper.Map(source); - dest.SomeDate.ShouldBe(source.SomeDate); - dest.OtherDate.ShouldBe(source.OtherDate.AddDays(1)); + CreateMap(); + this.Internal().ForAllPropertyMaps(pm => pm.DestinationName.StartsWith("Other"), (pm, opt) => opt.MapFrom(typeof(ConditionalValueResolver), pm.SourceMember.Name)); } } + protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.AddProfile()); + public class ConditionalValueResolver : IMemberValueResolver + { + public DateTime Resolve(object s, object d, DateTime source, DateTime destination, ResolutionContext context) => source.AddDays(1); + } + [Fact] + public void Should_use_resolver() + { + var source = new Source { SomeDate = new DateTime(2000, 1, 1), OtherDate = new DateTime(2000, 1, 1) }; + var dest = Mapper.Map(source); + dest.SomeDate.ShouldBe(source.SomeDate); + dest.OtherDate.ShouldBe(source.OtherDate.AddDays(1)); + } } \ No newline at end of file diff --git a/src/UnitTests/ForPath.cs b/src/UnitTests/ForPath.cs index d18e817fcf..a9e013afaf 100644 --- a/src/UnitTests/ForPath.cs +++ b/src/UnitTests/ForPath.cs @@ -5,408 +5,407 @@ using Shouldly; using Xunit; -namespace AutoMapper.UnitTests +namespace AutoMapper.UnitTests; + +public class InheritForPath : AutoMapperSpecBase { - public class InheritForPath : AutoMapperSpecBase + public class RootModel { - public class RootModel - { - public int ID { get; set; } - public string Title { get; set; } - public NestedModel Nested { get; set; } - } - - public class NestedModel - { - public int NestedID { get; set; } - public string NestedTitle { get; set; } - public string NestedTitle2 { get; set; } - } - - public class DerivedModel : RootModel - { - public string DescendantField { get; set; } - } - // destination types - public class DataModel - { - public int ID { get; set; } - public string Title { get; set; } - - public int OtherID { get; set; } - public string Title2 { get; set; } - } + public int ID { get; set; } + public string Title { get; set; } + public NestedModel Nested { get; set; } + } - public class DerivedDataModel : DataModel - { - public string DescendantField { get; set; } - } + public class NestedModel + { + public int NestedID { get; set; } + public string NestedTitle { get; set; } + public string NestedTitle2 { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg=> - { - cfg.CreateMap() - .ForMember(dest => dest.OtherID, opt => opt.MapFrom(src => src.Nested.NestedID)) - .ForMember(dest => dest.Title, opt => opt.MapFrom(src => src.Nested.NestedTitle)) - .ForMember(dest => dest.Title2, opt => opt.MapFrom(src => src.Nested.NestedTitle2)) - .ReverseMap() - .ForPath(d=>d.Nested.NestedTitle2, o=>o.Ignore()); - - cfg.CreateMap() - .IncludeBase().ReverseMap() - .ForPath(d=>d.Nested.NestedTitle, o=>o.Ignore()) - .ForPath(d => d.Nested.NestedTitle2, opt => opt.MapFrom(src => src.Title2)); - }); + public class DerivedModel : RootModel + { + public string DescendantField { get; set; } + } + // destination types + public class DataModel + { + public int ID { get; set; } + public string Title { get; set; } - [Fact] - public void Should_work() - { - var source = new DerivedDataModel() { OtherID = 2, Title2 = "nested test", ID = 1, Title = "test", DescendantField = "descendant field" }; - var destination = Mapper.Map(source); - destination.Nested.NestedID.ShouldBe(2); - destination.Nested.NestedTitle.ShouldBeNull(); - destination.Nested.NestedTitle2.ShouldBe("nested test"); - } + public int OtherID { get; set; } + public string Title2 { get; set; } } - public class ForPath : AutoMapperSpecBase + public class DerivedDataModel : DataModel { - public class Order - { - public CustomerHolder CustomerHolder { get; set; } - } + public string DescendantField { get; set; } + } - public class CustomerHolder - { - public Customer Customer { get; set; } - } + protected override MapperConfiguration CreateConfiguration() => new(cfg=> + { + cfg.CreateMap() + .ForMember(dest => dest.OtherID, opt => opt.MapFrom(src => src.Nested.NestedID)) + .ForMember(dest => dest.Title, opt => opt.MapFrom(src => src.Nested.NestedTitle)) + .ForMember(dest => dest.Title2, opt => opt.MapFrom(src => src.Nested.NestedTitle2)) + .ReverseMap() + .ForPath(d=>d.Nested.NestedTitle2, o=>o.Ignore()); + + cfg.CreateMap() + .IncludeBase().ReverseMap() + .ForPath(d=>d.Nested.NestedTitle, o=>o.Ignore()) + .ForPath(d => d.Nested.NestedTitle2, opt => opt.MapFrom(src => src.Title2)); + }); + + [Fact] + public void Should_work() + { + var source = new DerivedDataModel() { OtherID = 2, Title2 = "nested test", ID = 1, Title = "test", DescendantField = "descendant field" }; + var destination = Mapper.Map(source); + destination.Nested.NestedID.ShouldBe(2); + destination.Nested.NestedTitle.ShouldBeNull(); + destination.Nested.NestedTitle2.ShouldBe("nested test"); + } +} - public class Customer - { - public string Name { get; set; } - public decimal Total { get; set; } - } +public class ForPath : AutoMapperSpecBase +{ + public class Order + { + public CustomerHolder CustomerHolder { get; set; } + } - public class OrderDto - { - public string CustomerName { get; set; } - public decimal Total { get; set; } - } + public class CustomerHolder + { + public Customer Customer { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ForPath(o=>o.CustomerHolder.Customer.Name, o=>o.MapFrom(s=>s.CustomerName)) - .ForPath(o => o.CustomerHolder.Customer.Total, o => o.MapFrom(s => s.Total)); - }); + public class Customer + { + public string Name { get; set; } + public decimal Total { get; set; } + } - [Fact] - public void Should_unflatten() - { - var dto = new OrderDto { CustomerName = "George Costanza", Total = 74.85m }; - var model = Mapper.Map(dto); - model.CustomerHolder.Customer.Name.ShouldBe("George Costanza"); - model.CustomerHolder.Customer.Total.ShouldBe(74.85m); - } + public class OrderDto + { + public string CustomerName { get; set; } + public decimal Total { get; set; } } - public class ForPathWithoutSettersForSubObjects : AutoMapperSpecBase + protected override MapperConfiguration CreateConfiguration() => new(cfg => { - public class Order - { - public CustomerHolder CustomerHolder { get; set; } - } + cfg.CreateMap() + .ForPath(o=>o.CustomerHolder.Customer.Name, o=>o.MapFrom(s=>s.CustomerName)) + .ForPath(o => o.CustomerHolder.Customer.Total, o => o.MapFrom(s => s.Total)); + }); - public class CustomerHolder - { - public Customer Customer { get; } - } + [Fact] + public void Should_unflatten() + { + var dto = new OrderDto { CustomerName = "George Costanza", Total = 74.85m }; + var model = Mapper.Map(dto); + model.CustomerHolder.Customer.Name.ShouldBe("George Costanza"); + model.CustomerHolder.Customer.Total.ShouldBe(74.85m); + } +} - public class Customer - { - public string Name { get; set; } - public decimal Total { get; set; } - } +public class ForPathWithoutSettersForSubObjects : AutoMapperSpecBase +{ + public class Order + { + public CustomerHolder CustomerHolder { get; set; } + } - public class OrderDto - { - public string CustomerName { get; set; } - public decimal Total { get; set; } - } + public class CustomerHolder + { + public Customer Customer { get; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ForPath(o => o.CustomerHolder.Customer.Name, o => o.MapFrom(s => s.CustomerName)) - .ForPath(o => o.CustomerHolder.Customer.Total, o => o.MapFrom(s => s.Total)); - }); + public class Customer + { + public string Name { get; set; } + public decimal Total { get; set; } + } - [Fact] - public void Should_unflatten() - { - new Action(() => Mapper.Map(new OrderDto())).ShouldThrowException(ex => - ex.InnerException?.Message.ShouldBe("typeMapDestination.CustomerHolder.Customer cannot be null because it's used by ForPath.")); - } + public class OrderDto + { + public string CustomerName { get; set; } + public decimal Total { get; set; } } - public class ForPathWithoutSettersShouldBehaveAsForMember : AutoMapperSpecBase + protected override MapperConfiguration CreateConfiguration() => new(cfg => { - public class Order - { - public CustomerHolder CustomerHolder { get; set; } - public int Value { get; } - } + cfg.CreateMap() + .ForPath(o => o.CustomerHolder.Customer.Name, o => o.MapFrom(s => s.CustomerName)) + .ForPath(o => o.CustomerHolder.Customer.Total, o => o.MapFrom(s => s.Total)); + }); - public class CustomerHolder - { - public Customer Customer { get; set; } - } + [Fact] + public void Should_unflatten() + { + new Action(() => Mapper.Map(new OrderDto())).ShouldThrowException(ex => + ex.InnerException?.Message.ShouldBe("typeMapDestination.CustomerHolder.Customer cannot be null because it's used by ForPath.")); + } +} - public class Customer - { - public string Name { get; } - public decimal Total { get; } - } +public class ForPathWithoutSettersShouldBehaveAsForMember : AutoMapperSpecBase +{ + public class Order + { + public CustomerHolder CustomerHolder { get; set; } + public int Value { get; } + } - public class OrderDto - { - public string CustomerName { get; set; } - public decimal Total { get; set; } - } + public class CustomerHolder + { + public Customer Customer { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ForMember(o=>o.Value, o=>o.MapFrom(src => 9)) - .ForPath(o => o.CustomerHolder.Customer.Name, o => o.MapFrom(s => s.CustomerName)) - .ForPath(o => o.CustomerHolder.Customer.Total, o => o.MapFrom(s => s.Total)); - }); + public class Customer + { + public string Name { get; } + public decimal Total { get; } + } - [Fact] - public void Should_unflatten() - { - var dto = new OrderDto { CustomerName = "George Costanza", Total = 74.85m }; - var model = Mapper.Map(dto); - model.Value.ShouldBe(0); - model.CustomerHolder.Customer.Name.ShouldBeNull(); - model.CustomerHolder.Customer.Total.ShouldBe(0m); - } + public class OrderDto + { + public string CustomerName { get; set; } + public decimal Total { get; set; } } - public class ForPathWithIgnoreShouldNotSetValue : AutoMapperSpecBase + protected override MapperConfiguration CreateConfiguration() => new(cfg => { - public partial class TimesheetModel - { - public int ID { get; set; } - public DateTime? StartDate { get; set; } - public int? Contact { get; set; } - public ContactModel ContactNavigation { get; set; } - } + cfg.CreateMap() + .ForMember(o=>o.Value, o=>o.MapFrom(src => 9)) + .ForPath(o => o.CustomerHolder.Customer.Name, o => o.MapFrom(s => s.CustomerName)) + .ForPath(o => o.CustomerHolder.Customer.Total, o => o.MapFrom(s => s.Total)); + }); + + [Fact] + public void Should_unflatten() + { + var dto = new OrderDto { CustomerName = "George Costanza", Total = 74.85m }; + var model = Mapper.Map(dto); + model.Value.ShouldBe(0); + model.CustomerHolder.Customer.Name.ShouldBeNull(); + model.CustomerHolder.Customer.Total.ShouldBe(0m); + } +} - public class TimesheetViewModel - { - public int? Contact { get; set; } - public DateTime? StartDate { get; set; } - } +public class ForPathWithIgnoreShouldNotSetValue : AutoMapperSpecBase +{ + public partial class TimesheetModel + { + public int ID { get; set; } + public DateTime? StartDate { get; set; } + public int? Contact { get; set; } + public ContactModel ContactNavigation { get; set; } + } - public class ContactModel - { - public int Id { get; set; } - } + public class TimesheetViewModel + { + public int? Contact { get; set; } + public DateTime? StartDate { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ForMember(d => d.Contact, o => o.MapFrom(s => s.ContactNavigation.Id)) - .ReverseMap() - .ForPath(s => s.ContactNavigation.Id, opt => opt.Ignore()); - }); + public class ContactModel + { + public int Id { get; set; } + } - [Fact] - public void Should_not_set_value() + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .ForMember(d => d.Contact, o => o.MapFrom(s => s.ContactNavigation.Id)) + .ReverseMap() + .ForPath(s => s.ContactNavigation.Id, opt => opt.Ignore()); + }); + + [Fact] + public void Should_not_set_value() + { + var source = new TimesheetModel { - var source = new TimesheetModel + Contact = 6, + ContactNavigation = new ContactModel { - Contact = 6, - ContactNavigation = new ContactModel - { - Id = 5 - } - }; - var dest = new TimesheetViewModel - { - Contact = 10 - }; - Mapper.Map(dest, source); + Id = 5 + } + }; + var dest = new TimesheetViewModel + { + Contact = 10 + }; + Mapper.Map(dest, source); - source.ContactNavigation.Id.ShouldBe(5); - } + source.ContactNavigation.Id.ShouldBe(5); } +} - public class ForPathWithNullExpressionShouldFail +public class ForPathWithNullExpressionShouldFail +{ + public class DestinationModel { - public class DestinationModel - { - public string Name { get; set; } - } + public string Name { get; set; } + } - public class SourceModel - { - public string Name { get; set; } - } - - [Fact] - public void Should_throw_exception() + public class SourceModel + { + public string Name { get; set; } + } + + [Fact] + public void Should_throw_exception() + { + Assert.Throws(() => { - Assert.Throws(() => + var cfg = new MapperConfiguration(config => { - var cfg = new MapperConfiguration(config => + Assert.Throws(() => { - Assert.Throws(() => - { - config.CreateMap() - .ForPath(sourceModel => sourceModel.Name, opts => opts.MapFrom(null)); - }); + config.CreateMap() + .ForPath(sourceModel => sourceModel.Name, opts => opts.MapFrom(null)); }); }); - } + }); } +} - public class ForPathWithPrivateSetters : AutoMapperSpecBase +public class ForPathWithPrivateSetters : AutoMapperSpecBase +{ + public class Order { - public class Order - { - public CustomerHolder CustomerHolder { get; private set; } - } + public CustomerHolder CustomerHolder { get; private set; } + } - public class CustomerHolder - { - public Customer Customer { get; private set; } - } + public class CustomerHolder + { + public Customer Customer { get; private set; } + } - public class Customer - { - public string Name { get; private set; } - public decimal Total { get; private set; } - } + public class Customer + { + public string Name { get; private set; } + public decimal Total { get; private set; } + } - public class OrderDto - { - public string CustomerName { get; set; } - public decimal Total { get; set; } - } + public class OrderDto + { + public string CustomerName { get; set; } + public decimal Total { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ForPath(o => o.CustomerHolder.Customer.Name, o => o.MapFrom(s => s.CustomerName)) - .ForPath(o => o.CustomerHolder.Customer.Total, o => o.MapFrom(s => s.Total)); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .ForPath(o => o.CustomerHolder.Customer.Name, o => o.MapFrom(s => s.CustomerName)) + .ForPath(o => o.CustomerHolder.Customer.Total, o => o.MapFrom(s => s.Total)); + }); - [Fact] - public void Should_unflatten() - { - var dto = new OrderDto { CustomerName = "George Costanza", Total = 74.85m }; - var model = Mapper.Map(dto); - model.CustomerHolder.Customer.Name.ShouldBe("George Costanza"); - model.CustomerHolder.Customer.Total.ShouldBe(74.85m); - } + [Fact] + public void Should_unflatten() + { + var dto = new OrderDto { CustomerName = "George Costanza", Total = 74.85m }; + var model = Mapper.Map(dto); + model.CustomerHolder.Customer.Name.ShouldBe("George Costanza"); + model.CustomerHolder.Customer.Total.ShouldBe(74.85m); } +} - public class ForPathWithValueTypesAndFields : AutoMapperSpecBase +public class ForPathWithValueTypesAndFields : AutoMapperSpecBase +{ + public struct Order { - public struct Order - { - public CustomerHolder CustomerHolder; - } + public CustomerHolder CustomerHolder; + } - public struct CustomerHolder - { - public Customer Customer; - } + public struct CustomerHolder + { + public Customer Customer; + } - public struct Customer - { - public string Name; - public decimal Total; - } + public struct Customer + { + public string Name; + public decimal Total; + } - public struct OrderDto - { - public string CustomerName; - public decimal Total; - } + public struct OrderDto + { + public string CustomerName; + public decimal Total; + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ForPath(o => o.CustomerHolder.Customer.Name, o => o.MapFrom(s => s.CustomerName)) - .ForPath(o => o.CustomerHolder.Customer.Total, o => o.MapFrom(s => s.Total)); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .ForPath(o => o.CustomerHolder.Customer.Name, o => o.MapFrom(s => s.CustomerName)) + .ForPath(o => o.CustomerHolder.Customer.Total, o => o.MapFrom(s => s.Total)); + }); - [Fact] - public void Should_unflatten() - { - var dto = new OrderDto { CustomerName = "George Costanza", Total = 74.85m }; - var model = Mapper.Map(dto); - model.CustomerHolder.Customer.Name.ShouldBe("George Costanza"); - model.CustomerHolder.Customer.Total.ShouldBe(74.85m); - } + [Fact] + public void Should_unflatten() + { + var dto = new OrderDto { CustomerName = "George Costanza", Total = 74.85m }; + var model = Mapper.Map(dto); + model.CustomerHolder.Customer.Name.ShouldBe("George Costanza"); + model.CustomerHolder.Customer.Total.ShouldBe(74.85m); } +} - public class ForPathWithConditions : AutoMapperSpecBase +public class ForPathWithConditions : AutoMapperSpecBase +{ + public class Order { - public class Order - { - public CustomerHolder CustomerHolder { get; set; } - } + public CustomerHolder CustomerHolder { get; set; } + } - public class CustomerHolder - { - public Customer Customer { get; set; } - } + public class CustomerHolder + { + public Customer Customer { get; set; } + } - public class Customer - { - public string Name { get; set; } - public decimal Total { get; set; } - public int Value { get; set; } - } + public class Customer + { + public string Name { get; set; } + public decimal Total { get; set; } + public int Value { get; set; } + } - public class OrderDto - { - public string CustomerName { get; set; } - public decimal Total { get; set; } - public int Value { get; set; } - } + public class OrderDto + { + public string CustomerName { get; set; } + public decimal Total { get; set; } + public int Value { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ForPath(o => o.CustomerHolder.Customer.Name, o => - { - o.Condition(c => !c.SourceMember.StartsWith("George")); - o.MapFrom(s => s.CustomerName); - }) - .ForPath(o => o.CustomerHolder.Customer.Total, o => - { - o.Condition(c => c.Source.Total < 50); - o.MapFrom(s => s.Total); - }) - .ForPath(o => o.CustomerHolder.Customer.Value, o => - { - o.Condition(c => c.Destination.CustomerHolder.Customer.Value == 0); - o.MapFrom(s => s.Value); - }); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .ForPath(o => o.CustomerHolder.Customer.Name, o => + { + o.Condition(c => !c.SourceMember.StartsWith("George")); + o.MapFrom(s => s.CustomerName); + }) + .ForPath(o => o.CustomerHolder.Customer.Total, o => + { + o.Condition(c => c.Source.Total < 50); + o.MapFrom(s => s.Total); + }) + .ForPath(o => o.CustomerHolder.Customer.Value, o => + { + o.Condition(c => c.Destination.CustomerHolder.Customer.Value == 0); + o.MapFrom(s => s.Value); + }); + }); - [Fact] - public void Should_unflatten() - { - var dto = new OrderDto { CustomerName = "George Costanza", Total = 74.85m, Value = 100 }; - var model = Mapper.Map(dto); - model.CustomerHolder.Customer.Name.ShouldBeNull(); - model.CustomerHolder.Customer.Total.ShouldBe(0); - model.CustomerHolder.Customer.Value.ShouldBe(100); - } + [Fact] + public void Should_unflatten() + { + var dto = new OrderDto { CustomerName = "George Costanza", Total = 74.85m, Value = 100 }; + var model = Mapper.Map(dto); + model.CustomerHolder.Customer.Name.ShouldBeNull(); + model.CustomerHolder.Customer.Total.ShouldBe(0); + model.CustomerHolder.Customer.Value.ShouldBe(100); } } diff --git a/src/UnitTests/IMappingExpression/ForCtorParam.cs b/src/UnitTests/IMappingExpression/ForCtorParam.cs index fd3f303392..5d13f98778 100644 --- a/src/UnitTests/IMappingExpression/ForCtorParam.cs +++ b/src/UnitTests/IMappingExpression/ForCtorParam.cs @@ -4,167 +4,166 @@ using System.Linq; using System.Collections.Generic; -namespace AutoMapper.UnitTests +namespace AutoMapper.UnitTests; + +public class ForCtorParam_MapFrom_String : AutoMapperSpecBase { - public class ForCtorParam_MapFrom_String : AutoMapperSpecBase + public class Destination { - public class Destination - { - public Destination(string key1, string value1) - { - Key = key1; - Value = value1; - } - - public string Key { get; } - public string Value { get; } - } - protected override MapperConfiguration CreateConfiguration() => new(c => - c.CreateMap(typeof(KeyValuePair<,>), typeof(Destination)) - .ForCtorParam("value1", o => o.MapFrom("Value")) - .ForCtorParam("key1", o => o.MapFrom("Key"))); - [Fact] - public void Should_map_ok() + public Destination(string key1, string value1) { - var destination = Map(new KeyValuePair(1,2)); - destination.Key.ShouldBe("1"); - destination.Value.ShouldBe("2"); + Key = key1; + Value = value1; } + + public string Key { get; } + public string Value { get; } } - public class ForCtorParam_MapFrom_ProjectTo : AutoMapperSpecBase + protected override MapperConfiguration CreateConfiguration() => new(c => + c.CreateMap(typeof(KeyValuePair<,>), typeof(Destination)) + .ForCtorParam("value1", o => o.MapFrom("Value")) + .ForCtorParam("key1", o => o.MapFrom("Key"))); + [Fact] + public void Should_map_ok() { - public class Source - { - public string Value1 { get; set; } - } - public class Destination - { - public Destination(string value) => Value = value; - public string Value { get; } - } - protected override MapperConfiguration CreateConfiguration() => new(c => c.CreateProjection().ForCtorParam("value", o => o.MapFrom(s => s.Value1))); - [Fact] - public void Should_map_ok() - { - var destination = ProjectTo(new[] { new Source { Value1 = "Core" }}.AsQueryable()).Single(); - destination.Value.ShouldBe("Core"); - } + var destination = Map(new KeyValuePair(1,2)); + destination.Key.ShouldBe("1"); + destination.Value.ShouldBe("2"); } - public class When_configuring__non_generic_ctor_param_members : AutoMapperSpecBase +} +public class ForCtorParam_MapFrom_ProjectTo : AutoMapperSpecBase +{ + public class Source { - public class Source - { - public int Value { get; set; } - } + public string Value1 { get; set; } + } + public class Destination + { + public Destination(string value) => Value = value; + public string Value { get; } + } + protected override MapperConfiguration CreateConfiguration() => new(c => c.CreateProjection().ForCtorParam("value", o => o.MapFrom(s => s.Value1))); + [Fact] + public void Should_map_ok() + { + var destination = ProjectTo(new[] { new Source { Value1 = "Core" }}.AsQueryable()).Single(); + destination.Value.ShouldBe("Core"); + } +} +public class When_configuring__non_generic_ctor_param_members : AutoMapperSpecBase +{ + public class Source + { + public int Value { get; set; } + } - public class Dest + public class Dest + { + public Dest(int thing) { - public Dest(int thing) - { - Value1 = thing; - } - - public int Value1 { get; } + Value1 = thing; } - public class DestWithNoConstructor - { - public int Value1 { get; set; } - } + public int Value1 { get; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(typeof(Source), typeof(Dest)) - .ForCtorParam("thing", opt => opt.MapFrom(src => ((Source)src).Value)); - }); + public class DestWithNoConstructor + { + public int Value1 { get; set; } + } - [Fact] - public void Should_redirect_value() - { - var dest = Mapper.Map(new Source { Value = 5 }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(typeof(Source), typeof(Dest)) + .ForCtorParam("thing", opt => opt.MapFrom(src => ((Source)src).Value)); + }); - dest.Value1.ShouldBe(5); - } + [Fact] + public void Should_redirect_value() + { + var dest = Mapper.Map(new Source { Value = 5 }); - [Fact] - public void Should_resolve_using_custom_func() - { - var mapper = new MapperConfiguration( - cfg => cfg.CreateMap().ForCtorParam("thing", opt => opt.MapFrom((src, ctxt) => - { - var rev = src.Value + 3; - return rev; - }))) - .CreateMapper(); + dest.Value1.ShouldBe(5); + } - var dest = mapper.Map(new Source { Value = 5 }); + [Fact] + public void Should_resolve_using_custom_func() + { + var mapper = new MapperConfiguration( + cfg => cfg.CreateMap().ForCtorParam("thing", opt => opt.MapFrom((src, ctxt) => + { + var rev = src.Value + 3; + return rev; + }))) + .CreateMapper(); - dest.Value1.ShouldBe(8); - } + var dest = mapper.Map(new Source { Value = 5 }); - [Fact] - public void Should_resolve_using_custom_func_with_correct_ResolutionContext() - { - const string itemKey = "key"; - var mapper = new MapperConfiguration( - cfg => cfg.CreateMap().ForCtorParam("thing", opt => - opt.MapFrom((src, ctx) => ctx.Items[itemKey]) - )) - .CreateMapper(); + dest.Value1.ShouldBe(8); + } + + [Fact] + public void Should_resolve_using_custom_func_with_correct_ResolutionContext() + { + const string itemKey = "key"; + var mapper = new MapperConfiguration( + cfg => cfg.CreateMap().ForCtorParam("thing", opt => + opt.MapFrom((src, ctx) => ctx.Items[itemKey]) + )) + .CreateMapper(); - var dest = mapper.Map(new Source { Value = 8 }, - opts => opts.Items[itemKey] = 10); + var dest = mapper.Map(new Source { Value = 8 }, + opts => opts.Items[itemKey] = 10); - dest.Value1.ShouldBe(10); - } + dest.Value1.ShouldBe(10); + } - [Fact] - public void Should_throw_on_nonexistent_parameter() + [Fact] + public void Should_throw_on_nonexistent_parameter() + { + Action configuration = () => new MapperConfiguration(cfg => { - Action configuration = () => new MapperConfiguration(cfg => - { - cfg.CreateMap() - .ForCtorParam("thing", opt => opt.MapFrom(src => src.Value)) - .ForCtorParam("think", opt => opt.MapFrom(src => src.Value)); - }); - configuration.ShouldThrowException(exception => - { - exception.Message.ShouldContain("does not have a matching constructor with a parameter named 'think'.", Case.Sensitive); - exception.Message.ShouldContain(typeof(Dest).FullName, Case.Sensitive); - }); - } + cfg.CreateMap() + .ForCtorParam("thing", opt => opt.MapFrom(src => src.Value)) + .ForCtorParam("think", opt => opt.MapFrom(src => src.Value)); + }); + configuration.ShouldThrowException(exception => + { + exception.Message.ShouldContain("does not have a matching constructor with a parameter named 'think'.", Case.Sensitive); + exception.Message.ShouldContain(typeof(Dest).FullName, Case.Sensitive); + }); + } - [Fact] - public void Should_throw_when_no_constructor_is_present() + [Fact] + public void Should_throw_when_no_constructor_is_present() + { + Action configuration = () => new MapperConfiguration(cfg => { - Action configuration = () => new MapperConfiguration(cfg => - { - cfg.CreateMap() - .ForMember(dest => dest.Value1, opt => opt.MapFrom(src => src.Value)) - .ForCtorParam("thing", opt => opt.MapFrom(src => src.Value)); - }); + cfg.CreateMap() + .ForMember(dest => dest.Value1, opt => opt.MapFrom(src => src.Value)) + .ForCtorParam("thing", opt => opt.MapFrom(src => src.Value)); + }); - configuration.ShouldThrowException(exception => - { - exception.Message.ShouldContain("does not have a constructor.", Case.Sensitive); - exception.Message.ShouldContain(typeof(Dest).FullName, Case.Sensitive); - }); - } + configuration.ShouldThrowException(exception => + { + exception.Message.ShouldContain("does not have a constructor.", Case.Sensitive); + exception.Message.ShouldContain(typeof(Dest).FullName, Case.Sensitive); + }); + } - [Fact] - public void Should_throw_when_parameter_is_misspelt() + [Fact] + public void Should_throw_when_parameter_is_misspelt() + { + Action configuration = () => new MapperConfiguration(cfg => { - Action configuration = () => new MapperConfiguration(cfg => - { - cfg.CreateMap() - .ForCtorParam("think", opt => opt.MapFrom(src => src.Value)); - }); + cfg.CreateMap() + .ForCtorParam("think", opt => opt.MapFrom(src => src.Value)); + }); - configuration.ShouldThrowException(exception => - { - exception.Message.ShouldContain("does not have a matching constructor with a parameter named 'think'.", Case.Sensitive); - exception.Message.ShouldContain(typeof(Dest).FullName, Case.Sensitive); - }); - } + configuration.ShouldThrowException(exception => + { + exception.Message.ShouldContain("does not have a matching constructor with a parameter named 'think'.", Case.Sensitive); + exception.Message.ShouldContain(typeof(Dest).FullName, Case.Sensitive); + }); } } \ No newline at end of file diff --git a/src/UnitTests/IMappingExpression/IncludeMembers.cs b/src/UnitTests/IMappingExpression/IncludeMembers.cs index ba480f3069..8dd54b04d0 100644 --- a/src/UnitTests/IMappingExpression/IncludeMembers.cs +++ b/src/UnitTests/IMappingExpression/IncludeMembers.cs @@ -9,1719 +9,1718 @@ using Shouldly; using Xunit; -namespace AutoMapper.UnitTests +namespace AutoMapper.UnitTests; + +public class IncludeMembers : AutoMapperSpecBase { - public class IncludeMembers : AutoMapperSpecBase + class Source { - class Source - { - public string Name { get; set; } - public InnerSource InnerSource { get; set; } - public OtherInnerSource OtherInnerSource { get; set; } - } - class InnerSource - { - public string Name { get; set; } - public string Description { get; set; } - } - class OtherInnerSource - { - public string Name { get; set; } - public string Description { get; set; } - public string Title { get; set; } - } - class Destination - { - public string Name { get; set; } - public string Description { get; set; } - public string Title { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg=> - { - cfg.CreateMap().IncludeMembers(s=>s.InnerSource, s=>s.OtherInnerSource); - cfg.CreateMap(MemberList.None); - cfg.CreateMap(MemberList.None); - }); - [Fact] - public void Should_flatten() - { - var source = new Source { Name = "name", InnerSource = new InnerSource{ Description = "description" }, OtherInnerSource = new OtherInnerSource{ Title = "title" } }; - var destination = Mapper.Map(source); - destination.Name.ShouldBe("name"); - destination.Description.ShouldBe("description"); - destination.Title.ShouldBe("title"); - } + public string Name { get; set; } + public InnerSource InnerSource { get; set; } + public OtherInnerSource OtherInnerSource { get; set; } } - public class IncludeMembersWrapperFirstOrDefault : AutoMapperSpecBase + class InnerSource { - class Source - { - public int Id { get; set; } - public string Name { get; set; } - public List InnerSources { get; set; } = new List(); - public List OtherInnerSources { get; set; } = new List(); - } - class InnerSourceWrapper - { - public InnerSource InnerSource { get; set; } - } - class InnerSource - { - public int Id { get; set; } - public string Name { get; set; } - public string Description { get; set; } - public string Publisher { get; set; } - } - class OtherInnerSource - { - public int Id { get; set; } - public string Name { get; set; } - public string Description { get; set; } - public string Title { get; set; } - public string Author { get; set; } - } - class Destination - { - public int Id { get; set; } - public string Name { get; set; } - public string Description { get; set; } - public string Title { get; set; } - public string Author { get; set; } - public string Publisher { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().IncludeMembers(s => s.InnerSources.FirstOrDefault().InnerSource, s => s.OtherInnerSources.FirstOrDefault()).ReverseMap(); - cfg.CreateMap(MemberList.None); - cfg.CreateMap(MemberList.None); - }); - [Fact] - public void Should_null_check() - { - Expression> expression = s => s.InnerSources.FirstOrDefault().InnerSource; - var result= expression.Body.NullCheck(null); - } - [Fact] - public void Should_flatten() - { - var source = new Source - { - Name = "name", - InnerSources = { new InnerSourceWrapper { InnerSource = new InnerSource { Description = "description", Publisher = "publisher" } } }, - OtherInnerSources = { new OtherInnerSource { Title = "title", Author = "author" } } - }; - var destination = Mapper.Map(source); - var plan = Configuration.BuildExecutionPlan(typeof(Source), typeof(Destination)); - FirstOrDefaultCounter.Assert(plan, 2); - destination.Name.ShouldBe("name"); - destination.Description.ShouldBe("description"); - destination.Title.ShouldBe("title"); - destination.Author.ShouldBe("author"); - destination.Publisher.ShouldBe("publisher"); - } - } - public class IncludeMembersFirstOrDefault : AutoMapperSpecBase - { - class Source - { - public int Id { get; set; } - public string Name { get; set; } - public List InnerSources { get; set; } = new List(); - public List OtherInnerSources { get; set; } = new List(); - } - class InnerSource - { - public int Id { get; set; } - public string Name { get; set; } - public string Description { get; set; } - public string Publisher { get; set; } - } - class OtherInnerSource - { - public int Id { get; set; } - public string Name { get; set; } - public string Description { get; set; } - public string Title { get; set; } - public string Author { get; set; } - } - class Destination - { - public int Id { get; set; } - public string Name { get; set; } - public string Description { get; set; } - public string Title { get; set; } - public string Author { get; set; } - public string Publisher { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => + public string Name { get; set; } + public string Description { get; set; } + } + class OtherInnerSource + { + public string Name { get; set; } + public string Description { get; set; } + public string Title { get; set; } + } + class Destination + { + public string Name { get; set; } + public string Description { get; set; } + public string Title { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(cfg=> + { + cfg.CreateMap().IncludeMembers(s=>s.InnerSource, s=>s.OtherInnerSource); + cfg.CreateMap(MemberList.None); + cfg.CreateMap(MemberList.None); + }); + [Fact] + public void Should_flatten() + { + var source = new Source { Name = "name", InnerSource = new InnerSource{ Description = "description" }, OtherInnerSource = new OtherInnerSource{ Title = "title" } }; + var destination = Mapper.Map(source); + destination.Name.ShouldBe("name"); + destination.Description.ShouldBe("description"); + destination.Title.ShouldBe("title"); + } +} +public class IncludeMembersWrapperFirstOrDefault : AutoMapperSpecBase +{ + class Source + { + public int Id { get; set; } + public string Name { get; set; } + public List InnerSources { get; set; } = new List(); + public List OtherInnerSources { get; set; } = new List(); + } + class InnerSourceWrapper + { + public InnerSource InnerSource { get; set; } + } + class InnerSource + { + public int Id { get; set; } + public string Name { get; set; } + public string Description { get; set; } + public string Publisher { get; set; } + } + class OtherInnerSource + { + public int Id { get; set; } + public string Name { get; set; } + public string Description { get; set; } + public string Title { get; set; } + public string Author { get; set; } + } + class Destination + { + public int Id { get; set; } + public string Name { get; set; } + public string Description { get; set; } + public string Title { get; set; } + public string Author { get; set; } + public string Publisher { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().IncludeMembers(s => s.InnerSources.FirstOrDefault().InnerSource, s => s.OtherInnerSources.FirstOrDefault()).ReverseMap(); + cfg.CreateMap(MemberList.None); + cfg.CreateMap(MemberList.None); + }); + [Fact] + public void Should_null_check() + { + Expression> expression = s => s.InnerSources.FirstOrDefault().InnerSource; + var result= expression.Body.NullCheck(null); + } + [Fact] + public void Should_flatten() + { + var source = new Source + { + Name = "name", + InnerSources = { new InnerSourceWrapper { InnerSource = new InnerSource { Description = "description", Publisher = "publisher" } } }, + OtherInnerSources = { new OtherInnerSource { Title = "title", Author = "author" } } + }; + var destination = Mapper.Map(source); + var plan = Configuration.BuildExecutionPlan(typeof(Source), typeof(Destination)); + FirstOrDefaultCounter.Assert(plan, 2); + destination.Name.ShouldBe("name"); + destination.Description.ShouldBe("description"); + destination.Title.ShouldBe("title"); + destination.Author.ShouldBe("author"); + destination.Publisher.ShouldBe("publisher"); + } +} +public class IncludeMembersFirstOrDefault : AutoMapperSpecBase +{ + class Source + { + public int Id { get; set; } + public string Name { get; set; } + public List InnerSources { get; set; } = new List(); + public List OtherInnerSources { get; set; } = new List(); + } + class InnerSource + { + public int Id { get; set; } + public string Name { get; set; } + public string Description { get; set; } + public string Publisher { get; set; } + } + class OtherInnerSource + { + public int Id { get; set; } + public string Name { get; set; } + public string Description { get; set; } + public string Title { get; set; } + public string Author { get; set; } + } + class Destination + { + public int Id { get; set; } + public string Name { get; set; } + public string Description { get; set; } + public string Title { get; set; } + public string Author { get; set; } + public string Publisher { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().IncludeMembers(s => s.InnerSources.FirstOrDefault(), s => s.OtherInnerSources.FirstOrDefault()).ReverseMap(); + cfg.CreateMap(MemberList.None); + cfg.CreateMap(MemberList.None); + }); + [Fact] + public void Should_flatten() + { + var source = new Source + { + Name = "name", + InnerSources = { new InnerSource { Description = "description", Publisher = "publisher" } }, + OtherInnerSources = { new OtherInnerSource { Title = "title", Author = "author" } } + }; + var destination = Mapper.Map(source); + var plan = Configuration.BuildExecutionPlan(typeof(Source), typeof(Destination)); + FirstOrDefaultCounter.Assert(plan, 2); + destination.Name.ShouldBe("name"); + destination.Description.ShouldBe("description"); + destination.Title.ShouldBe("title"); + destination.Author.ShouldBe("author"); + destination.Publisher.ShouldBe("publisher"); + } +} +public class IncludeMembersFirstOrDefaultReverseMap : AutoMapperSpecBase +{ + class Source + { + public int Id { get; set; } + public string Name { get; set; } + public List InnerSources { get; set; } = new List(); + public List OtherInnerSources { get; set; } = new List(); + } + class InnerSource + { + public int Id { get; set; } + public string Name { get; set; } + public string Description { get; set; } + public string Publisher { get; set; } + } + class OtherInnerSource + { + public int Id { get; set; } + public string Name { get; set; } + public string Description { get; set; } + public string Title { get; set; } + public string Author { get; set; } + } + class Destination + { + public int Id { get; set; } + public string Name { get; set; } + public string Description { get; set; } + public string Title { get; set; } + public string Author { get; set; } + public string Publisher { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().IncludeMembers(s => s.InnerSources.FirstOrDefault(), s => s.OtherInnerSources.FirstOrDefault()).ReverseMap(); + cfg.CreateMap(MemberList.None).ReverseMap(); + cfg.CreateMap(MemberList.None).ReverseMap(); + }); + [Fact] + public void Should_unflatten() + { + var source = Mapper.Map(new Destination { Description = "description", Name = "name", Title = "title" }); + source.Name.ShouldBe("name"); + } +} +public class IncludeMembersNested : AutoMapperSpecBase +{ + class Source + { + public string Name { get; set; } + public InnerSource InnerSource { get; set; } + public OtherInnerSource OtherInnerSource { get; set; } + } + class InnerSource + { + public NestedInnerSource NestedInnerSource { get; set; } + } + class OtherInnerSource + { + public NestedOtherInnerSource NestedOtherInnerSource { get; set; } + } + class NestedInnerSource + { + public string Name { get; set; } + public string Description { get; set; } + } + class NestedOtherInnerSource + { + public string Name { get; set; } + public string Description { get; set; } + public string Title { get; set; } + } + class Destination + { + public string Name { get; set; } + public string Description { get; set; } + public string Title { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().IncludeMembers(s => s.InnerSource.NestedInnerSource, s => s.OtherInnerSource.NestedOtherInnerSource); + cfg.CreateMap(MemberList.None); + cfg.CreateMap(MemberList.None); + }); + [Fact] + public void Should_flatten() + { + var source = new Source + { + Name = "name", + InnerSource = new InnerSource { NestedInnerSource = new NestedInnerSource { Description = "description" } }, + OtherInnerSource = new OtherInnerSource { NestedOtherInnerSource = new NestedOtherInnerSource { Title = "title" } } + }; + var destination = Mapper.Map(source); + destination.Name.ShouldBe("name"); + destination.Description.ShouldBe("description"); + destination.Title.ShouldBe("title"); + } +} + +public class IncludeMembersWithMapFromExpression : AutoMapperSpecBase +{ + class Source + { + public string Name { get; set; } + public InnerSource InnerSource { get; set; } + public OtherInnerSource OtherInnerSource { get; set; } + } + class InnerSource + { + public string Name { get; set; } + public string Description1 { get; set; } + } + class OtherInnerSource + { + public string Name { get; set; } + public string Description { get; set; } + public string Title1 { get; set; } + } + class Destination + { + public string Name { get; set; } + public string Description { get; set; } + public string Title { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().IncludeMembers(s => s.InnerSource, s => s.OtherInnerSource); + cfg.CreateMap(MemberList.None).ForMember(d=>d.Description, o=>o.MapFrom(s=>s.Description1)); + cfg.CreateMap(MemberList.None).ForMember(d=>d.Title, o=>o.MapFrom(s=>s.Title1)); + }); + [Fact] + public void Should_flatten() + { + var source = new Source { Name = "name", InnerSource = new InnerSource { Description1 = "description" }, OtherInnerSource = new OtherInnerSource { Title1 = "title" } }; + var destination = Mapper.Map(source); + destination.Name.ShouldBe("name"); + destination.Description.ShouldBe("description"); + destination.Title.ShouldBe("title"); + } +} + +public class IncludeMembersWithNullSubstitute : AutoMapperSpecBase +{ + class Source + { + public string Name { get; set; } + public InnerSource InnerSource { get; set; } + public OtherInnerSource OtherInnerSource { get; set; } + } + class InnerSource + { + public string Name { get; set; } + public string Description { get; set; } + } + class OtherInnerSource + { + public string Name { get; set; } + public string Description { get; set; } + public string Title { get; set; } + } + class Destination + { + public string Name { get; set; } + public string Description { get; set; } + public string Title { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().IncludeMembers(s => s.InnerSource, s => s.OtherInnerSource); + cfg.CreateMap(MemberList.None).ForMember(d => d.Description, o => o.NullSubstitute("description")); + cfg.CreateMap(MemberList.None).ForMember(d=>d.Title, o => o.NullSubstitute("title")); + }); + [Fact] + public void Should_flatten() + { + var source = new Source { Name = "name" }; + var destination = Mapper.Map(source); + destination.Name.ShouldBe("name"); + destination.Description.ShouldBe("description"); + destination.Title.ShouldBe("title"); + } +} + +public class IncludeMembersWithMapFromFunc : AutoMapperSpecBase +{ + class Source + { + public string Name { get; set; } + public InnerSource InnerSource { get; set; } + public OtherInnerSource OtherInnerSource { get; set; } + } + class InnerSource + { + public string Name { get; set; } + public string Description1 { get; set; } + } + class OtherInnerSource + { + public string Name { get; set; } + public string Description { get; set; } + public string Title1 { get; set; } + } + class Destination + { + public string Name { get; set; } + public string Description { get; set; } + public string Title { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().IncludeMembers(s => s.InnerSource, s => s.OtherInnerSource); + cfg.CreateMap(MemberList.None).ForMember(d => d.Description, o => o.MapFrom((s, d) => s.Description1)); + cfg.CreateMap(MemberList.None).ForMember(d => d.Title, o => o.MapFrom((s, d) => s.Title1)); + }); + [Fact] + public void Should_flatten() + { + var source = new Source { Name = "name", InnerSource = new InnerSource { Description1 = "description" }, OtherInnerSource = new OtherInnerSource { Title1 = "title" } }; + var destination = Mapper.Map(source); + destination.Name.ShouldBe("name"); + destination.Description.ShouldBe("description"); + destination.Title.ShouldBe("title"); + } +} + +public class IncludeMembersWithResolver : AutoMapperSpecBase +{ + class Source + { + public string Name { get; set; } + public InnerSource InnerSource { get; set; } + public OtherInnerSource OtherInnerSource { get; set; } + } + class InnerSource + { + public string Name { get; set; } + public string Description1 { get; set; } + } + class OtherInnerSource + { + public string Name { get; set; } + public string Description { get; set; } + public string Title1 { get; set; } + } + class Destination + { + public string Name { get; set; } + public string Description { get; set; } + public string Title { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().IncludeMembers(s => s.InnerSource, s => s.OtherInnerSource); + cfg.CreateMap(MemberList.None).ForMember(d => d.Description, o => o.MapFrom()); + cfg.CreateMap(MemberList.None).ForMember(d => d.Title, o => o.MapFrom()); + }); + [Fact] + public void Should_flatten() + { + var source = new Source { Name = "name", InnerSource = new InnerSource { Description1 = "description" }, OtherInnerSource = new OtherInnerSource { Title1 = "title" } }; + var destination = Mapper.Map(source); + destination.Name.ShouldBe("name"); + destination.Description.ShouldBe("description"); + destination.Title.ShouldBe("title"); + } + + private class DescriptionResolver : IValueResolver + { + public string Resolve(InnerSource source, Destination destination, string destMember, ResolutionContext context) => source.Description1; + } + + private class TitleResolver : IValueResolver + { + public string Resolve(OtherInnerSource source, Destination destination, string destMember, ResolutionContext context) => source.Title1; + } +} + +public class IncludeMembersWithMemberResolver : AutoMapperSpecBase +{ + class Source + { + public string Name { get; set; } + public InnerSource InnerSource { get; set; } + public OtherInnerSource OtherInnerSource { get; set; } + } + class InnerSource + { + public string Name { get; set; } + public string Description1 { get; set; } + } + class OtherInnerSource + { + public string Name { get; set; } + public string Description { get; set; } + public string Title1 { get; set; } + } + class Destination + { + public string Name { get; set; } + public string Description { get; set; } + public string Title { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().IncludeMembers(s => s.InnerSource, s => s.OtherInnerSource); + cfg.CreateMap(MemberList.None).ForMember(d => d.Description, o => o.MapFrom(s=>s.Description1)); + cfg.CreateMap(MemberList.None).ForMember(d => d.Title, o => o.MapFrom("Title1")); + }); + [Fact] + public void Should_flatten() + { + var source = new Source { Name = "name", InnerSource = new InnerSource { Description1 = "description" }, OtherInnerSource = new OtherInnerSource { Title1 = "title" } }; + var destination = Mapper.Map(source); + destination.Name.ShouldBe("name"); + destination.Description.ShouldBe("description"); + destination.Title.ShouldBe("title"); + } + + private class DescriptionResolver : IMemberValueResolver + { + public string Resolve(InnerSource source, Destination destination, string sourceMember, string destMember, ResolutionContext context) => sourceMember; + } + + private class TitleResolver : IMemberValueResolver + { + public string Resolve(OtherInnerSource source, Destination destination, string sourceMember, string destMember, ResolutionContext context) => sourceMember; + } +} +public class IncludeMembersWithValueConverter : AutoMapperSpecBase +{ + class Source + { + public string Name { get; set; } + public InnerSource InnerSource { get; set; } + public OtherInnerSource OtherInnerSource { get; set; } + } + class InnerSource + { + public string Name { get; set; } + public string Description1 { get; set; } + } + class OtherInnerSource + { + public string Name { get; set; } + public string Description { get; set; } + public string Title1 { get; set; } + } + class Destination + { + public string Name { get; set; } + public string Description { get; set; } + public string Title { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().IncludeMembers(s => s.InnerSource, s => s.OtherInnerSource); + cfg.CreateMap(MemberList.None).ForMember(d => d.Description, o => o.ConvertUsing(s => s.Description1)); + cfg.CreateMap(MemberList.None).ForMember(d => d.Title, o => o.ConvertUsing("Title1")); + }); + [Fact] + public void Should_flatten() + { + var source = new Source { Name = "name", InnerSource = new InnerSource { Description1 = "description" }, OtherInnerSource = new OtherInnerSource { Title1 = "title" } }; + var destination = Mapper.Map(source); + destination.Name.ShouldBe("name"); + destination.Description.ShouldBe("description"); + destination.Title.ShouldBe("title"); + } + + private class ValueConverter : IValueConverter + { + public string Convert(string sourceMember, ResolutionContext context) => sourceMember; + } +} + +public class IncludeMembersWithConditions : AutoMapperSpecBase +{ + class Source + { + public string Name { get; set; } + public InnerSource InnerSource { get; set; } + public OtherInnerSource OtherInnerSource { get; set; } + } + class InnerSource + { + public string Name { get; set; } + public string Description { get; set; } + } + class OtherInnerSource + { + public string Name { get; set; } + public string Description { get; set; } + public string Title { get; set; } + } + class Destination + { + public string Name { get; set; } + public string Description { get; set; } + public string Title { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().IncludeMembers(s => s.InnerSource, s => s.OtherInnerSource); + cfg.CreateMap(MemberList.None).ForMember(d => d.Description, o => o.Condition((s, d, sm, dm, c) => false)); + cfg.CreateMap(MemberList.None).ForMember(d => d.Description, o => o.Condition((s, d, sm, dm, c) => true)); + }); + [Fact] + public void Should_flatten() + { + var source = new Source { Name = "name", InnerSource = new InnerSource { Description = "description" }, OtherInnerSource = new OtherInnerSource { Title = "title" } }; + var destination = Mapper.Map(source); + destination.Name.ShouldBe("name"); + destination.Description.ShouldBeNull(); + destination.Title.ShouldBe("title"); + } +} +public class IncludeMembersWithPreConditions : AutoMapperSpecBase +{ + class Source + { + public string Name { get; set; } + public InnerSource InnerSource { get; set; } + public OtherInnerSource OtherInnerSource { get; set; } + } + class InnerSource + { + public string Name { get; set; } + public string Description { get; set; } + } + class OtherInnerSource + { + public string Name { get; set; } + public string Description { get; set; } + public string Title { get; set; } + } + class Destination + { + public string Name { get; set; } + public string Description { get; set; } + public string Title { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().IncludeMembers(s => s.InnerSource, s => s.OtherInnerSource); + cfg.CreateMap(MemberList.None).ForMember(d => d.Description, o => o.PreCondition((s, d, c) => false)); + cfg.CreateMap(MemberList.None).ForMember(d => d.Description, o => o.PreCondition((s, d, c) => true)); + }); + [Fact] + public void Should_flatten() + { + var source = new Source { Name = "name", InnerSource = new InnerSource { Description = "description" }, OtherInnerSource = new OtherInnerSource { Title = "title" } }; + var destination = Mapper.Map(source); + destination.Name.ShouldBe("name"); + destination.Description.ShouldBeNull(); + destination.Title.ShouldBe("title"); + } +} +public class IncludeMembersCycle : AutoMapperSpecBase +{ + class Source + { + public string Name { get; set; } + public InnerSource InnerSource { get; set; } + public OtherInnerSource OtherInnerSource { get; set; } + } + class InnerSource + { + public string Name { get; set; } + public string Description { get; set; } + public Source Parent { get; set; } + } + class OtherInnerSource + { + public string Name { get; set; } + public string Description { get; set; } + public string Title { get; set; } + public Source Parent { get; set; } + } + class Destination + { + public string Name { get; set; } + public string Description { get; set; } + public string Title { get; set; } + public Destination Parent { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().IncludeMembers(s => s.InnerSource, s => s.OtherInnerSource); + cfg.CreateMap(MemberList.None).IncludeMembers(s=>s.Parent); + cfg.CreateMap(MemberList.None).IncludeMembers(s=>s.Parent); + }); + [Fact] + public void Should_flatten() + { + var source = new Source { Name = "name", InnerSource = new InnerSource { Description = "description" }, OtherInnerSource = new OtherInnerSource { Title = "title" } }; + source.InnerSource.Parent = source; + source.OtherInnerSource.Parent = source; + var destination = Mapper.Map(source); + destination.Name.ShouldBe("name"); + destination.Description.ShouldBe("description"); + destination.Title.ShouldBe("title"); + destination.Parent.ShouldBe(destination); + } +} +public class IncludeMembersReverseMap : AutoMapperSpecBase +{ + class Source + { + public string Name { get; set; } + public InnerSource InnerSource { get; set; } + public OtherInnerSource OtherInnerSource { get; set; } + } + class InnerSource + { + public string Name { get; set; } + public string Description { get; set; } + } + class OtherInnerSource + { + public string Name { get; set; } + public string Description { get; set; } + public string Title { get; set; } + } + class Destination + { + public string Name { get; set; } + public string Description { get; set; } + public string Title { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().IncludeMembers(s => s.InnerSource, s => s.OtherInnerSource).ReverseMap(); + cfg.CreateMap(MemberList.None).ReverseMap(); + cfg.CreateMap(MemberList.None).ReverseMap(); + }); + [Fact] + public void Should_unflatten() + { + var source = Mapper.Map(new Destination { Description = "description", Name = "name", Title = "title" }); + source.Name.ShouldBe("name"); + source.InnerSource.Name.ShouldBe("name"); + source.OtherInnerSource.Name.ShouldBe("name"); + source.InnerSource.Description.ShouldBe("description"); + source.OtherInnerSource.Description.ShouldBe("description"); + source.OtherInnerSource.Title.ShouldBe("title"); + } +} +public class IncludeMembersReverseMapOverride : AutoMapperSpecBase +{ + class Source + { + public string Name { get; set; } + public InnerSource InnerSource { get; set; } + public OtherInnerSource OtherInnerSource { get; set; } + } + class InnerSource + { + public string Name { get; set; } + public string Description { get; set; } + } + class OtherInnerSource + { + public string Name { get; set; } + public string Description { get; set; } + public string Title { get; set; } + } + class Destination + { + public string Name { get; set; } + public string Description { get; set; } + public string Title { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().IncludeMembers(s => s.InnerSource, s => s.OtherInnerSource).ReverseMap() + .ForMember(d=>d.InnerSource, o=>o.Ignore()) + .ForMember(d=>d.OtherInnerSource, o=>o.Ignore()); + cfg.CreateMap(MemberList.None); + cfg.CreateMap(MemberList.None); + }); + [Fact] + public void Should_unflatten() + { + var source = Mapper.Map(new Destination { Description = "description", Name = "name", Title = "title" }); + source.Name.ShouldBe("name"); + source.InnerSource.ShouldBeNull(); + source.OtherInnerSource.ShouldBeNull(); + } +} + +public class ReverseMapToIncludeMembers : AutoMapperSpecBase +{ + class Source + { + public string Name { get; set; } + public InnerSource InnerSource { get; set; } + public OtherInnerSource OtherInnerSource { get; set; } + } + class InnerSource + { + public string Name { get; set; } + public string Description { get; set; } + } + class OtherInnerSource + { + public string Name { get; set; } + public string Description { get; set; } + public string Title { get; set; } + } + class Destination + { + public string Name { get; set; } + public string Description { get; set; } + public string Title { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .ForMember(d => d.InnerSource, o => o.MapFrom(s => s)) + .ForMember(d => d.OtherInnerSource, o => o.MapFrom(s => s)) + .ReverseMap(); + cfg.CreateMap(MemberList.None).ReverseMap(); + cfg.CreateMap(MemberList.None).ReverseMap(); + }); + [Fact] + public void Should_flatten() + { + var source = new Source { Name = "name", InnerSource = new InnerSource { Description = "description" }, OtherInnerSource = new OtherInnerSource { Title = "title" } }; + var destination = Mapper.Map(source); + destination.Name.ShouldBe("name"); + destination.Description.ShouldBe("description"); + destination.Title.ShouldBe("title"); + } +} +public class ReverseMapToIncludeMembersOverride : AutoMapperSpecBase +{ + class Source + { + public string Name { get; set; } + public InnerSource InnerSource { get; set; } + public OtherInnerSource OtherInnerSource { get; set; } + } + class InnerSource + { + public string Name { get; set; } + public string Description { get; set; } + } + class OtherInnerSource + { + public string Name { get; set; } + public string Description { get; set; } + public string Title { get; set; } + } + class Destination + { + public string Name { get; set; } + public string Description { get; set; } + public string Title { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(MemberList.None) + .ForMember(d => d.InnerSource, o => o.MapFrom(s => s)) + .ForMember(d => d.OtherInnerSource, o => o.MapFrom(s => s)) + .ReverseMap() + .IncludeMembers(); + cfg.CreateMap(MemberList.None).ReverseMap(); + cfg.CreateMap(MemberList.None).ReverseMap(); + }); + [Fact] + public void Should_flatten() + { + var source = new Source { Name = "name", InnerSource = new InnerSource { Description = "description" }, OtherInnerSource = new OtherInnerSource { Title = "title" } }; + var destination = Mapper.Map(source); + destination.Name.ShouldBe("name"); + destination.Description.ShouldBeNull(); + destination.Title.ShouldBeNull(); + } +} +public class IncludeMembersWithAfterMap : AutoMapperSpecBase +{ + class Source + { + public string Name { get; set; } + public InnerSource InnerSource { get; set; } + public OtherInnerSource OtherInnerSource { get; set; } + } + class InnerSource + { + public string Name { get; set; } + public string Description { get; set; } + } + class OtherInnerSource + { + public string Name { get; set; } + public string Description { get; set; } + public string Title { get; set; } + } + class Destination + { + public string Name { get; set; } + public string Description { get; set; } + public string Title { get; set; } + } + bool afterMap, beforeMap; + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().IncludeMembers(s => s.InnerSource, s => s.OtherInnerSource); + cfg.CreateMap(MemberList.None).AfterMap((s,d)=>afterMap=true); + cfg.CreateMap(MemberList.None).BeforeMap((s, d, c) => beforeMap = true); + }); + [Fact] + public void Should_flatten() + { + var source = new Source { Name = "name", InnerSource = new InnerSource { Description = "description" }, OtherInnerSource = new OtherInnerSource { Title = "title" } }; + var destination = Mapper.Map(source); + destination.Name.ShouldBe("name"); + destination.Description.ShouldBe("description"); + destination.Title.ShouldBe("title"); + afterMap.ShouldBeTrue(); + beforeMap.ShouldBeTrue(); + } +} + +public class IncludeMembersWithForPath : AutoMapperSpecBase +{ + class Source + { + public string Name { get; set; } + public InnerSource InnerSource { get; set; } + public OtherInnerSource OtherInnerSource { get; set; } + } + class InnerSource + { + public string Name { get; set; } + public string Description { get; set; } + } + class OtherInnerSource + { + public string Name { get; set; } + public string Description { get; set; } + public string Title { get; set; } + } + class Destination + { + public string Name { get; set; } + public InnerDestination InnerDestination { get; set; } + } + class InnerDestination + { + public string Description { get; set; } + public string Title { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().IncludeMembers(s => s.InnerSource, s => s.OtherInnerSource); + cfg.CreateMap(MemberList.None).ForPath(d=>d.InnerDestination.Description, o=> { - cfg.CreateMap().IncludeMembers(s => s.InnerSources.FirstOrDefault(), s => s.OtherInnerSources.FirstOrDefault()).ReverseMap(); - cfg.CreateMap(MemberList.None); - cfg.CreateMap(MemberList.None); + o.MapFrom(s => s.Description); + o.Condition(c => true); }); - [Fact] - public void Should_flatten() + cfg.CreateMap(MemberList.None).ForPath(d=>d.InnerDestination.Title, o=> { - var source = new Source - { - Name = "name", - InnerSources = { new InnerSource { Description = "description", Publisher = "publisher" } }, - OtherInnerSources = { new OtherInnerSource { Title = "title", Author = "author" } } - }; - var destination = Mapper.Map(source); - var plan = Configuration.BuildExecutionPlan(typeof(Source), typeof(Destination)); - FirstOrDefaultCounter.Assert(plan, 2); - destination.Name.ShouldBe("name"); - destination.Description.ShouldBe("description"); - destination.Title.ShouldBe("title"); - destination.Author.ShouldBe("author"); - destination.Publisher.ShouldBe("publisher"); - } - } - public class IncludeMembersFirstOrDefaultReverseMap : AutoMapperSpecBase - { - class Source - { - public int Id { get; set; } - public string Name { get; set; } - public List InnerSources { get; set; } = new List(); - public List OtherInnerSources { get; set; } = new List(); - } - class InnerSource - { - public int Id { get; set; } - public string Name { get; set; } - public string Description { get; set; } - public string Publisher { get; set; } - } - class OtherInnerSource - { - public int Id { get; set; } - public string Name { get; set; } - public string Description { get; set; } - public string Title { get; set; } - public string Author { get; set; } - } - class Destination - { - public int Id { get; set; } - public string Name { get; set; } - public string Description { get; set; } - public string Title { get; set; } - public string Author { get; set; } - public string Publisher { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().IncludeMembers(s => s.InnerSources.FirstOrDefault(), s => s.OtherInnerSources.FirstOrDefault()).ReverseMap(); - cfg.CreateMap(MemberList.None).ReverseMap(); - cfg.CreateMap(MemberList.None).ReverseMap(); + o.MapFrom(s => s.Title); + o.Condition(c => true); }); - [Fact] - public void Should_unflatten() - { - var source = Mapper.Map(new Destination { Description = "description", Name = "name", Title = "title" }); - source.Name.ShouldBe("name"); - } + }); + [Fact] + public void Should_flatten() + { + var source = new Source { Name = "name", InnerSource = new InnerSource { Description = "description" }, OtherInnerSource = new OtherInnerSource { Title = "title" } }; + var destination = Mapper.Map(source); + destination.Name.ShouldBe("name"); + destination.InnerDestination.Description.ShouldBe("description"); + destination.InnerDestination.Title.ShouldBe("title"); } - public class IncludeMembersNested : AutoMapperSpecBase +} +public class IncludeMembersTransformers : AutoMapperSpecBase +{ + class Source { - class Source - { - public string Name { get; set; } - public InnerSource InnerSource { get; set; } - public OtherInnerSource OtherInnerSource { get; set; } - } - class InnerSource - { - public NestedInnerSource NestedInnerSource { get; set; } - } - class OtherInnerSource - { - public NestedOtherInnerSource NestedOtherInnerSource { get; set; } - } - class NestedInnerSource - { - public string Name { get; set; } - public string Description { get; set; } - } - class NestedOtherInnerSource - { - public string Name { get; set; } - public string Description { get; set; } - public string Title { get; set; } - } - class Destination - { - public string Name { get; set; } - public string Description { get; set; } - public string Title { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().IncludeMembers(s => s.InnerSource.NestedInnerSource, s => s.OtherInnerSource.NestedOtherInnerSource); - cfg.CreateMap(MemberList.None); - cfg.CreateMap(MemberList.None); - }); - [Fact] - public void Should_flatten() - { - var source = new Source - { - Name = "name", - InnerSource = new InnerSource { NestedInnerSource = new NestedInnerSource { Description = "description" } }, - OtherInnerSource = new OtherInnerSource { NestedOtherInnerSource = new NestedOtherInnerSource { Title = "title" } } - }; - var destination = Mapper.Map(source); - destination.Name.ShouldBe("name"); - destination.Description.ShouldBe("description"); - destination.Title.ShouldBe("title"); - } + public string Name { get; set; } + public InnerSource InnerSource { get; set; } + public OtherInnerSource OtherInnerSource { get; set; } + } + class InnerSource + { + public string Name { get; set; } + public string Description { get; set; } + } + class OtherInnerSource + { + public string Name { get; set; } + public string Description { get; set; } + public string Title { get; set; } + } + class Destination + { + public string Name { get; set; } + public string Description { get; set; } + public string Title { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().IncludeMembers(s => s.InnerSource, s => s.OtherInnerSource).AddTransform(s => s + "Main"); + cfg.CreateMap(MemberList.None).ForMember(d=>d.Description, o=>o.AddTransform(s=>s+"Extra")).AddTransform(s => s + "Ex"); + cfg.CreateMap(MemberList.None).ForMember(d => d.Title, o => o.AddTransform(s => s + "Extra")).AddTransform(s => s + "Ex"); + }); + [Fact] + public void Should_flatten() + { + var source = new Source { Name = "name", InnerSource = new InnerSource { Description = "description" }, OtherInnerSource = new OtherInnerSource { Title = "title" } }; + var destination = Mapper.Map(source); + destination.Name.ShouldBe("nameMain"); + destination.Description.ShouldBe("descriptionExtraExMain"); + destination.Title.ShouldBe("titleExtraExMain"); } +} +public class IncludeMembersTransformersPerMember : AutoMapperSpecBase +{ + class Source + { + public string Name { get; set; } + public InnerSource InnerSource { get; set; } + public OtherInnerSource OtherInnerSource { get; set; } + } + class InnerSource + { + public string Name { get; set; } + public string Description { get; set; } + } + class OtherInnerSource + { + public string Name { get; set; } + public string Description { get; set; } + public string Title { get; set; } + } + class Destination + { + public string Name { get; set; } + public string Description { get; set; } + public string Title { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().IncludeMembers(s => s.InnerSource, s => s.OtherInnerSource); + cfg.CreateMap(MemberList.None).ForMember(d=>d.Description, o=>o.AddTransform(s=>s+"Ex")); + cfg.CreateMap(MemberList.None).ForMember(d => d.Title, o => o.AddTransform(s => s + "Ex")); + }); + [Fact] + public void Should_flatten() + { + var source = new Source { Name = "name", InnerSource = new InnerSource { Description = "description" }, OtherInnerSource = new OtherInnerSource { Title = "title" } }; + var destination = Mapper.Map(source); + destination.Name.ShouldBe("name"); + destination.Description.ShouldBe("descriptionEx"); + destination.Title.ShouldBe("titleEx"); + } +} +public class IncludeMembersWithGenerics : AutoMapperSpecBase +{ + class Source + { + public string Name { get; set; } + public TInnerSource InnerSource { get; set; } + public TOtherInnerSource OtherInnerSource { get; set; } + } + class InnerSource + { + public string Name { get; set; } + public string Description { get; set; } + } + class OtherInnerSource + { + public string Name { get; set; } + public string Description { get; set; } + public string Title { get; set; } + } + class Destination + { + public string Name { get; set; } + public string Description { get; set; } + public string Title { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(typeof(Source<,>), typeof(Destination), MemberList.None).IncludeMembers("InnerSource", "OtherInnerSource"); + cfg.CreateMap(MemberList.None); + cfg.CreateMap(MemberList.None); + }); + [Fact] + public void Should_flatten() + { + var source = new Source { Name = "name", InnerSource = new InnerSource { Description = "description" }, OtherInnerSource = new OtherInnerSource { Title = "title" } }; + var destination = Mapper.Map(source); + destination.Name.ShouldBe("name"); + destination.Description.ShouldBe("description"); + destination.Title.ShouldBe("title"); + } +} - public class IncludeMembersWithMapFromExpression : AutoMapperSpecBase +public class IncludeMembersWithGenericsInvalidStrings +{ + class Source { - class Source - { - public string Name { get; set; } - public InnerSource InnerSource { get; set; } - public OtherInnerSource OtherInnerSource { get; set; } - } - class InnerSource - { - public string Name { get; set; } - public string Description1 { get; set; } - } - class OtherInnerSource - { - public string Name { get; set; } - public string Description { get; set; } - public string Title1 { get; set; } - } - class Destination - { - public string Name { get; set; } - public string Description { get; set; } - public string Title { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => + public string Name { get; set; } + public TInnerSource InnerSource { get; set; } + public TOtherInnerSource OtherInnerSource { get; set; } + } + class Destination + { + public string Name { get; set; } + public string Description { get; set; } + public string Title { get; set; } + } + [Fact] + public void Should_throw() + { + new MapperConfiguration(cfg => { - cfg.CreateMap().IncludeMembers(s => s.InnerSource, s => s.OtherInnerSource); - cfg.CreateMap(MemberList.None).ForMember(d=>d.Description, o=>o.MapFrom(s=>s.Description1)); - cfg.CreateMap(MemberList.None).ForMember(d=>d.Title, o=>o.MapFrom(s=>s.Title1)); + Assert.Throws(() => cfg.CreateMap(typeof(Source<,>), typeof(Destination), MemberList.None).IncludeMembers("dInnerSource", "fOtherInnerSource")); }); - [Fact] - public void Should_flatten() - { - var source = new Source { Name = "name", InnerSource = new InnerSource { Description1 = "description" }, OtherInnerSource = new OtherInnerSource { Title1 = "title" } }; - var destination = Mapper.Map(source); - destination.Name.ShouldBe("name"); - destination.Description.ShouldBe("description"); - destination.Title.ShouldBe("title"); - } } +} - public class IncludeMembersWithNullSubstitute : AutoMapperSpecBase +public class IncludeMembersReverseMapGenerics : AutoMapperSpecBase +{ + class Source { - class Source - { - public string Name { get; set; } - public InnerSource InnerSource { get; set; } - public OtherInnerSource OtherInnerSource { get; set; } - } - class InnerSource - { - public string Name { get; set; } - public string Description { get; set; } - } - class OtherInnerSource - { - public string Name { get; set; } - public string Description { get; set; } - public string Title { get; set; } - } - class Destination - { - public string Name { get; set; } - public string Description { get; set; } - public string Title { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().IncludeMembers(s => s.InnerSource, s => s.OtherInnerSource); - cfg.CreateMap(MemberList.None).ForMember(d => d.Description, o => o.NullSubstitute("description")); - cfg.CreateMap(MemberList.None).ForMember(d=>d.Title, o => o.NullSubstitute("title")); - }); - [Fact] - public void Should_flatten() - { - var source = new Source { Name = "name" }; - var destination = Mapper.Map(source); - destination.Name.ShouldBe("name"); - destination.Description.ShouldBe("description"); - destination.Title.ShouldBe("title"); - } + public string Name { get; set; } + public TInnerSource InnerSource { get; set; } + public TOtherInnerSource OtherInnerSource { get; set; } + } + class InnerSource + { + public string Name { get; set; } + public string Description { get; set; } + } + class OtherInnerSource + { + public string Name { get; set; } + public string Description { get; set; } + public string Title { get; set; } + } + class Destination + { + public string Name { get; set; } + public string Description { get; set; } + public string Title { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(typeof(Source<,>), typeof(Destination), MemberList.None).IncludeMembers("InnerSource", "OtherInnerSource").ReverseMap(); + cfg.CreateMap(MemberList.None).ReverseMap(); + cfg.CreateMap(MemberList.None).ReverseMap(); + }); + [Fact] + public void Should_unflatten() + { + var source = Mapper.Map>(new Destination { Description = "description", Name = "name", Title = "title" }); + source.Name.ShouldBe("name"); + source.InnerSource.Name.ShouldBe("name"); + source.OtherInnerSource.Name.ShouldBe("name"); + source.InnerSource.Description.ShouldBe("description"); + source.OtherInnerSource.Description.ShouldBe("description"); + source.OtherInnerSource.Title.ShouldBe("title"); + } +} +public class IncludeMembersReverseMapGenericsOverride : AutoMapperSpecBase +{ + class Source + { + public string Name { get; set; } + public TInnerSource InnerSource { get; set; } + public TOtherInnerSource OtherInnerSource { get; set; } + } + class InnerSource + { + public string Name { get; set; } + public string Description { get; set; } + } + class OtherInnerSource + { + public string Name { get; set; } + public string Description { get; set; } + public string Title { get; set; } + } + class Destination + { + public string Name { get; set; } + public string Description { get; set; } + public string Title { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(typeof(Source<,>), typeof(Destination), MemberList.None).IncludeMembers("InnerSource", "OtherInnerSource").ReverseMap() + .ForMember("InnerSource", o=>o.Ignore()) + .ForMember("OtherInnerSource", o=>o.Ignore()); + cfg.CreateMap(MemberList.None); + cfg.CreateMap(MemberList.None); + }); + [Fact] + public void Should_unflatten() + { + var source = Mapper.Map>(new Destination { Description = "description", Name = "name", Title = "title" }); + source.Name.ShouldBe("name"); + source.InnerSource.ShouldBeNull(); + source.OtherInnerSource.ShouldBeNull(); + } +} +public class ReverseMapToIncludeMembersGenerics : AutoMapperSpecBase +{ + class Source + { + public string Name { get; set; } + public TInnerSource InnerSource { get; set; } + public TOtherInnerSource OtherInnerSource { get; set; } + } + class InnerSource + { + public string Name { get; set; } + public string Description { get; set; } + } + class OtherInnerSource + { + public string Name { get; set; } + public string Description { get; set; } + public string Title { get; set; } + } + class Destination + { + public string Name { get; set; } + public string Description { get; set; } + public string Title { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(typeof(Destination), typeof(Source<,>)) + .ForMember("InnerSource", o => o.MapFrom(s => s)) + .ForMember("OtherInnerSource", o => o.MapFrom(s => s)) + .ReverseMap(); + cfg.CreateMap(MemberList.None); + cfg.CreateMap(MemberList.None); + }); + [Fact] + public void Should_flatten() + { + var source = new Source { Name = "name", InnerSource = new InnerSource { Description = "description" }, OtherInnerSource = new OtherInnerSource { Title = "title" } }; + var destination = Mapper.Map(source); + destination.Name.ShouldBe("name"); + destination.Description.ShouldBe("description"); + destination.Title.ShouldBe("title"); + } +} +public class ReverseMapToIncludeMembersGenericsOverride : AutoMapperSpecBase +{ + class Source + { + public string Name { get; set; } + public TInnerSource InnerSource { get; set; } + public TOtherInnerSource OtherInnerSource { get; set; } + } + class InnerSource + { + public string Name { get; set; } + public string Description { get; set; } + } + class OtherInnerSource + { + public string Name { get; set; } + public string Description { get; set; } + public string Title { get; set; } + } + class Destination + { + public string Name { get; set; } + public string Description { get; set; } + public string Title { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(typeof(Destination), typeof(Source<,>)) + .ForMember("InnerSource", o => o.MapFrom(s => s)) + .ForMember("OtherInnerSource", o => o.MapFrom(s => s)) + .ReverseMap() + .IncludeMembers(); + cfg.CreateMap(MemberList.None); + cfg.CreateMap(MemberList.None); + }); + [Fact] + public void Should_flatten() + { + var source = new Source { Name = "name", InnerSource = new InnerSource { Description = "description" }, OtherInnerSource = new OtherInnerSource { Title = "title" } }; + var destination = Mapper.Map(source); + destination.Name.ShouldBe("name"); + destination.Description.ShouldBeNull(); + destination.Title.ShouldBeNull(); + } +} +public class IncludeMembersSourceValidation : AutoMapperSpecBase +{ + class Source + { + public string Name { get; set; } + public InnerSource InnerSource { get; set; } + public OtherInnerSource OtherInnerSource { get; set; } + } + class InnerSource + { + public string Name { get; set; } + public string Description { get; set; } + } + class OtherInnerSource + { + public string Name { get; set; } + public string Description { get; set; } + public string Title { get; set; } + } + class Destination + { + public string Name { get; set; } + public string Description { get; set; } + public string Title { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(MemberList.Source).IncludeMembers(s => s.InnerSource, s => s.OtherInnerSource); + cfg.CreateMap(MemberList.None); + cfg.CreateMap(MemberList.None); + }); + [Fact] + public void Should_flatten() + { + var source = new Source { Name = "name", InnerSource = new InnerSource { Description = "description" }, OtherInnerSource = new OtherInnerSource { Title = "title" } }; + var destination = Mapper.Map(source); + destination.Name.ShouldBe("name"); + destination.Description.ShouldBe("description"); + destination.Title.ShouldBe("title"); } - public class IncludeMembersWithMapFromFunc : AutoMapperSpecBase +} +public class IncludeMembersWithGenericsSourceValidation : AutoMapperSpecBase +{ + class Source { - class Source - { - public string Name { get; set; } - public InnerSource InnerSource { get; set; } - public OtherInnerSource OtherInnerSource { get; set; } - } - class InnerSource - { - public string Name { get; set; } - public string Description1 { get; set; } - } - class OtherInnerSource - { - public string Name { get; set; } - public string Description { get; set; } - public string Title1 { get; set; } - } - class Destination - { - public string Name { get; set; } - public string Description { get; set; } - public string Title { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().IncludeMembers(s => s.InnerSource, s => s.OtherInnerSource); - cfg.CreateMap(MemberList.None).ForMember(d => d.Description, o => o.MapFrom((s, d) => s.Description1)); - cfg.CreateMap(MemberList.None).ForMember(d => d.Title, o => o.MapFrom((s, d) => s.Title1)); - }); - [Fact] - public void Should_flatten() - { - var source = new Source { Name = "name", InnerSource = new InnerSource { Description1 = "description" }, OtherInnerSource = new OtherInnerSource { Title1 = "title" } }; - var destination = Mapper.Map(source); - destination.Name.ShouldBe("name"); - destination.Description.ShouldBe("description"); - destination.Title.ShouldBe("title"); - } + public string Name { get; set; } + public TInnerSource InnerSource { get; set; } + public TOtherInnerSource OtherInnerSource { get; set; } + } + class InnerSource + { + public string Name { get; set; } + public string Description { get; set; } + } + class OtherInnerSource + { + public string Name { get; set; } + public string Description { get; set; } + public string Title { get; set; } + } + class Destination + { + public string Name { get; set; } + public string Description { get; set; } + public string Title { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(typeof(Source<,>), typeof(Destination), MemberList.Source).IncludeMembers("InnerSource", "OtherInnerSource"); + cfg.CreateMap(MemberList.None); + cfg.CreateMap(MemberList.None); + }); + [Fact] + public void Should_flatten() + { + var source = new Source { Name = "name", InnerSource = new InnerSource { Description = "description" }, OtherInnerSource = new OtherInnerSource { Title = "title" } }; + var destination = Mapper.Map(source); + destination.Name.ShouldBe("name"); + destination.Description.ShouldBe("description"); + destination.Title.ShouldBe("title"); + } +} +public class IncludeMembersWithInclude : AutoMapperSpecBase +{ + public class ParentOfSource + { + public Source InnerSource { get; set; } + } + public class Source : SourceBase + { + } + public class SourceBase + { + public string FirstName { get; set; } + public string LastName { get; set; } + } + public class Destination + { + public string FullName { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().ForMember(dest => dest.FullName, opt => opt.MapFrom(src => src.FirstName + " " + src.LastName)).IncludeAllDerived(); + cfg.CreateMap().IncludeMembers(src => src.InnerSource); + cfg.CreateMap(); + }); + [Fact] + public void Should_inherit_configuration() => Mapper.Map(new ParentOfSource { InnerSource = new Source { FirstName = "first", LastName = "last" } }).FullName.ShouldBe("first last"); +} +public class IncludeMembersWithIncludeDifferentOrder : AutoMapperSpecBase +{ + public class ParentOfSource + { + public Source InnerSource { get; set; } + } + public class Source : SourceBase + { + } + public class SourceBase + { + public string FirstName { get; set; } + public string LastName { get; set; } + } + public class Destination + { + public string FullName { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().ForMember(dest => dest.FullName, opt => opt.MapFrom(src => src.FirstName + " " + src.LastName)).IncludeAllDerived(); + cfg.CreateMap(); + cfg.CreateMap().IncludeMembers(src => src.InnerSource); + }); + [Fact] + public void Should_inherit_configuration() => Mapper.Map(new ParentOfSource { InnerSource = new Source { FirstName = "first", LastName = "last" } }).FullName.ShouldBe("first last"); +} +public class IncludeMembersWithIncludeBase : AutoMapperSpecBase +{ + public class Customer + { + public int Id { get; set; } + public string Name { get; set; } + public Address Address { get; set; } + } + public class Address + { + public string Line1 { get; set; } + public string Postcode { get; set; } + } + public class CustomerDtoBase + { + public int Id { get; set; } + public string Name { get; set; } + public string AddressLine1 { get; set; } + public string Postcode { get; set; } + } + public class CreateCustomerDto : CustomerDtoBase + { + public string CreatedBy { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(cfg=> + { + cfg.CreateMap().IncludeMembers(x => x.Address) .ForMember(m => m.Id, o => o.Ignore()); + cfg.CreateMap(MemberList.None).ForMember(m => m.AddressLine1, o => o.MapFrom(x => x.Line1)); + cfg.CreateMap().IncludeBase().ForMember(m => m.CreatedBy, o => o.Ignore()); + }); + [Fact] + public void Should_inherit_IncludeMembers() => Mapper.Map(new Customer { Address = new Address { Postcode = "Postcode" } }).Postcode.ShouldBe("Postcode"); +} +public class IncludeMembersWithIncludeBaseOverride : AutoMapperSpecBase +{ + public class Customer + { + public int Id { get; set; } + public string Name { get; set; } + public Address Address { get; set; } + public Address NewAddress { get; set; } + } + public class Address + { + public string Line1 { get; set; } + public string Postcode { get; set; } + } + public class CustomerDtoBase + { + public int Id { get; set; } + public string Name { get; set; } + public string AddressLine1 { get; set; } + public string Postcode { get; set; } + } + public class CreateCustomerDto : CustomerDtoBase + { + public string CreatedBy { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().IncludeMembers(x => x.Address).ForMember(m => m.Id, o => o.Ignore()); + cfg.CreateMap(MemberList.None).ForMember(m => m.AddressLine1, o => o.MapFrom(x => x.Line1)); + cfg.CreateMap(MemberList.None).IncludeBase(); + cfg.CreateMap().IncludeMembers(s => s.NewAddress).IncludeBase().ForMember(m => m.CreatedBy, o => o.Ignore()); + }); + [Fact] + public void Should_override_IncludeMembers() => Mapper.Map(new Customer { NewAddress = new Address { Postcode = "Postcode" } }).Postcode.ShouldBe("Postcode"); +} +public class IncludeMembersWithIncludeBaseOverrideMapFrom : AutoMapperSpecBase +{ + public class Customer + { + public int Id { get; set; } + public string Name { get; set; } + public Address Address { get; set; } } - - public class IncludeMembersWithResolver : AutoMapperSpecBase + public class Address { - class Source - { - public string Name { get; set; } - public InnerSource InnerSource { get; set; } - public OtherInnerSource OtherInnerSource { get; set; } - } - class InnerSource - { - public string Name { get; set; } - public string Description1 { get; set; } - } - class OtherInnerSource - { - public string Name { get; set; } - public string Description { get; set; } - public string Title1 { get; set; } - } - class Destination - { - public string Name { get; set; } - public string Description { get; set; } - public string Title { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().IncludeMembers(s => s.InnerSource, s => s.OtherInnerSource); - cfg.CreateMap(MemberList.None).ForMember(d => d.Description, o => o.MapFrom()); - cfg.CreateMap(MemberList.None).ForMember(d => d.Title, o => o.MapFrom()); - }); - [Fact] - public void Should_flatten() - { - var source = new Source { Name = "name", InnerSource = new InnerSource { Description1 = "description" }, OtherInnerSource = new OtherInnerSource { Title1 = "title" } }; - var destination = Mapper.Map(source); - destination.Name.ShouldBe("name"); - destination.Description.ShouldBe("description"); - destination.Title.ShouldBe("title"); - } - - private class DescriptionResolver : IValueResolver - { - public string Resolve(InnerSource source, Destination destination, string destMember, ResolutionContext context) => source.Description1; - } - - private class TitleResolver : IValueResolver - { - public string Resolve(OtherInnerSource source, Destination destination, string destMember, ResolutionContext context) => source.Title1; - } + public string Line1 { get; set; } + public string Postcode { get; set; } } - - public class IncludeMembersWithMemberResolver : AutoMapperSpecBase + public class CustomerDtoBase { - class Source - { - public string Name { get; set; } - public InnerSource InnerSource { get; set; } - public OtherInnerSource OtherInnerSource { get; set; } - } - class InnerSource - { - public string Name { get; set; } - public string Description1 { get; set; } - } - class OtherInnerSource - { - public string Name { get; set; } - public string Description { get; set; } - public string Title1 { get; set; } - } - class Destination - { - public string Name { get; set; } - public string Description { get; set; } - public string Title { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().IncludeMembers(s => s.InnerSource, s => s.OtherInnerSource); - cfg.CreateMap(MemberList.None).ForMember(d => d.Description, o => o.MapFrom(s=>s.Description1)); - cfg.CreateMap(MemberList.None).ForMember(d => d.Title, o => o.MapFrom("Title1")); - }); - [Fact] - public void Should_flatten() - { - var source = new Source { Name = "name", InnerSource = new InnerSource { Description1 = "description" }, OtherInnerSource = new OtherInnerSource { Title1 = "title" } }; - var destination = Mapper.Map(source); - destination.Name.ShouldBe("name"); - destination.Description.ShouldBe("description"); - destination.Title.ShouldBe("title"); - } - - private class DescriptionResolver : IMemberValueResolver - { - public string Resolve(InnerSource source, Destination destination, string sourceMember, string destMember, ResolutionContext context) => sourceMember; - } - - private class TitleResolver : IMemberValueResolver - { - public string Resolve(OtherInnerSource source, Destination destination, string sourceMember, string destMember, ResolutionContext context) => sourceMember; - } + public int Id { get; set; } + public string Name { get; set; } + public string AddressLine1 { get; set; } + public string Postcode { get; set; } } - public class IncludeMembersWithValueConverter : AutoMapperSpecBase + public class CreateCustomerDto : CustomerDtoBase { - class Source - { - public string Name { get; set; } - public InnerSource InnerSource { get; set; } - public OtherInnerSource OtherInnerSource { get; set; } - } - class InnerSource - { - public string Name { get; set; } - public string Description1 { get; set; } - } - class OtherInnerSource - { - public string Name { get; set; } - public string Description { get; set; } - public string Title1 { get; set; } - } - class Destination - { - public string Name { get; set; } - public string Description { get; set; } - public string Title { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().IncludeMembers(s => s.InnerSource, s => s.OtherInnerSource); - cfg.CreateMap(MemberList.None).ForMember(d => d.Description, o => o.ConvertUsing(s => s.Description1)); - cfg.CreateMap(MemberList.None).ForMember(d => d.Title, o => o.ConvertUsing("Title1")); - }); - [Fact] - public void Should_flatten() - { - var source = new Source { Name = "name", InnerSource = new InnerSource { Description1 = "description" }, OtherInnerSource = new OtherInnerSource { Title1 = "title" } }; - var destination = Mapper.Map(source); - destination.Name.ShouldBe("name"); - destination.Description.ShouldBe("description"); - destination.Title.ShouldBe("title"); - } - - private class ValueConverter : IValueConverter - { - public string Convert(string sourceMember, ResolutionContext context) => sourceMember; - } + public string CreatedBy { get; set; } } - - public class IncludeMembersWithConditions : AutoMapperSpecBase + protected override MapperConfiguration CreateConfiguration() => new(cfg => { - class Source - { - public string Name { get; set; } - public InnerSource InnerSource { get; set; } - public OtherInnerSource OtherInnerSource { get; set; } - } - class InnerSource - { - public string Name { get; set; } - public string Description { get; set; } - } - class OtherInnerSource - { - public string Name { get; set; } - public string Description { get; set; } - public string Title { get; set; } - } - class Destination - { - public string Name { get; set; } - public string Description { get; set; } - public string Title { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().IncludeMembers(s => s.InnerSource, s => s.OtherInnerSource); - cfg.CreateMap(MemberList.None).ForMember(d => d.Description, o => o.Condition((s, d, sm, dm, c) => false)); - cfg.CreateMap(MemberList.None).ForMember(d => d.Description, o => o.Condition((s, d, sm, dm, c) => true)); - }); - [Fact] - public void Should_flatten() - { - var source = new Source { Name = "name", InnerSource = new InnerSource { Description = "description" }, OtherInnerSource = new OtherInnerSource { Title = "title" } }; - var destination = Mapper.Map(source); - destination.Name.ShouldBe("name"); - destination.Description.ShouldBeNull(); - destination.Title.ShouldBe("title"); - } + cfg.CreateMap().IncludeMembers(x => x.Address).ForMember(m => m.Id, o => o.Ignore()); + cfg.CreateMap(MemberList.None).ForMember(m => m.AddressLine1, o => o.MapFrom(x => x.Line1)); + cfg.CreateMap() + .IncludeBase() + .ForMember(d=>d.Postcode, o=>o.MapFrom((s, d)=>s.Name)) + .ForMember(m => m.CreatedBy, o => o.Ignore()); + }); + [Fact] + public void Should_override_IncludeMembers() => Mapper.Map(new Customer { Name = "Postcode", Address = new Address() }).Postcode.ShouldBe("Postcode"); +} +public class IncludeMembersWithIncludeBaseOverrideConvention : AutoMapperSpecBase +{ + public class Customer + { + public int Id { get; set; } + public string Name { get; set; } + public Address Address { get; set; } } - public class IncludeMembersWithPreConditions : AutoMapperSpecBase + public class NewCustomer : Customer { - class Source - { - public string Name { get; set; } - public InnerSource InnerSource { get; set; } - public OtherInnerSource OtherInnerSource { get; set; } - } - class InnerSource - { - public string Name { get; set; } - public string Description { get; set; } - } - class OtherInnerSource - { - public string Name { get; set; } - public string Description { get; set; } - public string Title { get; set; } - } - class Destination - { - public string Name { get; set; } - public string Description { get; set; } - public string Title { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().IncludeMembers(s => s.InnerSource, s => s.OtherInnerSource); - cfg.CreateMap(MemberList.None).ForMember(d => d.Description, o => o.PreCondition((s, d, c) => false)); - cfg.CreateMap(MemberList.None).ForMember(d => d.Description, o => o.PreCondition((s, d, c) => true)); - }); - [Fact] - public void Should_flatten() - { - var source = new Source { Name = "name", InnerSource = new InnerSource { Description = "description" }, OtherInnerSource = new OtherInnerSource { Title = "title" } }; - var destination = Mapper.Map(source); - destination.Name.ShouldBe("name"); - destination.Description.ShouldBeNull(); - destination.Title.ShouldBe("title"); - } + public string Postcode { get; set; } } - public class IncludeMembersCycle : AutoMapperSpecBase + public class Address { - class Source - { - public string Name { get; set; } - public InnerSource InnerSource { get; set; } - public OtherInnerSource OtherInnerSource { get; set; } - } - class InnerSource - { - public string Name { get; set; } - public string Description { get; set; } - public Source Parent { get; set; } - } - class OtherInnerSource - { - public string Name { get; set; } - public string Description { get; set; } - public string Title { get; set; } - public Source Parent { get; set; } - } - class Destination - { - public string Name { get; set; } - public string Description { get; set; } - public string Title { get; set; } - public Destination Parent { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().IncludeMembers(s => s.InnerSource, s => s.OtherInnerSource); - cfg.CreateMap(MemberList.None).IncludeMembers(s=>s.Parent); - cfg.CreateMap(MemberList.None).IncludeMembers(s=>s.Parent); - }); - [Fact] - public void Should_flatten() - { - var source = new Source { Name = "name", InnerSource = new InnerSource { Description = "description" }, OtherInnerSource = new OtherInnerSource { Title = "title" } }; - source.InnerSource.Parent = source; - source.OtherInnerSource.Parent = source; - var destination = Mapper.Map(source); - destination.Name.ShouldBe("name"); - destination.Description.ShouldBe("description"); - destination.Title.ShouldBe("title"); - destination.Parent.ShouldBe(destination); - } - } - public class IncludeMembersReverseMap : AutoMapperSpecBase - { - class Source - { - public string Name { get; set; } - public InnerSource InnerSource { get; set; } - public OtherInnerSource OtherInnerSource { get; set; } - } - class InnerSource - { - public string Name { get; set; } - public string Description { get; set; } - } - class OtherInnerSource - { - public string Name { get; set; } - public string Description { get; set; } - public string Title { get; set; } - } - class Destination - { - public string Name { get; set; } - public string Description { get; set; } - public string Title { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().IncludeMembers(s => s.InnerSource, s => s.OtherInnerSource).ReverseMap(); - cfg.CreateMap(MemberList.None).ReverseMap(); - cfg.CreateMap(MemberList.None).ReverseMap(); - }); - [Fact] - public void Should_unflatten() - { - var source = Mapper.Map(new Destination { Description = "description", Name = "name", Title = "title" }); - source.Name.ShouldBe("name"); - source.InnerSource.Name.ShouldBe("name"); - source.OtherInnerSource.Name.ShouldBe("name"); - source.InnerSource.Description.ShouldBe("description"); - source.OtherInnerSource.Description.ShouldBe("description"); - source.OtherInnerSource.Title.ShouldBe("title"); - } - } - public class IncludeMembersReverseMapOverride : AutoMapperSpecBase - { - class Source - { - public string Name { get; set; } - public InnerSource InnerSource { get; set; } - public OtherInnerSource OtherInnerSource { get; set; } - } - class InnerSource - { - public string Name { get; set; } - public string Description { get; set; } - } - class OtherInnerSource - { - public string Name { get; set; } - public string Description { get; set; } - public string Title { get; set; } - } - class Destination - { - public string Name { get; set; } - public string Description { get; set; } - public string Title { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().IncludeMembers(s => s.InnerSource, s => s.OtherInnerSource).ReverseMap() - .ForMember(d=>d.InnerSource, o=>o.Ignore()) - .ForMember(d=>d.OtherInnerSource, o=>o.Ignore()); - cfg.CreateMap(MemberList.None); - cfg.CreateMap(MemberList.None); - }); - [Fact] - public void Should_unflatten() - { - var source = Mapper.Map(new Destination { Description = "description", Name = "name", Title = "title" }); - source.Name.ShouldBe("name"); - source.InnerSource.ShouldBeNull(); - source.OtherInnerSource.ShouldBeNull(); - } + public string Line1 { get; set; } + public string Postcode { get; set; } } - - public class ReverseMapToIncludeMembers : AutoMapperSpecBase + public class CustomerDtoBase { - class Source - { - public string Name { get; set; } - public InnerSource InnerSource { get; set; } - public OtherInnerSource OtherInnerSource { get; set; } - } - class InnerSource - { - public string Name { get; set; } - public string Description { get; set; } - } - class OtherInnerSource - { - public string Name { get; set; } - public string Description { get; set; } - public string Title { get; set; } - } - class Destination - { - public string Name { get; set; } - public string Description { get; set; } - public string Title { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ForMember(d => d.InnerSource, o => o.MapFrom(s => s)) - .ForMember(d => d.OtherInnerSource, o => o.MapFrom(s => s)) - .ReverseMap(); - cfg.CreateMap(MemberList.None).ReverseMap(); - cfg.CreateMap(MemberList.None).ReverseMap(); - }); - [Fact] - public void Should_flatten() - { - var source = new Source { Name = "name", InnerSource = new InnerSource { Description = "description" }, OtherInnerSource = new OtherInnerSource { Title = "title" } }; - var destination = Mapper.Map(source); - destination.Name.ShouldBe("name"); - destination.Description.ShouldBe("description"); - destination.Title.ShouldBe("title"); - } + public int Id { get; set; } + public string Name { get; set; } + public string AddressLine1 { get; set; } + public string Postcode { get; set; } } - public class ReverseMapToIncludeMembersOverride : AutoMapperSpecBase + public class CreateCustomerDto : CustomerDtoBase { - class Source - { - public string Name { get; set; } - public InnerSource InnerSource { get; set; } - public OtherInnerSource OtherInnerSource { get; set; } - } - class InnerSource - { - public string Name { get; set; } - public string Description { get; set; } - } - class OtherInnerSource - { - public string Name { get; set; } - public string Description { get; set; } - public string Title { get; set; } - } - class Destination - { - public string Name { get; set; } - public string Description { get; set; } - public string Title { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(MemberList.None) - .ForMember(d => d.InnerSource, o => o.MapFrom(s => s)) - .ForMember(d => d.OtherInnerSource, o => o.MapFrom(s => s)) - .ReverseMap() - .IncludeMembers(); - cfg.CreateMap(MemberList.None).ReverseMap(); - cfg.CreateMap(MemberList.None).ReverseMap(); - }); - [Fact] - public void Should_flatten() - { - var source = new Source { Name = "name", InnerSource = new InnerSource { Description = "description" }, OtherInnerSource = new OtherInnerSource { Title = "title" } }; - var destination = Mapper.Map(source); - destination.Name.ShouldBe("name"); - destination.Description.ShouldBeNull(); - destination.Title.ShouldBeNull(); - } + public string CreatedBy { get; set; } } - public class IncludeMembersWithAfterMap : AutoMapperSpecBase + protected override MapperConfiguration CreateConfiguration() => new(cfg => { - class Source - { - public string Name { get; set; } - public InnerSource InnerSource { get; set; } - public OtherInnerSource OtherInnerSource { get; set; } - } - class InnerSource - { - public string Name { get; set; } - public string Description { get; set; } - } - class OtherInnerSource - { - public string Name { get; set; } - public string Description { get; set; } - public string Title { get; set; } - } - class Destination - { - public string Name { get; set; } - public string Description { get; set; } - public string Title { get; set; } - } - bool afterMap, beforeMap; - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().IncludeMembers(s => s.InnerSource, s => s.OtherInnerSource); - cfg.CreateMap(MemberList.None).AfterMap((s,d)=>afterMap=true); - cfg.CreateMap(MemberList.None).BeforeMap((s, d, c) => beforeMap = true); - }); - [Fact] - public void Should_flatten() - { - var source = new Source { Name = "name", InnerSource = new InnerSource { Description = "description" }, OtherInnerSource = new OtherInnerSource { Title = "title" } }; - var destination = Mapper.Map(source); - destination.Name.ShouldBe("name"); - destination.Description.ShouldBe("description"); - destination.Title.ShouldBe("title"); - afterMap.ShouldBeTrue(); - beforeMap.ShouldBeTrue(); - } + cfg.CreateMap().IncludeMembers(x => x.Address).ForMember(m => m.Id, o => o.Ignore()); + cfg.CreateMap(MemberList.None).ForMember(m => m.AddressLine1, o => o.MapFrom(x => x.Line1)); + cfg.CreateMap().IncludeBase().ForMember(m => m.CreatedBy, o => o.Ignore()); + }); + [Fact] + public void Should_override_IncludeMembers() => Mapper.Map(new NewCustomer { Postcode = "Postcode", Address = new Address() }).Postcode.ShouldBe("Postcode"); +} +public class IncludeMembersWithValueTypeValidation : AutoMapperSpecBase +{ + class Source + { + public InnerSource InnerSource { get; set; } } - - public class IncludeMembersWithForPath : AutoMapperSpecBase + struct InnerSource { - class Source - { - public string Name { get; set; } - public InnerSource InnerSource { get; set; } - public OtherInnerSource OtherInnerSource { get; set; } - } - class InnerSource - { - public string Name { get; set; } - public string Description { get; set; } - } - class OtherInnerSource - { - public string Name { get; set; } - public string Description { get; set; } - public string Title { get; set; } - } - class Destination - { - public string Name { get; set; } - public InnerDestination InnerDestination { get; set; } - } - class InnerDestination - { - public string Description { get; set; } - public string Title { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().IncludeMembers(s => s.InnerSource, s => s.OtherInnerSource); - cfg.CreateMap(MemberList.None).ForPath(d=>d.InnerDestination.Description, o=> - { - o.MapFrom(s => s.Description); - o.Condition(c => true); - }); - cfg.CreateMap(MemberList.None).ForPath(d=>d.InnerDestination.Title, o=> - { - o.MapFrom(s => s.Title); - o.Condition(c => true); - }); - }); - [Fact] - public void Should_flatten() - { - var source = new Source { Name = "name", InnerSource = new InnerSource { Description = "description" }, OtherInnerSource = new OtherInnerSource { Title = "title" } }; - var destination = Mapper.Map(source); - destination.Name.ShouldBe("name"); - destination.InnerDestination.Description.ShouldBe("description"); - destination.InnerDestination.Title.ShouldBe("title"); - } + public string Name { get; set; } } - public class IncludeMembersTransformers : AutoMapperSpecBase + class Destination { - class Source - { - public string Name { get; set; } - public InnerSource InnerSource { get; set; } - public OtherInnerSource OtherInnerSource { get; set; } - } - class InnerSource - { - public string Name { get; set; } - public string Description { get; set; } - } - class OtherInnerSource - { - public string Name { get; set; } - public string Description { get; set; } - public string Title { get; set; } - } - class Destination - { - public string Name { get; set; } - public string Description { get; set; } - public string Title { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().IncludeMembers(s => s.InnerSource, s => s.OtherInnerSource).AddTransform(s => s + "Main"); - cfg.CreateMap(MemberList.None).ForMember(d=>d.Description, o=>o.AddTransform(s=>s+"Extra")).AddTransform(s => s + "Ex"); - cfg.CreateMap(MemberList.None).ForMember(d => d.Title, o => o.AddTransform(s => s + "Extra")).AddTransform(s => s + "Ex"); - }); - [Fact] - public void Should_flatten() - { - var source = new Source { Name = "name", InnerSource = new InnerSource { Description = "description" }, OtherInnerSource = new OtherInnerSource { Title = "title" } }; - var destination = Mapper.Map(source); - destination.Name.ShouldBe("nameMain"); - destination.Description.ShouldBe("descriptionExtraExMain"); - destination.Title.ShouldBe("titleExtraExMain"); - } + public string Name { get; set; } } - public class IncludeMembersTransformersPerMember : AutoMapperSpecBase + protected override MapperConfiguration CreateConfiguration() => new(cfg => { - class Source - { - public string Name { get; set; } - public InnerSource InnerSource { get; set; } - public OtherInnerSource OtherInnerSource { get; set; } - } - class InnerSource - { - public string Name { get; set; } - public string Description { get; set; } - } - class OtherInnerSource - { - public string Name { get; set; } - public string Description { get; set; } - public string Title { get; set; } - } - class Destination - { - public string Name { get; set; } - public string Description { get; set; } - public string Title { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().IncludeMembers(s => s.InnerSource, s => s.OtherInnerSource); - cfg.CreateMap(MemberList.None).ForMember(d=>d.Description, o=>o.AddTransform(s=>s+"Ex")); - cfg.CreateMap(MemberList.None).ForMember(d => d.Title, o => o.AddTransform(s => s + "Ex")); - }); - [Fact] - public void Should_flatten() - { - var source = new Source { Name = "name", InnerSource = new InnerSource { Description = "description" }, OtherInnerSource = new OtherInnerSource { Title = "title" } }; - var destination = Mapper.Map(source); - destination.Name.ShouldBe("name"); - destination.Description.ShouldBe("descriptionEx"); - destination.Title.ShouldBe("titleEx"); - } + cfg.CreateMap().IncludeMembers(s => s.InnerSource); + cfg.CreateMap(MemberList.None); + }); + [Fact] + public void Validate() => AssertConfigurationIsValid(); +} +public class CascadedIncludeMembers : AutoMapperSpecBase +{ + public class Source + { + public int Id; + public Level1 FieldLevel1; } - public class IncludeMembersWithGenerics : AutoMapperSpecBase + public class Level1 { - class Source - { - public string Name { get; set; } - public TInnerSource InnerSource { get; set; } - public TOtherInnerSource OtherInnerSource { get; set; } - } - class InnerSource - { - public string Name { get; set; } - public string Description { get; set; } - } - class OtherInnerSource - { - public string Name { get; set; } - public string Description { get; set; } - public string Title { get; set; } - } - class Destination - { - public string Name { get; set; } - public string Description { get; set; } - public string Title { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(typeof(Source<,>), typeof(Destination), MemberList.None).IncludeMembers("InnerSource", "OtherInnerSource"); - cfg.CreateMap(MemberList.None); - cfg.CreateMap(MemberList.None); - }); - [Fact] - public void Should_flatten() - { - var source = new Source { Name = "name", InnerSource = new InnerSource { Description = "description" }, OtherInnerSource = new OtherInnerSource { Title = "title" } }; - var destination = Mapper.Map(source); - destination.Name.ShouldBe("name"); - destination.Description.ShouldBe("description"); - destination.Title.ShouldBe("title"); - } + public Level2 FieldLevel2; + public long Level1Field; } - - public class IncludeMembersWithGenericsInvalidStrings + public class Level2 { - class Source - { - public string Name { get; set; } - public TInnerSource InnerSource { get; set; } - public TOtherInnerSource OtherInnerSource { get; set; } - } - class Destination - { - public string Name { get; set; } - public string Description { get; set; } - public string Title { get; set; } - } - [Fact] - public void Should_throw() - { - new MapperConfiguration(cfg => - { - Assert.Throws(() => cfg.CreateMap(typeof(Source<,>), typeof(Destination), MemberList.None).IncludeMembers("dInnerSource", "fOtherInnerSource")); - }); - } + public long TheField; } - - public class IncludeMembersReverseMapGenerics : AutoMapperSpecBase + public class Destination { - class Source - { - public string Name { get; set; } - public TInnerSource InnerSource { get; set; } - public TOtherInnerSource OtherInnerSource { get; set; } - } - class InnerSource - { - public string Name { get; set; } - public string Description { get; set; } - } - class OtherInnerSource - { - public string Name { get; set; } - public string Description { get; set; } - public string Title { get; set; } - } - class Destination - { - public string Name { get; set; } - public string Description { get; set; } - public string Title { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(typeof(Source<,>), typeof(Destination), MemberList.None).IncludeMembers("InnerSource", "OtherInnerSource").ReverseMap(); - cfg.CreateMap(MemberList.None).ReverseMap(); - cfg.CreateMap(MemberList.None).ReverseMap(); - }); - [Fact] - public void Should_unflatten() - { - var source = Mapper.Map>(new Destination { Description = "description", Name = "name", Title = "title" }); - source.Name.ShouldBe("name"); - source.InnerSource.Name.ShouldBe("name"); - source.OtherInnerSource.Name.ShouldBe("name"); - source.InnerSource.Description.ShouldBe("description"); - source.OtherInnerSource.Description.ShouldBe("description"); - source.OtherInnerSource.Title.ShouldBe("title"); - } - } - public class IncludeMembersReverseMapGenericsOverride : AutoMapperSpecBase - { - class Source - { - public string Name { get; set; } - public TInnerSource InnerSource { get; set; } - public TOtherInnerSource OtherInnerSource { get; set; } - } - class InnerSource - { - public string Name { get; set; } - public string Description { get; set; } - } - class OtherInnerSource - { - public string Name { get; set; } - public string Description { get; set; } - public string Title { get; set; } - } - class Destination - { - public string Name { get; set; } - public string Description { get; set; } - public string Title { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(typeof(Source<,>), typeof(Destination), MemberList.None).IncludeMembers("InnerSource", "OtherInnerSource").ReverseMap() - .ForMember("InnerSource", o=>o.Ignore()) - .ForMember("OtherInnerSource", o=>o.Ignore()); - cfg.CreateMap(MemberList.None); - cfg.CreateMap(MemberList.None); - }); - [Fact] - public void Should_unflatten() - { - var source = Mapper.Map>(new Destination { Description = "description", Name = "name", Title = "title" }); - source.Name.ShouldBe("name"); - source.InnerSource.ShouldBeNull(); - source.OtherInnerSource.ShouldBeNull(); - } + public int Id; + public long TheField; + public long Level1Field; } - public class ReverseMapToIncludeMembersGenerics : AutoMapperSpecBase + protected override MapperConfiguration CreateConfiguration() => new(cfg => { - class Source - { - public string Name { get; set; } - public TInnerSource InnerSource { get; set; } - public TOtherInnerSource OtherInnerSource { get; set; } - } - class InnerSource - { - public string Name { get; set; } - public string Description { get; set; } - } - class OtherInnerSource - { - public string Name { get; set; } - public string Description { get; set; } - public string Title { get; set; } - } - class Destination - { - public string Name { get; set; } - public string Description { get; set; } - public string Title { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(typeof(Destination), typeof(Source<,>)) - .ForMember("InnerSource", o => o.MapFrom(s => s)) - .ForMember("OtherInnerSource", o => o.MapFrom(s => s)) - .ReverseMap(); - cfg.CreateMap(MemberList.None); - cfg.CreateMap(MemberList.None); - }); - [Fact] - public void Should_flatten() - { - var source = new Source { Name = "name", InnerSource = new InnerSource { Description = "description" }, OtherInnerSource = new OtherInnerSource { Title = "title" } }; - var destination = Mapper.Map(source); - destination.Name.ShouldBe("name"); - destination.Description.ShouldBe("description"); - destination.Title.ShouldBe("title"); - } + cfg.CreateMap().IncludeMembers(s => s.FieldLevel1); + cfg.CreateMap(MemberList.None).IncludeMembers(s => s.FieldLevel2); + cfg.CreateMap(MemberList.None); + }); + [Fact] + public void Should_work() + { + var dest = Map(new Source { Id = 1, FieldLevel1 = new Level1 { Level1Field = 3, FieldLevel2 = new Level2 { TheField = 2 } } }); + dest.Id.ShouldBe(1); + dest.TheField.ShouldBe(2); + dest.Level1Field.ShouldBe(3); } - public class ReverseMapToIncludeMembersGenericsOverride : AutoMapperSpecBase +} +public class CascadedIncludeMembersForPath : AutoMapperSpecBase +{ + public class Source { - class Source - { - public string Name { get; set; } - public TInnerSource InnerSource { get; set; } - public TOtherInnerSource OtherInnerSource { get; set; } - } - class InnerSource - { - public string Name { get; set; } - public string Description { get; set; } - } - class OtherInnerSource - { - public string Name { get; set; } - public string Description { get; set; } - public string Title { get; set; } - } - class Destination - { - public string Name { get; set; } - public string Description { get; set; } - public string Title { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(typeof(Destination), typeof(Source<,>)) - .ForMember("InnerSource", o => o.MapFrom(s => s)) - .ForMember("OtherInnerSource", o => o.MapFrom(s => s)) - .ReverseMap() - .IncludeMembers(); - cfg.CreateMap(MemberList.None); - cfg.CreateMap(MemberList.None); - }); - [Fact] - public void Should_flatten() - { - var source = new Source { Name = "name", InnerSource = new InnerSource { Description = "description" }, OtherInnerSource = new OtherInnerSource { Title = "title" } }; - var destination = Mapper.Map(source); - destination.Name.ShouldBe("name"); - destination.Description.ShouldBeNull(); - destination.Title.ShouldBeNull(); - } + public int Id; + public Level1 FieldLevel1; } - public class IncludeMembersSourceValidation : AutoMapperSpecBase + public class Level1 { - class Source - { - public string Name { get; set; } - public InnerSource InnerSource { get; set; } - public OtherInnerSource OtherInnerSource { get; set; } - } - class InnerSource - { - public string Name { get; set; } - public string Description { get; set; } - } - class OtherInnerSource - { - public string Name { get; set; } - public string Description { get; set; } - public string Title { get; set; } - } - class Destination - { - public string Name { get; set; } - public string Description { get; set; } - public string Title { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(MemberList.Source).IncludeMembers(s => s.InnerSource, s => s.OtherInnerSource); - cfg.CreateMap(MemberList.None); - cfg.CreateMap(MemberList.None); - }); - [Fact] - public void Should_flatten() - { - var source = new Source { Name = "name", InnerSource = new InnerSource { Description = "description" }, OtherInnerSource = new OtherInnerSource { Title = "title" } }; - var destination = Mapper.Map(source); - destination.Name.ShouldBe("name"); - destination.Description.ShouldBe("description"); - destination.Title.ShouldBe("title"); - } - + public Level2 FieldLevel2; + public long Level1Field; } - public class IncludeMembersWithGenericsSourceValidation : AutoMapperSpecBase + public class Level2 { - class Source - { - public string Name { get; set; } - public TInnerSource InnerSource { get; set; } - public TOtherInnerSource OtherInnerSource { get; set; } - } - class InnerSource - { - public string Name { get; set; } - public string Description { get; set; } - } - class OtherInnerSource - { - public string Name { get; set; } - public string Description { get; set; } - public string Title { get; set; } - } - class Destination - { - public string Name { get; set; } - public string Description { get; set; } - public string Title { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(typeof(Source<,>), typeof(Destination), MemberList.Source).IncludeMembers("InnerSource", "OtherInnerSource"); - cfg.CreateMap(MemberList.None); - cfg.CreateMap(MemberList.None); - }); - [Fact] - public void Should_flatten() - { - var source = new Source { Name = "name", InnerSource = new InnerSource { Description = "description" }, OtherInnerSource = new OtherInnerSource { Title = "title" } }; - var destination = Mapper.Map(source); - destination.Name.ShouldBe("name"); - destination.Description.ShouldBe("description"); - destination.Title.ShouldBe("title"); - } + public long TheField; } - public class IncludeMembersWithInclude : AutoMapperSpecBase + public class Destination { - public class ParentOfSource - { - public Source InnerSource { get; set; } - } - public class Source : SourceBase - { - } - public class SourceBase - { - public string FirstName { get; set; } - public string LastName { get; set; } - } - public class Destination - { - public string FullName { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().ForMember(dest => dest.FullName, opt => opt.MapFrom(src => src.FirstName + " " + src.LastName)).IncludeAllDerived(); - cfg.CreateMap().IncludeMembers(src => src.InnerSource); - cfg.CreateMap(); - }); - [Fact] - public void Should_inherit_configuration() => Mapper.Map(new ParentOfSource { InnerSource = new Source { FirstName = "first", LastName = "last" } }).FullName.ShouldBe("first last"); + public int Id; + public long TheField; + public long Level1Field; } - public class IncludeMembersWithIncludeDifferentOrder : AutoMapperSpecBase + protected override MapperConfiguration CreateConfiguration() => new(cfg => { - public class ParentOfSource - { - public Source InnerSource { get; set; } - } - public class Source : SourceBase - { - } - public class SourceBase - { - public string FirstName { get; set; } - public string LastName { get; set; } - } - public class Destination - { - public string FullName { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().ForMember(dest => dest.FullName, opt => opt.MapFrom(src => src.FirstName + " " + src.LastName)).IncludeAllDerived(); - cfg.CreateMap(); - cfg.CreateMap().IncludeMembers(src => src.InnerSource); - }); - [Fact] - public void Should_inherit_configuration() => Mapper.Map(new ParentOfSource { InnerSource = new Source { FirstName = "first", LastName = "last" } }).FullName.ShouldBe("first last"); + cfg.CreateMap().IncludeMembers(s => s.FieldLevel1); + cfg.CreateMap(MemberList.None).IncludeMembers(s => s.FieldLevel2); + cfg.CreateMap(MemberList.None).ForPath(d => d.TheField, o => o.MapFrom(s => s.TheField)); + }); + [Fact] + public void Should_work() + { + var dest = Map(new Source { Id = 1, FieldLevel1 = new Level1 { Level1Field = 3, FieldLevel2 = new Level2 { TheField = 2 } } }); + dest.Id.ShouldBe(1); + dest.TheField.ShouldBe(2); + dest.Level1Field.ShouldBe(3); } - public class IncludeMembersWithIncludeBase : AutoMapperSpecBase +} +public class IncludeMembersWithCascadedIncludeBase : AutoMapperSpecBase +{ + class Item { - public class Customer - { - public int Id { get; set; } - public string Name { get; set; } - public Address Address { get; set; } - } - public class Address - { - public string Line1 { get; set; } - public string Postcode { get; set; } - } - public class CustomerDtoBase - { - public int Id { get; set; } - public string Name { get; set; } - public string AddressLine1 { get; set; } - public string Postcode { get; set; } - } - public class CreateCustomerDto : CustomerDtoBase - { - public string CreatedBy { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg=> - { - cfg.CreateMap().IncludeMembers(x => x.Address) .ForMember(m => m.Id, o => o.Ignore()); - cfg.CreateMap(MemberList.None).ForMember(m => m.AddressLine1, o => o.MapFrom(x => x.Line1)); - cfg.CreateMap().IncludeBase().ForMember(m => m.CreatedBy, o => o.Ignore()); - }); - [Fact] - public void Should_inherit_IncludeMembers() => Mapper.Map(new Customer { Address = new Address { Postcode = "Postcode" } }).Postcode.ShouldBe("Postcode"); + public int Id { get; set; } + public MetaData MetaData { get; set; } + public string Signature { get; set; } } - public class IncludeMembersWithIncludeBaseOverride : AutoMapperSpecBase + class MetaData { - public class Customer - { - public int Id { get; set; } - public string Name { get; set; } - public Address Address { get; set; } - public Address NewAddress { get; set; } - } - public class Address - { - public string Line1 { get; set; } - public string Postcode { get; set; } - } - public class CustomerDtoBase - { - public int Id { get; set; } - public string Name { get; set; } - public string AddressLine1 { get; set; } - public string Postcode { get; set; } - } - public class CreateCustomerDto : CustomerDtoBase - { - public string CreatedBy { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().IncludeMembers(x => x.Address).ForMember(m => m.Id, o => o.Ignore()); - cfg.CreateMap(MemberList.None).ForMember(m => m.AddressLine1, o => o.MapFrom(x => x.Line1)); - cfg.CreateMap(MemberList.None).IncludeBase(); - cfg.CreateMap().IncludeMembers(s => s.NewAddress).IncludeBase().ForMember(m => m.CreatedBy, o => o.Ignore()); - }); - [Fact] - public void Should_override_IncludeMembers() => Mapper.Map(new Customer { NewAddress = new Address { Postcode = "Postcode" } }).Postcode.ShouldBe("Postcode"); + public string Hash { get; set; } } - public class IncludeMembersWithIncludeBaseOverrideMapFrom : AutoMapperSpecBase + class ExpiredItem : Item { - public class Customer - { - public int Id { get; set; } - public string Name { get; set; } - public Address Address { get; set; } - } - public class Address - { - public string Line1 { get; set; } - public string Postcode { get; set; } - } - public class CustomerDtoBase - { - public int Id { get; set; } - public string Name { get; set; } - public string AddressLine1 { get; set; } - public string Postcode { get; set; } - } - public class CreateCustomerDto : CustomerDtoBase - { - public string CreatedBy { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().IncludeMembers(x => x.Address).ForMember(m => m.Id, o => o.Ignore()); - cfg.CreateMap(MemberList.None).ForMember(m => m.AddressLine1, o => o.MapFrom(x => x.Line1)); - cfg.CreateMap() - .IncludeBase() - .ForMember(d=>d.Postcode, o=>o.MapFrom((s, d)=>s.Name)) - .ForMember(m => m.CreatedBy, o => o.Ignore()); - }); - [Fact] - public void Should_override_IncludeMembers() => Mapper.Map(new Customer { Name = "Postcode", Address = new Address() }).Postcode.ShouldBe("Postcode"); + public DateTime Expired { get; set; } } - public class IncludeMembersWithIncludeBaseOverrideConvention : AutoMapperSpecBase + class Response { - public class Customer - { - public int Id { get; set; } - public string Name { get; set; } - public Address Address { get; set; } - } - public class NewCustomer : Customer - { - public string Postcode { get; set; } - } - public class Address - { - public string Line1 { get; set; } - public string Postcode { get; set; } - } - public class CustomerDtoBase - { - public int Id { get; set; } - public string Name { get; set; } - public string AddressLine1 { get; set; } - public string Postcode { get; set; } - } - public class CreateCustomerDto : CustomerDtoBase - { - public string CreatedBy { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().IncludeMembers(x => x.Address).ForMember(m => m.Id, o => o.Ignore()); - cfg.CreateMap(MemberList.None).ForMember(m => m.AddressLine1, o => o.MapFrom(x => x.Line1)); - cfg.CreateMap().IncludeBase().ForMember(m => m.CreatedBy, o => o.Ignore()); - }); - [Fact] - public void Should_override_IncludeMembers() => Mapper.Map(new NewCustomer { Postcode = "Postcode", Address = new Address() }).Postcode.ShouldBe("Postcode"); + public int Id { get; set; } + public string Hash { get; set; } } - public class IncludeMembersWithValueTypeValidation : AutoMapperSpecBase + class SignedResponse : Response { - class Source - { - public InnerSource InnerSource { get; set; } - } - struct InnerSource - { - public string Name { get; set; } - } - class Destination - { - public string Name { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().IncludeMembers(s => s.InnerSource); - cfg.CreateMap(MemberList.None); - }); - [Fact] - public void Validate() => AssertConfigurationIsValid(); + public string Signature { get; set; } + public DateTime Expired { get; set; } } - public class CascadedIncludeMembers : AutoMapperSpecBase + protected override MapperConfiguration CreateConfiguration() => new(cfg => { - public class Source - { - public int Id; - public Level1 FieldLevel1; - } - public class Level1 - { - public Level2 FieldLevel2; - public long Level1Field; - } - public class Level2 - { - public long TheField; - } - public class Destination - { - public int Id; - public long TheField; - public long Level1Field; - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().IncludeMembers(s => s.FieldLevel1); - cfg.CreateMap(MemberList.None).IncludeMembers(s => s.FieldLevel2); - cfg.CreateMap(MemberList.None); - }); - [Fact] - public void Should_work() - { - var dest = Map(new Source { Id = 1, FieldLevel1 = new Level1 { Level1Field = 3, FieldLevel2 = new Level2 { TheField = 2 } } }); - dest.Id.ShouldBe(1); - dest.TheField.ShouldBe(2); - dest.Level1Field.ShouldBe(3); - } + cfg.CreateMap(MemberList.None); + cfg.CreateMap().IncludeMembers(src => src.MetaData); + cfg.CreateMap().IncludeBase().ForMember(dest => dest.Expired, opt => opt.Ignore()); + cfg.CreateMap().IncludeBase(); + }); + [Fact] + public void Should_inherit_IncludeMembers() => Mapper.Map(new ExpiredItem { MetaData = new MetaData { Hash = "hash" } }).Hash.ShouldBe("hash"); +} +public class IncludeMembersConstructorMapping : AutoMapperSpecBase +{ + public class Source + { + public int Id; + public Level1 FieldLevel1; } - public class CascadedIncludeMembersForPath : AutoMapperSpecBase + public class Level1 { - public class Source - { - public int Id; - public Level1 FieldLevel1; - } - public class Level1 - { - public Level2 FieldLevel2; - public long Level1Field; - } - public class Level2 - { - public long TheField; - } - public class Destination - { - public int Id; - public long TheField; - public long Level1Field; - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().IncludeMembers(s => s.FieldLevel1); - cfg.CreateMap(MemberList.None).IncludeMembers(s => s.FieldLevel2); - cfg.CreateMap(MemberList.None).ForPath(d => d.TheField, o => o.MapFrom(s => s.TheField)); - }); - [Fact] - public void Should_work() - { - var dest = Map(new Source { Id = 1, FieldLevel1 = new Level1 { Level1Field = 3, FieldLevel2 = new Level2 { TheField = 2 } } }); - dest.Id.ShouldBe(1); - dest.TheField.ShouldBe(2); - dest.Level1Field.ShouldBe(3); - } + public Level2 FieldLevel2; + public long Level1Field; } - public class IncludeMembersWithCascadedIncludeBase : AutoMapperSpecBase + public class Level2 { - class Item - { - public int Id { get; set; } - public MetaData MetaData { get; set; } - public string Signature { get; set; } - } - class MetaData - { - public string Hash { get; set; } - } - class ExpiredItem : Item - { - public DateTime Expired { get; set; } - } - class Response - { - public int Id { get; set; } - public string Hash { get; set; } - } - class SignedResponse : Response - { - public string Signature { get; set; } - public DateTime Expired { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(MemberList.None); - cfg.CreateMap().IncludeMembers(src => src.MetaData); - cfg.CreateMap().IncludeBase().ForMember(dest => dest.Expired, opt => opt.Ignore()); - cfg.CreateMap().IncludeBase(); - }); - [Fact] - public void Should_inherit_IncludeMembers() => Mapper.Map(new ExpiredItem { MetaData = new MetaData { Hash = "hash" } }).Hash.ShouldBe("hash"); + public long TheField; } - public class IncludeMembersConstructorMapping : AutoMapperSpecBase + public record Destination(int Id, long TheField, long Level1Field) { - public class Source - { - public int Id; - public Level1 FieldLevel1; - } - public class Level1 - { - public Level2 FieldLevel2; - public long Level1Field; - } - public class Level2 - { - public long TheField; - } - public record Destination(int Id, long TheField, long Level1Field) - { - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.ShouldUseConstructor = c => c.IsPublic; - cfg.CreateMap().IncludeMembers(s => s.FieldLevel1); - cfg.CreateMap(MemberList.None).IncludeMembers(s => s.FieldLevel2); - cfg.CreateMap(MemberList.None); - }); - [Fact] - public void Should_work() - { - var dest = Map(new Source { Id = 1, FieldLevel1 = new Level1 { Level1Field = 3, FieldLevel2 = new Level2 { TheField = 2 } } }); - dest.Id.ShouldBe(1); - dest.TheField.ShouldBe(2); - dest.Level1Field.ShouldBe(3); - } + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.ShouldUseConstructor = c => c.IsPublic; + cfg.CreateMap().IncludeMembers(s => s.FieldLevel1); + cfg.CreateMap(MemberList.None).IncludeMembers(s => s.FieldLevel2); + cfg.CreateMap(MemberList.None); + }); + [Fact] + public void Should_work() + { + var dest = Map(new Source { Id = 1, FieldLevel1 = new Level1 { Level1Field = 3, FieldLevel2 = new Level2 { TheField = 2 } } }); + dest.Id.ShouldBe(1); + dest.TheField.ShouldBe(2); + dest.Level1Field.ShouldBe(3); } } \ No newline at end of file diff --git a/src/UnitTests/IMappingExpression/NonGenericConstructorTests.cs b/src/UnitTests/IMappingExpression/NonGenericConstructorTests.cs index 0f675aea3d..f49c604cbd 100644 --- a/src/UnitTests/IMappingExpression/NonGenericConstructorTests.cs +++ b/src/UnitTests/IMappingExpression/NonGenericConstructorTests.cs @@ -1,57 +1,56 @@ -namespace AutoMapper.UnitTests.Projection +namespace AutoMapper.UnitTests.Projection; + +using System; +using System.Linq; +using System.Linq.Expressions; +using QueryableExtensions; +using Shouldly; +using Xunit; + +public class NonGenericConstructorTests : AutoMapperSpecBase { - using System; - using System.Linq; - using System.Linq.Expressions; - using QueryableExtensions; - using Shouldly; - using Xunit; - - public class NonGenericConstructorTests : AutoMapperSpecBase + private Dest[] _dest; + + public class Source { - private Dest[] _dest; + public int Value { get; set; } + } - public class Source + public class Dest + { + public Dest() { - public int Value { get; set; } + } - - public class Dest + public Dest(int other) { - public Dest() - { - - } - public Dest(int other) - { - Other = other; - } - - public int Value { get; set; } - [IgnoreMap] - public int Other { get; set; } + Other = other; } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.AddIgnoreMapAttribute(); - cfg.CreateMap(typeof (Source), typeof (Dest)).ConstructUsing(src => new Dest(((Source)src).Value + 10)); - }); + public int Value { get; set; } + [IgnoreMap] + public int Other { get; set; } + } + + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.AddIgnoreMapAttribute(); + cfg.CreateMap(typeof (Source), typeof (Dest)).ConstructUsing(src => new Dest(((Source)src).Value + 10)); + }); - protected override void Because_of() + protected override void Because_of() + { + var values = new[] { - var values = new[] + new Source() { - new Source() - { - Value = 5 - } - }.AsQueryable(); - - _dest = values.ProjectTo(Configuration).ToArray(); - } + Value = 5 + } + }.AsQueryable(); - [Fact] - public void Should_construct_correctly() => _dest[0].Other.ShouldBe(15); + _dest = values.ProjectTo(Configuration).ToArray(); } + + [Fact] + public void Should_construct_correctly() => _dest[0].Other.ShouldBe(15); } \ No newline at end of file diff --git a/src/UnitTests/IMappingExpression/NonGenericProjectEnumTest.cs b/src/UnitTests/IMappingExpression/NonGenericProjectEnumTest.cs index e788b75956..3ac98fe155 100644 --- a/src/UnitTests/IMappingExpression/NonGenericProjectEnumTest.cs +++ b/src/UnitTests/IMappingExpression/NonGenericProjectEnumTest.cs @@ -1,126 +1,125 @@ using System; -namespace AutoMapper.UnitTests.Projection +namespace AutoMapper.UnitTests.Projection; + +using QueryableExtensions; +using Shouldly; +using System.Linq; +using Xunit; + +public class NonGenericProjectEnumTest { - using QueryableExtensions; - using Shouldly; - using System.Linq; - using Xunit; + private MapperConfiguration _config; - public class NonGenericProjectEnumTest + public NonGenericProjectEnumTest() { - private MapperConfiguration _config; - - public NonGenericProjectEnumTest() + _config = new MapperConfiguration(cfg => { - _config = new MapperConfiguration(cfg => - { - cfg.CreateMap(typeof(Customer), typeof(CustomerDto)); - cfg.CreateMap(typeof(CustomerType), typeof(string)).ConvertUsing(ct => ct.ToString().ToUpper()); - }); - } - - [Fact] - public void ProjectingEnumToString() - { - var customers = new[] { new Customer() { FirstName = "Bill", LastName = "White", CustomerType = CustomerType.Vip } }.AsQueryable(); + cfg.CreateMap(typeof(Customer), typeof(CustomerDto)); + cfg.CreateMap(typeof(CustomerType), typeof(string)).ConvertUsing(ct => ct.ToString().ToUpper()); + }); + } - var projected = customers.ProjectTo(_config); - projected.ShouldNotBeNull(); - customers.Single().CustomerType.ToString().ToUpper().ShouldBe(projected.Single().CustomerType); - } + [Fact] + public void ProjectingEnumToString() + { + var customers = new[] { new Customer() { FirstName = "Bill", LastName = "White", CustomerType = CustomerType.Vip } }.AsQueryable(); - public class Customer - { - public string FirstName { get; set; } + var projected = customers.ProjectTo(_config); + projected.ShouldNotBeNull(); + customers.Single().CustomerType.ToString().ToUpper().ShouldBe(projected.Single().CustomerType); + } - public string LastName { get; set; } + public class Customer + { + public string FirstName { get; set; } - public CustomerType CustomerType { get; set; } - } + public string LastName { get; set; } - public class CustomerDto - { - public string FirstName { get; set; } + public CustomerType CustomerType { get; set; } + } - public string LastName { get; set; } + public class CustomerDto + { + public string FirstName { get; set; } - public string CustomerType { get; set; } - } + public string LastName { get; set; } - public enum CustomerType - { - Regular, - Vip, - } + public string CustomerType { get; set; } } - public class NonGenericProjectAndMapEnumTest + public enum CustomerType { - private IMapper _mapper; + Regular, + Vip, + } +} - public NonGenericProjectAndMapEnumTest() - { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap(typeof (Customer), typeof (CustomerDto)); - cfg.CreateMap(typeof (CustomerType), typeof (string)).ConvertUsing(ct => ct.ToString().ToUpper()); - }); - _mapper = config.CreateMapper(); - } - - [Fact] - public void ProjectingEnumToString() +public class NonGenericProjectAndMapEnumTest +{ + private IMapper _mapper; + + public NonGenericProjectAndMapEnumTest() + { + var config = new MapperConfiguration(cfg => { - var customers = new[] { new Customer() { FirstName = "Bill", LastName = "White", CustomerType = CustomerType.Vip } }.AsQueryable(); + cfg.CreateMap(typeof (Customer), typeof (CustomerDto)); + cfg.CreateMap(typeof (CustomerType), typeof (string)).ConvertUsing(ct => ct.ToString().ToUpper()); + }); + _mapper = config.CreateMapper(); + } - var projected = customers.ProjectTo(_mapper.ConfigurationProvider); - projected.ShouldNotBeNull(); - Assert.Equal(customers.Single().CustomerType.ToString(), projected.Single().CustomerType, StringComparer.OrdinalIgnoreCase); - } + [Fact] + public void ProjectingEnumToString() + { + var customers = new[] { new Customer() { FirstName = "Bill", LastName = "White", CustomerType = CustomerType.Vip } }.AsQueryable(); - public class Customer - { - public string FirstName { get; set; } + var projected = customers.ProjectTo(_mapper.ConfigurationProvider); + projected.ShouldNotBeNull(); + Assert.Equal(customers.Single().CustomerType.ToString(), projected.Single().CustomerType, StringComparer.OrdinalIgnoreCase); + } - public string LastName { get; set; } + public class Customer + { + public string FirstName { get; set; } - public CustomerType CustomerType { get; set; } - } + public string LastName { get; set; } - public class CustomerDto - { - public string FirstName { get; set; } + public CustomerType CustomerType { get; set; } + } - public string LastName { get; set; } + public class CustomerDto + { + public string FirstName { get; set; } - public string CustomerType { get; set; } - } + public string LastName { get; set; } - public enum CustomerType - { - Regular, - Vip, - } + public string CustomerType { get; set; } } - public class NonGenericProjectionOverrides : AutoMapperSpecBase + public enum CustomerType { - public class Source - { - - } + Regular, + Vip, + } +} - public class Dest - { - public int Value { get; set; } - } +public class NonGenericProjectionOverrides : AutoMapperSpecBase +{ + public class Source + { + + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(typeof (Source), typeof (Dest)).ConvertUsing(src => new Dest {Value = 10}); - }); - [Fact] - public void Validate() => AssertConfigurationIsValid(); + public class Dest + { + public int Value { get; set; } } + + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(typeof (Source), typeof (Dest)).ConvertUsing(src => new Dest {Value = 10}); + }); + [Fact] + public void Validate() => AssertConfigurationIsValid(); } \ No newline at end of file diff --git a/src/UnitTests/IMappingExpression/NonGenericResolveUsing.cs b/src/UnitTests/IMappingExpression/NonGenericResolveUsing.cs index 8b49808fbe..d9c68b63b1 100644 --- a/src/UnitTests/IMappingExpression/NonGenericResolveUsing.cs +++ b/src/UnitTests/IMappingExpression/NonGenericResolveUsing.cs @@ -2,34 +2,33 @@ using Shouldly; using System.Linq; -namespace AutoMapper.UnitTests +namespace AutoMapper.UnitTests; + +public class When_using_non_generic_ResolveUsing : AutoMapperSpecBase { - public class When_using_non_generic_ResolveUsing : AutoMapperSpecBase - { - private Destination _destination; + private Destination _destination; - public class Source - { - } - public class Destination - { - public int Value { get; set; } - } + public class Source + { + } + public class Destination + { + public int Value { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(typeof(Source), typeof(Destination)).ForMember("Value", o => o.MapFrom((src, dest, member, ctx) => 10)); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(typeof(Source), typeof(Destination)).ForMember("Value", o => o.MapFrom((src, dest, member, ctx) => 10)); + }); - protected override void Because_of() - { - _destination = Mapper.Map(new Source()); - } + protected override void Because_of() + { + _destination = Mapper.Map(new Source()); + } - [Fact] - public void Should_map_ok() - { - _destination.Value.ShouldBe(10); - } + [Fact] + public void Should_map_ok() + { + _destination.Value.ShouldBe(10); } } \ No newline at end of file diff --git a/src/UnitTests/IgnoreAllPropertiesWithAnInaccessibleSetterTests.cs b/src/UnitTests/IgnoreAllPropertiesWithAnInaccessibleSetterTests.cs index 65675178af..b2844cb36c 100644 --- a/src/UnitTests/IgnoreAllPropertiesWithAnInaccessibleSetterTests.cs +++ b/src/UnitTests/IgnoreAllPropertiesWithAnInaccessibleSetterTests.cs @@ -1,43 +1,42 @@ using Xunit; -namespace AutoMapper.UnitTests +namespace AutoMapper.UnitTests; + +public class SomeSource { - public class SomeSource - { - public int IgnoreMe { get; set; } - } + public int IgnoreMe { get; set; } +} - public class Destination : DestinationBase - { - } +public class Destination : DestinationBase +{ +} - public class DestinationBase - { - public int IgnoreMe { get; private set; } - } +public class DestinationBase +{ + public int IgnoreMe { get; private set; } +} - public class IgnoreAllPropertiesWithAnInaccessibleSetterTests +public class IgnoreAllPropertiesWithAnInaccessibleSetterTests +{ + [Fact] + public void AutoMapper_SimpleObject_IgnoresPrivateSettersInBaseClasses() { - [Fact] - public void AutoMapper_SimpleObject_IgnoresPrivateSettersInBaseClasses() + // Arrange + var config = new MapperConfiguration(cfg => { - // Arrange - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap() - .IgnoreAllPropertiesWithAnInaccessibleSetter(); - }); - var mapper = config.CreateMapper(); - - var source = new SomeSource { IgnoreMe = 666 }; - var destination = new Destination(); - - // Act - mapper.Map(source, destination); - - // Assert - config.AssertConfigurationIsValid(); - Assert.Equal(0, destination.IgnoreMe); - } + cfg.CreateMap() + .IgnoreAllPropertiesWithAnInaccessibleSetter(); + }); + var mapper = config.CreateMapper(); + + var source = new SomeSource { IgnoreMe = 666 }; + var destination = new Destination(); + + // Act + mapper.Map(source, destination); + + // Assert + config.AssertConfigurationIsValid(); + Assert.Equal(0, destination.IgnoreMe); } } diff --git a/src/UnitTests/IgnoreAllTests.cs b/src/UnitTests/IgnoreAllTests.cs index 3a621e2a40..e63397020f 100644 --- a/src/UnitTests/IgnoreAllTests.cs +++ b/src/UnitTests/IgnoreAllTests.cs @@ -3,226 +3,225 @@ using Shouldly; using System; -namespace AutoMapper.UnitTests +namespace AutoMapper.UnitTests; + +public class When_overriding_global_ignore : AutoMapperSpecBase { - public class When_overriding_global_ignore : AutoMapperSpecBase + Destination _destination; + + public class Source { - Destination _destination; + public int ShouldBeMapped { get; set; } + } - public class Source - { - public int ShouldBeMapped { get; set; } - } + public class Destination + { + public int ShouldBeMapped { get; set; } + } - public class Destination - { - public int ShouldBeMapped { get; set; } - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.AddGlobalIgnore("ShouldBeMapped"); + cfg.CreateMap().ForMember(d => d.ShouldBeMapped, o => o.MapFrom(src => 12)); + }); - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.AddGlobalIgnore("ShouldBeMapped"); - cfg.CreateMap().ForMember(d => d.ShouldBeMapped, o => o.MapFrom(src => 12)); - }); + protected override void Because_of() + { + _destination = Mapper.Map(new Source()); + } - protected override void Because_of() - { - _destination = Mapper.Map(new Source()); - } + [Fact] + public void Should_not_ignore() + { + _destination.ShouldBeMapped.ShouldBe(12); + } +} - [Fact] - public void Should_not_ignore() - { - _destination.ShouldBeMapped.ShouldBe(12); - } +public class IgnoreAllTests +{ + public class Source + { + public string ShouldBeMapped { get; set; } } - public class IgnoreAllTests + public class Destination { - public class Source - { - public string ShouldBeMapped { get; set; } - } + public string ShouldBeMapped { get; set; } + public string StartingWith_ShouldNotBeMapped { get; set; } + public List StartingWith_ShouldBeNullAfterwards { get; set; } + public string AnotherString_ShouldBeNullAfterwards { get; set; } + } - public class Destination - { - public string ShouldBeMapped { get; set; } - public string StartingWith_ShouldNotBeMapped { get; set; } - public List StartingWith_ShouldBeNullAfterwards { get; set; } - public string AnotherString_ShouldBeNullAfterwards { get; set; } - } + public class DestinationWrongType + { + public Destination ShouldBeMapped { get; set; } + } - public class DestinationWrongType + public class FooProfile : Profile + { + public FooProfile() { - public Destination ShouldBeMapped { get; set; } + CreateMap() + .ForMember(dest => dest.AnotherString_ShouldBeNullAfterwards, opt => opt.Ignore()); } + } - public class FooProfile : Profile + [Fact] + public void GlobalIgnore_ignores_all_properties_beginning_with_string() + { + var config = new MapperConfiguration(cfg => { - public FooProfile() - { - CreateMap() - .ForMember(dest => dest.AnotherString_ShouldBeNullAfterwards, opt => opt.Ignore()); - } - } + cfg.AddGlobalIgnore("StartingWith"); + cfg.CreateMap() + .ForMember(dest => dest.AnotherString_ShouldBeNullAfterwards, opt => opt.Ignore()); + }); + + config.CreateMapper().Map(new Source{ShouldBeMapped = "true"}); + config.AssertConfigurationIsValid(); + } - [Fact] - public void GlobalIgnore_ignores_all_properties_beginning_with_string() + [Fact] + public void GlobalIgnore_ignores_all_properties_beginning_with_string_in_profiles() + { + var config = new MapperConfiguration(cfg => { - var config = new MapperConfiguration(cfg => - { - cfg.AddGlobalIgnore("StartingWith"); - cfg.CreateMap() - .ForMember(dest => dest.AnotherString_ShouldBeNullAfterwards, opt => opt.Ignore()); - }); - - config.CreateMapper().Map(new Source{ShouldBeMapped = "true"}); - config.AssertConfigurationIsValid(); - } + cfg.AddGlobalIgnore("StartingWith"); + cfg.AddProfile(); + }); + + config.CreateMapper().Map(new Source{ShouldBeMapped = "true"}); + config.AssertConfigurationIsValid(); + } - [Fact] - public void GlobalIgnore_ignores_all_properties_beginning_with_string_in_profiles() + [Fact] + public void GlobalIgnore_ignores_properties_with_names_matching_but_different_types() + { + var config = new MapperConfiguration(cfg => { - var config = new MapperConfiguration(cfg => - { - cfg.AddGlobalIgnore("StartingWith"); - cfg.AddProfile(); - }); - - config.CreateMapper().Map(new Source{ShouldBeMapped = "true"}); - config.AssertConfigurationIsValid(); - } + cfg.AddGlobalIgnore("ShouldBeMapped"); + cfg.CreateMap(); + }); - [Fact] - public void GlobalIgnore_ignores_properties_with_names_matching_but_different_types() - { - var config = new MapperConfiguration(cfg => - { - cfg.AddGlobalIgnore("ShouldBeMapped"); - cfg.CreateMap(); - }); - - config.CreateMapper().Map(new Source { ShouldBeMapped = "true" }); - config.AssertConfigurationIsValid(); - } + config.CreateMapper().Map(new Source { ShouldBeMapped = "true" }); + config.AssertConfigurationIsValid(); + } - [Fact] - public void Ignored_properties_should_be_default_value() + [Fact] + public void Ignored_properties_should_be_default_value() + { + var config = new MapperConfiguration(cfg => { - var config = new MapperConfiguration(cfg => - { - cfg.AddGlobalIgnore("StartingWith"); - cfg.CreateMap() - .ForMember(dest => dest.AnotherString_ShouldBeNullAfterwards, opt => opt.Ignore()); - }); - - Destination destination = config.CreateMapper().Map(new Source { ShouldBeMapped = "true" }); - destination.StartingWith_ShouldBeNullAfterwards.ShouldBe(null); - destination.StartingWith_ShouldNotBeMapped.ShouldBe(null); - } + cfg.AddGlobalIgnore("StartingWith"); + cfg.CreateMap() + .ForMember(dest => dest.AnotherString_ShouldBeNullAfterwards, opt => opt.Ignore()); + }); - [Fact] - public void Ignore_supports_two_different_values() - { - var config = new MapperConfiguration(cfg => - { - cfg.AddGlobalIgnore("StartingWith"); - cfg.AddGlobalIgnore("AnotherString"); - cfg.CreateMap(); - }); - - Destination destination = config.CreateMapper().Map(new Source { ShouldBeMapped = "true" }); - destination.AnotherString_ShouldBeNullAfterwards.ShouldBe(null); - destination.StartingWith_ShouldNotBeMapped.ShouldBe(null); - } + Destination destination = config.CreateMapper().Map(new Source { ShouldBeMapped = "true" }); + destination.StartingWith_ShouldBeNullAfterwards.ShouldBe(null); + destination.StartingWith_ShouldNotBeMapped.ShouldBe(null); } - public class IgnoreAttributeTests + + [Fact] + public void Ignore_supports_two_different_values() { - public class Source + var config = new MapperConfiguration(cfg => { - public string ShouldBeMapped { get; set; } - public string ShouldNotBeMapped { get; set; } - } + cfg.AddGlobalIgnore("StartingWith"); + cfg.AddGlobalIgnore("AnotherString"); + cfg.CreateMap(); + }); - public class Destination - { - public string ShouldBeMapped { get; set; } - [IgnoreMap] - public string ShouldNotBeMapped { get; set; } - } + Destination destination = config.CreateMapper().Map(new Source { ShouldBeMapped = "true" }); + destination.AnotherString_ShouldBeNullAfterwards.ShouldBe(null); + destination.StartingWith_ShouldNotBeMapped.ShouldBe(null); + } +} +public class IgnoreAttributeTests +{ + public class Source + { + public string ShouldBeMapped { get; set; } + public string ShouldNotBeMapped { get; set; } + } - [Fact] - public void Ignore_On_Source_Field() - { - var config = new MapperConfiguration(cfg => - { - cfg.AddIgnoreMapAttribute(); - cfg.CreateMap(); - }); - config.AssertConfigurationIsValid(); - - Source source = new Source - { - ShouldBeMapped = "Value1", - ShouldNotBeMapped = "Value2" - }; - - Destination destination = config.CreateMapper().Map(source); - destination.ShouldNotBeMapped.ShouldBe(null); - } + public class Destination + { + public string ShouldBeMapped { get; set; } + [IgnoreMap] + public string ShouldNotBeMapped { get; set; } } - public class ReverseMapIgnoreAttributeTests + [Fact] + public void Ignore_On_Source_Field() { - public class Source + var config = new MapperConfiguration(cfg => { - public string ShouldBeMapped { get; set; } - public string ShouldNotBeMapped { get; set; } - } + cfg.AddIgnoreMapAttribute(); + cfg.CreateMap(); + }); + config.AssertConfigurationIsValid(); - public class Destination + Source source = new Source { - public string ShouldBeMapped { get; set; } - [IgnoreMap] - public string ShouldNotBeMapped { get; set; } - } + ShouldBeMapped = "Value1", + ShouldNotBeMapped = "Value2" + }; - [Fact] - public void Ignore_On_Source_Field() - { - var config = new MapperConfiguration(cfg => - { - cfg.AddIgnoreMapAttribute(); - cfg.CreateMap().ReverseMap(); - }); - config.AssertConfigurationIsValid(); - - Destination source = new Destination - { - ShouldBeMapped = "Value1", - ShouldNotBeMapped = "Value2" - }; - - Source destination = config.CreateMapper().Map(source); - destination.ShouldNotBeMapped.ShouldBe(null); + Destination destination = config.CreateMapper().Map(source); + destination.ShouldNotBeMapped.ShouldBe(null); + } +} - } +public class ReverseMapIgnoreAttributeTests +{ + public class Source + { + public string ShouldBeMapped { get; set; } + public string ShouldNotBeMapped { get; set; } + } - public class Source2 - { - } + public class Destination + { + public string ShouldBeMapped { get; set; } + [IgnoreMap] + public string ShouldNotBeMapped { get; set; } + } - public class Destination2 + [Fact] + public void Ignore_On_Source_Field() + { + var config = new MapperConfiguration(cfg => { - [IgnoreMap] - public string ShouldNotThrowExceptionOnReverseMapping { get; set; } - } + cfg.AddIgnoreMapAttribute(); + cfg.CreateMap().ReverseMap(); + }); + config.AssertConfigurationIsValid(); - [Fact] - public void Sould_not_throw_exception_when_reverse_property_does_not_exist() + Destination source = new Destination { - typeof(ArgumentOutOfRangeException).ShouldNotBeThrownBy(() => new MapperConfiguration(cfg => cfg.CreateMap() - .ReverseMap())); - } + ShouldBeMapped = "Value1", + ShouldNotBeMapped = "Value2" + }; + + Source destination = config.CreateMapper().Map(source); + destination.ShouldNotBeMapped.ShouldBe(null); + + } + + public class Source2 + { + } + + public class Destination2 + { + [IgnoreMap] + public string ShouldNotThrowExceptionOnReverseMapping { get; set; } + } + + [Fact] + public void Sould_not_throw_exception_when_reverse_property_does_not_exist() + { + typeof(ArgumentOutOfRangeException).ShouldNotBeThrownBy(() => new MapperConfiguration(cfg => cfg.CreateMap() + .ReverseMap())); } } \ No newline at end of file diff --git a/src/UnitTests/InterfaceMapping.cs b/src/UnitTests/InterfaceMapping.cs index 25fb94b2f9..a0d7a4725a 100644 --- a/src/UnitTests/InterfaceMapping.cs +++ b/src/UnitTests/InterfaceMapping.cs @@ -4,753 +4,752 @@ using System.Linq; using Shouldly; using Xunit; -namespace AutoMapper.UnitTests.InterfaceMapping +namespace AutoMapper.UnitTests.InterfaceMapping; + +public class InterfaceInheritance : AutoMapperSpecBase { - public class InterfaceInheritance : AutoMapperSpecBase + protected override MapperConfiguration CreateConfiguration() => new(cfg => { - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .IncludeBase() - .IncludeBase(); - cfg.CreateMap(); - cfg.CreateMap(); - }); - [Fact] - public void Should_choose_the_derived_interface() - { - var source = new Source - { - Name = "Name", - PropertyA = "PropertyA", - PropertyB = "PropertyB" - }; - var destination = new Target(); - Mapper.Map(source, destination); - destination.Name.ShouldBe(source.Name); - destination.PropertyA.ShouldBe(source.PropertyA); - destination.PropertyB.ShouldBe(source.PropertyB); - } - public class Source - { - public string PropertyA { get; set; } - public string PropertyB { get; set; } - public string Name { get; set; } - } - public class Target : IProperties - { - public string PropertyA { get; set; } - public string PropertyB { get; set; } - public string Name { get; set; } - } - public interface IProperties : IPropertyA, IPropertyB - { - string Name { get; set; } - } - public interface IPropertyA - { - string PropertyA { get; set; } - } - public interface IPropertyB - { - string PropertyB { get; set; } - } + cfg.CreateMap() + .IncludeBase() + .IncludeBase(); + cfg.CreateMap(); + cfg.CreateMap(); + }); + [Fact] + public void Should_choose_the_derived_interface() + { + var source = new Source + { + Name = "Name", + PropertyA = "PropertyA", + PropertyB = "PropertyB" + }; + var destination = new Target(); + Mapper.Map(source, destination); + destination.Name.ShouldBe(source.Name); + destination.PropertyA.ShouldBe(source.PropertyA); + destination.PropertyB.ShouldBe(source.PropertyB); + } + public class Source + { + public string PropertyA { get; set; } + public string PropertyB { get; set; } + public string Name { get; set; } + } + public class Target : IProperties + { + public string PropertyA { get; set; } + public string PropertyB { get; set; } + public string Name { get; set; } } - public class MapToInterface : NonValidatingSpecBase + public interface IProperties : IPropertyA, IPropertyB { - protected override MapperConfiguration CreateConfiguration() => new(c=>c.CreateMap>()); - [Fact] - public void Should_throw() => new Action(()=>Mapper.Map>(new object())).ShouldThrow().Message.ShouldStartWith( - "Cannot create interface System.Collections.Generic.IEnumerable`1[System.Object]"); + string Name { get; set; } } - public class GenericsAndInterfaces : AutoMapperSpecBase + public interface IPropertyA { - MyClass source = new MyClass { Container = new ContainerClass { MyProperty = 3 } }; + string PropertyA { get; set; } + } + public interface IPropertyB + { + string PropertyB { get; set; } + } +} +public class MapToInterface : NonValidatingSpecBase +{ + protected override MapperConfiguration CreateConfiguration() => new(c=>c.CreateMap>()); + [Fact] + public void Should_throw() => new Action(()=>Mapper.Map>(new object())).ShouldThrow().Message.ShouldStartWith( + "Cannot create interface System.Collections.Generic.IEnumerable`1[System.Object]"); +} +public class GenericsAndInterfaces : AutoMapperSpecBase +{ + MyClass source = new MyClass { Container = new ContainerClass { MyProperty = 3 } }; - public interface IMyInterface - { - T Container { get; set; } - } + public interface IMyInterface + { + T Container { get; set; } + } - public class ContainerClass - { - public int MyProperty { get; set; } - } + public class ContainerClass + { + public int MyProperty { get; set; } + } - public class ImplementedClass : IMyInterface + public class ImplementedClass : IMyInterface + { + public ContainerClass Container { - public ContainerClass Container - { - get; - set; - } + get; + set; } + } - public class MyClass - { - public T Container { get; set; } - } + public class MyClass + { + public T Container { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.CreateMap(typeof(MyClass<>), typeof(IMyInterface<>)).AsProxy()); + protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.CreateMap(typeof(MyClass<>), typeof(IMyInterface<>)).AsProxy()); - [Fact] - public void ShouldMapToExistingObject() - { - var destination = new ImplementedClass(); - Mapper.Map(source, destination, typeof(MyClass), typeof(IMyInterface)); - destination.Container.MyProperty.ShouldBe(3); - } + [Fact] + public void ShouldMapToExistingObject() + { + var destination = new ImplementedClass(); + Mapper.Map(source, destination, typeof(MyClass), typeof(IMyInterface)); + destination.Container.MyProperty.ShouldBe(3); + } - [Fact] - public void ShouldMapToNewObject() - { - var destination = (IMyInterface) Mapper.Map(source, typeof(MyClass), typeof(IMyInterface)); - destination.Container.MyProperty.ShouldBe(3); - } + [Fact] + public void ShouldMapToNewObject() + { + var destination = (IMyInterface) Mapper.Map(source, typeof(MyClass), typeof(IMyInterface)); + destination.Container.MyProperty.ShouldBe(3); } +} - public class When_mapping_generic_interface : AutoMapperSpecBase +public class When_mapping_generic_interface : AutoMapperSpecBase +{ + public class Source : List { - public class Source : List - { - public String PropertyToMap { get; set; } - public String PropertyToIgnore { get; set; } = "I am not ignored"; - } + public String PropertyToMap { get; set; } + public String PropertyToIgnore { get; set; } = "I am not ignored"; + } - public class Destination : DestinationBase - { - } + public class Destination : DestinationBase + { + } - public abstract class DestinationBase : DestinationBaseBase, IDestinationBase - { - private String m_PropertyToIgnore; + public abstract class DestinationBase : DestinationBaseBase, IDestinationBase + { + private String m_PropertyToIgnore; - public virtual String PropertyToMap { get; set; } + public virtual String PropertyToMap { get; set; } - [IgnoreMap] - public override String PropertyToIgnore + [IgnoreMap] + public override String PropertyToIgnore + { + get { - get - { - return m_PropertyToIgnore ?? (m_PropertyToIgnore = "Ignore me"); - } - set - { - m_PropertyToIgnore = value; - } + return m_PropertyToIgnore ?? (m_PropertyToIgnore = "Ignore me"); + } + set + { + m_PropertyToIgnore = value; } - - public virtual List Items { get; set; } } - public abstract class DestinationBaseBase - { - [IgnoreMap] - public virtual String PropertyToIgnore { get; set; } - } + public virtual List Items { get; set; } + } - public interface IDestinationBase - { - String PropertyToMap { get; set; } - List Items { get; set; } - } + public abstract class DestinationBaseBase + { + [IgnoreMap] + public virtual String PropertyToIgnore { get; set; } + } + + public interface IDestinationBase + { + String PropertyToMap { get; set; } + List Items { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg=> - cfg.CreateMap(typeof(IList<>), typeof(IDestinationBase<>)) - .ForMember(nameof(IDestinationBase.Items), p_Expression => p_Expression.MapFrom(p_Source => p_Source)) - .ForMember("PropertyToMap", o=>o.Ignore()) - .AsProxy()); + protected override MapperConfiguration CreateConfiguration() => new(cfg=> + cfg.CreateMap(typeof(IList<>), typeof(IDestinationBase<>)) + .ForMember(nameof(IDestinationBase.Items), p_Expression => p_Expression.MapFrom(p_Source => p_Source)) + .ForMember("PropertyToMap", o=>o.Ignore()) + .AsProxy()); - [Fact] - public void Should_work() - { - var source = new Source{"Cat", "Dog"}; - source.PropertyToMap = "Hello World"; - var destination = Mapper.Map>(source); - destination.PropertyToMap.ShouldBeNull(); - destination.Items.ShouldBe(source); - } + [Fact] + public void Should_work() + { + var source = new Source{"Cat", "Dog"}; + source.PropertyToMap = "Hello World"; + var destination = Mapper.Map>(source); + destination.PropertyToMap.ShouldBeNull(); + destination.Items.ShouldBe(source); } +} - public class When_mapping_an_interface_with_getter_only_member : AutoMapperSpecBase +public class When_mapping_an_interface_with_getter_only_member : AutoMapperSpecBase +{ + interface ISource { - interface ISource - { - int Id { get; set; } - } + int Id { get; set; } + } - public interface IDestination - { - int Id { get; set; } - int ReadOnly { get; } - } + public interface IDestination + { + int Id { get; set; } + int ReadOnly { get; } + } - class Source : ISource - { - public int Id { get; set; } - } + class Source : ISource + { + public int Id { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(c=>c.CreateMap().AsProxy()); + protected override MapperConfiguration CreateConfiguration() => new(c=>c.CreateMap().AsProxy()); - [Fact] - public void ShouldMapOk() - { - Mapper.Map(new Source { Id = 5 }).Id.ShouldBe(5); - } + [Fact] + public void ShouldMapOk() + { + Mapper.Map(new Source { Id = 5 }).Id.ShouldBe(5); } +} - public class When_mapping_base_interface_members +public class When_mapping_base_interface_members +{ + public interface ISource { - public interface ISource - { - int Id { get; set; } - } - - public interface ITarget : ITargetBase - { - int Id { get; set; } - } + int Id { get; set; } + } - public interface ITargetBase - { - int BaseId { get; set; } - } + public interface ITarget : ITargetBase + { + int Id { get; set; } + } - [Fact] - public void Should_find_inherited_members_by_name() - { - new MapperConfiguration(c=>c.CreateMap().ForMember("BaseId", opt => opt.Ignore())); - } + public interface ITargetBase + { + int BaseId { get; set; } } - public class When_mapping_to_existing_object_through_interfaces : AutoMapperSpecBase + [Fact] + public void Should_find_inherited_members_by_name() { - private class2DTO _result; + new MapperConfiguration(c=>c.CreateMap().ForMember("BaseId", opt => opt.Ignore())); + } +} - public class class1 : iclass1 - { - public string prop1 { get; set; } - } +public class When_mapping_to_existing_object_through_interfaces : AutoMapperSpecBase +{ + private class2DTO _result; - public class class2 : class1, iclass2 - { - public string prop2 { get; set; } - } + public class class1 : iclass1 + { + public string prop1 { get; set; } + } - public class class1DTO : iclass1DTO - { - public string prop1 { get; set; } - } + public class class2 : class1, iclass2 + { + public string prop2 { get; set; } + } - public class class2DTO : class1DTO, iclass2DTO - { - public string prop2 { get; set; } - } + public class class1DTO : iclass1DTO + { + public string prop1 { get; set; } + } - public interface iclass1 - { - string prop1 { get; set; } - } + public class class2DTO : class1DTO, iclass2DTO + { + public string prop2 { get; set; } + } - public interface iclass2 - { - string prop2 { get; set; } - } + public interface iclass1 + { + string prop1 { get; set; } + } - public interface iclass1DTO - { - string prop1 { get; set; } - } + public interface iclass2 + { + string prop2 { get; set; } + } - public interface iclass2DTO - { - string prop2 { get; set; } - } + public interface iclass1DTO + { + string prop1 { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - cfg.CreateMap(); - }); + public interface iclass2DTO + { + string prop2 { get; set; } + } - protected override void Because_of() - { - var bo = new class2 { prop1 = "PROP1", prop2 = "PROP2" }; - _result = Mapper.Map(bo, new class2DTO()); - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + cfg.CreateMap(); + }); - [Fact] - public void Should_use_the_most_derived_interface() - { - _result.prop2.ShouldBe("PROP2"); - } + protected override void Because_of() + { + var bo = new class2 { prop1 = "PROP1", prop2 = "PROP2" }; + _result = Mapper.Map(bo, new class2DTO()); } - public class When_mapping_an_interface_to_an_abstract_type : AutoMapperSpecBase + [Fact] + public void Should_use_the_most_derived_interface() { - private DtoObject _result; + _result.prop2.ShouldBe("PROP2"); + } +} - public class ModelObject - { - public IChildModelObject Child { get; set; } - } +public class When_mapping_an_interface_to_an_abstract_type : AutoMapperSpecBase +{ + private DtoObject _result; - public interface IChildModelObject - { - string ChildProperty { get; set; } - } + public class ModelObject + { + public IChildModelObject Child { get; set; } + } - public class SubChildModelObject : IChildModelObject - { - public string ChildProperty { get; set; } - } + public interface IChildModelObject + { + string ChildProperty { get; set; } + } - public class DtoObject - { - public DtoChildObject Child { get; set; } - } + public class SubChildModelObject : IChildModelObject + { + public string ChildProperty { get; set; } + } - public abstract class DtoChildObject - { - public virtual string ChildProperty { get; set; } - } + public class DtoObject + { + public DtoChildObject Child { get; set; } + } - public class SubDtoChildObject : DtoChildObject - { - } + public abstract class DtoChildObject + { + public virtual string ChildProperty { get; set; } + } - protected override void Because_of() - { - var model = new ModelObject - { - Child = new SubChildModelObject {ChildProperty = "child property value"} - }; - _result = Mapper.Map(model); - } + public class SubDtoChildObject : DtoChildObject + { + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => + protected override void Because_of() + { + var model = new ModelObject { + Child = new SubChildModelObject {ChildProperty = "child property value"} + }; + _result = Mapper.Map(model); + } - cfg.CreateMap(); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { - cfg.CreateMap() - .Include(); + cfg.CreateMap(); - cfg.CreateMap(); - }); + cfg.CreateMap() + .Include(); - [Fact] - public void Should_map_Child_to_SubDtoChildObject_type() - { - _result.Child.ShouldBeOfType(typeof (SubDtoChildObject)); - } + cfg.CreateMap(); + }); - [Fact] - public void Should_map_ChildProperty_to_child_property_value() - { - _result.Child.ChildProperty.ShouldBe("child property value"); - } + [Fact] + public void Should_map_Child_to_SubDtoChildObject_type() + { + _result.Child.ShouldBeOfType(typeof (SubDtoChildObject)); } - public class When_mapping_a_concrete_type_to_an_interface_type : AutoMapperSpecBase + [Fact] + public void Should_map_ChildProperty_to_child_property_value() { - private IDestination _result; - - public class Source - { - public int Value { get; set; } - public int Value1 { get; set; } - } - - public interface IDestination - { - int Value { get; set; } - int Value2 { get; set; } - string Value3 { get; set; } - } + _result.Child.ChildProperty.ShouldBe("child property value"); + } +} - protected override MapperConfiguration CreateConfiguration() => new(cfg =>cfg.CreateMap().AsProxy() - .ForMember(x => x.Value2, o => o.MapFrom(x => x.Value1)) - .ForMember(x => x.Value3, o => o.Ignore()) - .AfterMap((_, d) => - { - d.Value3 = "value 3"; - })); +public class When_mapping_a_concrete_type_to_an_interface_type : AutoMapperSpecBase +{ + private IDestination _result; - protected override void Because_of() - { - _result = Mapper.Map(new Source {Value = 5, Value1 = 50}); - } + public class Source + { + public int Value { get; set; } + public int Value1 { get; set; } + } - [Fact] - public void Should_create_an_implementation_of_the_interface() - { - _result.Value.ShouldBe(5); - } + public interface IDestination + { + int Value { get; set; } + int Value2 { get; set; } + string Value3 { get; set; } + } - [Fact] - public void Should_apply_rules_after_proxying() + protected override MapperConfiguration CreateConfiguration() => new(cfg =>cfg.CreateMap().AsProxy() + .ForMember(x => x.Value2, o => o.MapFrom(x => x.Value1)) + .ForMember(x => x.Value3, o => o.Ignore()) + .AfterMap((_, d) => { - _result.Value2.ShouldBe(50); - _result.Value3.ShouldBe("value 3"); - } + d.Value3 = "value 3"; + })); - [Fact] - public void Should_not_derive_from_INotifyPropertyChanged() - { - _result.ShouldNotBeOfType(); - } + protected override void Because_of() + { + _result = Mapper.Map(new Source {Value = 5, Value1 = 50}); } - public class When_mapping_an_interface_type_to_a_concrete_type_and_reverse : AutoMapperSpecBase + [Fact] + public void Should_create_an_implementation_of_the_interface() { - public interface ISource - { - int Value { get; set; } - } + _result.Value.ShouldBe(5); + } - public class Destination - { - public int Value { get; set; } - } + [Fact] + public void Should_apply_rules_after_proxying() + { + _result.Value2.ShouldBe(50); + _result.Value3.ShouldBe("value 3"); + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - cfg.CreateMap().ReverseMap()); + [Fact] + public void Should_not_derive_from_INotifyPropertyChanged() + { + _result.ShouldNotBeOfType(); + } +} - [Fact] - public void Should_not_convert_to_interface() - { - Should.Throw(() => Mapper.Map(new Destination {Value = 5})) - .Message.ShouldStartWith("Cannot create interface " + typeof(ISource).FullName); - } +public class When_mapping_an_interface_type_to_a_concrete_type_and_reverse : AutoMapperSpecBase +{ + public interface ISource + { + int Value { get; set; } } - public class When_mapping_an_interface_type_to_an_interface_type_and_reverse : AutoMapperSpecBase + public class Destination { - public interface ISource - { - int Value { get; set; } - } + public int Value { get; set; } + } - public class Source: ISource - { - public int Value { get; set; } - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + cfg.CreateMap().ReverseMap()); - public interface IDestination - { - int Value { get; set; } - } + [Fact] + public void Should_not_convert_to_interface() + { + Should.Throw(() => Mapper.Map(new Destination {Value = 5})) + .Message.ShouldStartWith("Cannot create interface " + typeof(ISource).FullName); + } +} - protected override MapperConfiguration CreateConfiguration() => new(cfg => - cfg.CreateMap().AsProxy().ReverseMap().AsProxy()); +public class When_mapping_an_interface_type_to_an_interface_type_and_reverse : AutoMapperSpecBase +{ + public interface ISource + { + int Value { get; set; } + } - [Fact] - public void Should_create_an_implementation_of_the_destination_interface() - { - var destination = Mapper.Map(new Source {Value = 5}); - destination.Value.ShouldBe(5); - } + public class Source: ISource + { + public int Value { get; set; } + } - [Fact] - public void Should_map_implementation_of_the_interface_to_the_proxied_implementation() - { - var destination = Mapper.Map(new Source {Value = 5}); - var reversed = Mapper.Map(destination); + public interface IDestination + { + int Value { get; set; } + } - reversed.ShouldNotBeOfType(); - reversed.Value.ShouldBe(5); - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + cfg.CreateMap().AsProxy().ReverseMap().AsProxy()); + + [Fact] + public void Should_create_an_implementation_of_the_destination_interface() + { + var destination = Mapper.Map(new Source {Value = 5}); + destination.Value.ShouldBe(5); } - public class When_mapping_a_concrete_type_to_an_interface_type_and_reverse : AutoMapperSpecBase + [Fact] + public void Should_map_implementation_of_the_interface_to_the_proxied_implementation() { - public class Source - { - public int Value { get; set; } - } + var destination = Mapper.Map(new Source {Value = 5}); + var reversed = Mapper.Map(destination); - public interface IDestination - { - int Value { get; set; } - } + reversed.ShouldNotBeOfType(); + reversed.Value.ShouldBe(5); + } +} - protected override MapperConfiguration CreateConfiguration() => new(cfg => - cfg.CreateMap().AsProxy().ReverseMap()); +public class When_mapping_a_concrete_type_to_an_interface_type_and_reverse : AutoMapperSpecBase +{ + public class Source + { + public int Value { get; set; } + } - [Fact] - public void Should_create_an_implementation_of_the_destination_interface() - { - var destination = Mapper.Map(new Source {Value = 5}); - destination.Value.ShouldBe(5); - } + public interface IDestination + { + int Value { get; set; } + } - [Fact] - public void Should_map_implementation_of_the_interface_to_the_class() - { - var destination = Mapper.Map(new Source {Value = 5}); - var reversed = Mapper.Map(destination); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + cfg.CreateMap().AsProxy().ReverseMap()); - reversed.Value.ShouldBe(5); - } + [Fact] + public void Should_create_an_implementation_of_the_destination_interface() + { + var destination = Mapper.Map(new Source {Value = 5}); + destination.Value.ShouldBe(5); } - public class When_mapping_a_concrete_type_to_an_interface_type_that_derives_from_INotifyPropertyChanged : AutoMapperSpecBase + [Fact] + public void Should_map_implementation_of_the_interface_to_the_class() { - private IDestination _result; + var destination = Mapper.Map(new Source {Value = 5}); + var reversed = Mapper.Map(destination); - private int _count; + reversed.Value.ShouldBe(5); + } +} - public class Source - { - public int Value { get; set; } - } +public class When_mapping_a_concrete_type_to_an_interface_type_that_derives_from_INotifyPropertyChanged : AutoMapperSpecBase +{ + private IDestination _result; - public interface IDestination : INotifyPropertyChanged - { - int Value { get; set; } - } + private int _count; - protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.CreateMap().AsProxy()); + public class Source + { + public int Value { get; set; } + } - protected override void Because_of() - { - _result = Mapper.Map(new Source {Value = 5}); - } + public interface IDestination : INotifyPropertyChanged + { + int Value { get; set; } + } - [Fact] - public void Should_create_an_implementation_of_the_interface() - { - _result.Value.ShouldBe(5); - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.CreateMap().AsProxy()); - [Fact] - public void Should_derive_from_INotifyPropertyChanged() - { - var q = _result as INotifyPropertyChanged; - q.ShouldNotBeNull(); - } + protected override void Because_of() + { + _result = Mapper.Map(new Source {Value = 5}); + } - [Fact] - public void Should_notify_property_changes() - { - var count = 0; - _result.PropertyChanged += (o, e) => { - count++; - o.ShouldBeSameAs(_result); - e.PropertyName.ShouldBe("Value"); - }; - - _result.Value = 42; - count.ShouldBe(1); - _result.Value.ShouldBe(42); - } + [Fact] + public void Should_create_an_implementation_of_the_interface() + { + _result.Value.ShouldBe(5); + } - [Fact] - public void Should_detach_event_handler() - { - _result.PropertyChanged += MyHandler; - _count.ShouldBe(0); + [Fact] + public void Should_derive_from_INotifyPropertyChanged() + { + var q = _result as INotifyPropertyChanged; + q.ShouldNotBeNull(); + } - _result.Value = 56; - _count.ShouldBe(1); + [Fact] + public void Should_notify_property_changes() + { + var count = 0; + _result.PropertyChanged += (o, e) => { + count++; + o.ShouldBeSameAs(_result); + e.PropertyName.ShouldBe("Value"); + }; + + _result.Value = 42; + count.ShouldBe(1); + _result.Value.ShouldBe(42); + } - _result.PropertyChanged -= MyHandler; - _count.ShouldBe(1); + [Fact] + public void Should_detach_event_handler() + { + _result.PropertyChanged += MyHandler; + _count.ShouldBe(0); - _result.Value = 75; - _count.ShouldBe(1); - } + _result.Value = 56; + _count.ShouldBe(1); - private void MyHandler(object sender, PropertyChangedEventArgs e) { - _count++; - } + _result.PropertyChanged -= MyHandler; + _count.ShouldBe(1); + + _result.Value = 75; + _count.ShouldBe(1); } - public class When_mapping_a_derived_interface_to_an_derived_concrete_type : AutoMapperSpecBase - { - private Destination _result = null; + private void MyHandler(object sender, PropertyChangedEventArgs e) { + _count++; + } +} - public interface ISourceBase - { - int Id { get; } - } +public class When_mapping_a_derived_interface_to_an_derived_concrete_type : AutoMapperSpecBase +{ + private Destination _result = null; - public interface ISource : ISourceBase - { - int SecondId { get; } - } + public interface ISourceBase + { + int Id { get; } + } - public class Source : ISource - { - public int Id { get; set; } - public int SecondId { get; set; } - } + public interface ISource : ISourceBase + { + int SecondId { get; } + } - public abstract class DestinationBase - { - public int Id { get; set; } - } + public class Source : ISource + { + public int Id { get; set; } + public int SecondId { get; set; } + } - public class Destination : DestinationBase - { - public int SecondId { get; set; } - } + public abstract class DestinationBase + { + public int Id { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - }); + public class Destination : DestinationBase + { + public int SecondId { get; set; } + } - protected override void Because_of() - { - _result = Mapper.Map(new Source {Id = 7, SecondId = 42}); - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + }); - [Fact] - public void Should_map_base_interface_property() - { - _result.Id.ShouldBe(7); - } + protected override void Because_of() + { + _result = Mapper.Map(new Source {Id = 7, SecondId = 42}); + } - [Fact] - public void Should_map_derived_interface_property() - { - _result.SecondId.ShouldBe(42); - } + [Fact] + public void Should_map_base_interface_property() + { + _result.Id.ShouldBe(7); } - public class When_mapping_a_derived_interface_to_an_derived_concrete_type_with_readonly_interface_members : AutoMapperSpecBase + [Fact] + public void Should_map_derived_interface_property() { - private Destination _result = null; + _result.SecondId.ShouldBe(42); + } +} - public interface ISourceBase - { - int Id { get; } - } +public class When_mapping_a_derived_interface_to_an_derived_concrete_type_with_readonly_interface_members : AutoMapperSpecBase +{ + private Destination _result = null; - public interface ISource : ISourceBase - { - int SecondId { get; } - } + public interface ISourceBase + { + int Id { get; } + } - public class Source : ISource - { - public int Id { get; set; } - public int SecondId { get; set; } - } + public interface ISource : ISourceBase + { + int SecondId { get; } + } - public interface IDestinationBase - { - int Id { get; } - } + public class Source : ISource + { + public int Id { get; set; } + public int SecondId { get; set; } + } - public interface IDestination : IDestinationBase - { - int SecondId { get; } - } + public interface IDestinationBase + { + int Id { get; } + } - public abstract class DestinationBase : IDestinationBase - { - public int Id { get; set; } - } + public interface IDestination : IDestinationBase + { + int SecondId { get; } + } - public class Destination : DestinationBase, IDestination - { - public int SecondId { get; set; } - } + public abstract class DestinationBase : IDestinationBase + { + public int Id { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - }); + public class Destination : DestinationBase, IDestination + { + public int SecondId { get; set; } + } - protected override void Because_of() - { - _result = Mapper.Map(new Source {Id = 7, SecondId = 42}); - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + }); - [Fact] - public void Should_map_base_interface_property() - { - _result.Id.ShouldBe(7); - } + protected override void Because_of() + { + _result = Mapper.Map(new Source {Id = 7, SecondId = 42}); + } - [Fact] - public void Should_map_derived_interface_property() - { - _result.SecondId.ShouldBe(42); - } + [Fact] + public void Should_map_base_interface_property() + { + _result.Id.ShouldBe(7); } - public class When_mapping_to_a_type_with_explicitly_implemented_interface_members : AutoMapperSpecBase + [Fact] + public void Should_map_derived_interface_property() { - private Destination _destination; + _result.SecondId.ShouldBe(42); + } +} - public class Source - { - public int Value { get; set; } - } +public class When_mapping_to_a_type_with_explicitly_implemented_interface_members : AutoMapperSpecBase +{ + private Destination _destination; - public interface IOtherDestination - { - int OtherValue { get; set; } - } + public class Source + { + public int Value { get; set; } + } - public class Destination : IOtherDestination - { - public int Value { get; set; } - int IOtherDestination.OtherValue { get; set; } - } + public interface IOtherDestination + { + int OtherValue { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - }); + public class Destination : IOtherDestination + { + public int Value { get; set; } + int IOtherDestination.OtherValue { get; set; } + } - protected override void Because_of() - { - _destination = Mapper.Map(new Source {Value = 10}); - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + }); - [Fact] - public void Should_ignore_interface_members_for_mapping() - { - _destination.Value.ShouldBe(10); - } + protected override void Because_of() + { + _destination = Mapper.Map(new Source {Value = 10}); } - public class MappingToInterfacesWithPolymorphism : AutoMapperSpecBase + [Fact] + public void Should_ignore_interface_members_for_mapping() { - private BaseDto[] _baseDtos; + _destination.Value.ShouldBe(10); + } +} - public interface IBase { } - public interface IDerived : IBase { } - public class Base : IBase { } - public class Derived : Base, IDerived { } - public class BaseDto { } - public class DerivedDto : BaseDto { } +public class MappingToInterfacesWithPolymorphism : AutoMapperSpecBase +{ + private BaseDto[] _baseDtos; - //and following mappings: - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().Include(); - cfg.CreateMap(); - cfg.CreateMap().Include(); - cfg.CreateMap(); - }); + public interface IBase { } + public interface IDerived : IBase { } + public class Base : IBase { } + public class Derived : Base, IDerived { } + public class BaseDto { } + public class DerivedDto : BaseDto { } - protected override void Because_of() - { - List list = new List() { new Derived() }; - _baseDtos = Mapper.Map, BaseDto[]>(list); - } + //and following mappings: + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().Include(); + cfg.CreateMap(); + cfg.CreateMap().Include(); + cfg.CreateMap(); + }); - [Fact] - public void Should_use_the_derived_type_map() - { - _baseDtos.First().ShouldBeOfType(); - } + protected override void Because_of() + { + List list = new List() { new Derived() }; + _baseDtos = Mapper.Map, BaseDto[]>(list); + } + [Fact] + public void Should_use_the_derived_type_map() + { + _baseDtos.First().ShouldBeOfType(); } + } diff --git a/src/UnitTests/Internal/CreateProxyThreading.cs b/src/UnitTests/Internal/CreateProxyThreading.cs index 38fd534c07..ff51ba162b 100644 --- a/src/UnitTests/Internal/CreateProxyThreading.cs +++ b/src/UnitTests/Internal/CreateProxyThreading.cs @@ -4,34 +4,33 @@ using AutoMapper.Execution; using Xunit; -namespace AutoMapper.UnitTests +namespace AutoMapper.UnitTests; + +public class CreateProxyThreading { - public class CreateProxyThreading + [Fact] + public void Should_create_the_proxy_once() { - [Fact] - public void Should_create_the_proxy_once() - { - var tasks = Enumerable.Range(0, 5).Select(i => Task.Factory.StartNew(() => - { - ProxyGenerator.GetProxyType(typeof(ISomeDto)); - })).ToArray(); - Task.WaitAll(tasks); - } - - public interface ISomeDto + var tasks = Enumerable.Range(0, 5).Select(i => Task.Factory.StartNew(() => { - string Property1 { get; set; } - string Property21 { get; set; } - string Property3 { get; set; } - string Property4 { get; set; } - string Property5 { get; set; } - string Property6 { get; set; } - string Property7 { get; set; } - string Property8 { get; set; } - string Property9 { get; set; } - string Property10 { get; set; } - string Property11 { get; set; } - } + ProxyGenerator.GetProxyType(typeof(ISomeDto)); + })).ToArray(); + Task.WaitAll(tasks); + } + public interface ISomeDto + { + string Property1 { get; set; } + string Property21 { get; set; } + string Property3 { get; set; } + string Property4 { get; set; } + string Property5 { get; set; } + string Property6 { get; set; } + string Property7 { get; set; } + string Property8 { get; set; } + string Property9 { get; set; } + string Property10 { get; set; } + string Property11 { get; set; } } + } diff --git a/src/UnitTests/Internal/GenerateSimilarType.cs b/src/UnitTests/Internal/GenerateSimilarType.cs index 0e3dbcb6d5..fd6dbbe92f 100644 --- a/src/UnitTests/Internal/GenerateSimilarType.cs +++ b/src/UnitTests/Internal/GenerateSimilarType.cs @@ -5,65 +5,64 @@ using Shouldly; using System; -namespace AutoMapper.UnitTests +namespace AutoMapper.UnitTests; + +public class GenerateSimilarType { - public class GenerateSimilarType + public partial class Article { - public partial class Article - { - public int Id { get; set; } - public int ProductId { get; set; } - public bool IsDefault { get; set; } - public short NationId { get; set; } - public virtual Product Product { get; set; } - } - - public partial class Product - { - public int Id { get; set; } - public string Name { get; set; } - public bool ECommercePublished { get; set; } - public virtual ICollection
Articles { get; set; } - } + public int Id { get; set; } + public int ProductId { get; set; } + public bool IsDefault { get; set; } + public short NationId { get; set; } + public virtual Product Product { get; set; } + } - class ExtraProduct : Product - { - public long Long { get; set; } - public short Short { get; set; } - public Article Article { get; set; } - } + public partial class Product + { + public int Id { get; set; } + public string Name { get; set; } + public bool ECommercePublished { get; set; } + public virtual ICollection
Articles { get; set; } + } - [Fact] - public void Should_work() - { - var extraProperties = typeof(ExtraProduct).GetProperties().Except(typeof(Product).GetProperties()).Select(p => new PropertyDescription(p)); - var similarType = ProxyGenerator.GetSimilarType(typeof(Product), extraProperties); + class ExtraProduct : Product + { + public long Long { get; set; } + public short Short { get; set; } + public Article Article { get; set; } + } - similarType.Assembly.IsDynamic.ShouldBeTrue(); - var sourceProperties = GetProperties(typeof(ExtraProduct)); - var similarTypeProperties = GetProperties(similarType); - similarTypeProperties.SequenceEqual(sourceProperties).ShouldBeTrue(); + [Fact] + public void Should_work() + { + var extraProperties = typeof(ExtraProduct).GetProperties().Except(typeof(Product).GetProperties()).Select(p => new PropertyDescription(p)); + var similarType = ProxyGenerator.GetSimilarType(typeof(Product), extraProperties); - dynamic instance = Activator.CreateInstance(similarType); - instance.Id = 12; - instance.Name = "John"; - instance.ECommercePublished = true; - instance.Short = short.MaxValue; - instance.Long = long.MaxValue; - var articles = new Article[] { new Article(), null, null }; - instance.Articles = articles; - instance.Article = articles[0]; + similarType.Assembly.IsDynamic.ShouldBeTrue(); + var sourceProperties = GetProperties(typeof(ExtraProduct)); + var similarTypeProperties = GetProperties(similarType); + similarTypeProperties.SequenceEqual(sourceProperties).ShouldBeTrue(); - Assert.Equal(12, instance.Id); - Assert.Equal("John", instance.Name); - Assert.Equal(true, instance.ECommercePublished); - Assert.Equal(short.MaxValue, instance.Short); - Assert.Equal(long.MaxValue, instance.Long); - Assert.Equal(articles, instance.Articles); - Assert.Equal(articles[0], instance.Article); - } + dynamic instance = Activator.CreateInstance(similarType); + instance.Id = 12; + instance.Name = "John"; + instance.ECommercePublished = true; + instance.Short = short.MaxValue; + instance.Long = long.MaxValue; + var articles = new Article[] { new Article(), null, null }; + instance.Articles = articles; + instance.Article = articles[0]; - public IEnumerable<(string Name, Type PropertyType)> GetProperties(Type type) => - type.GetProperties().OrderBy(p => p.Name).Select(p => (p.Name, p.PropertyType)); + Assert.Equal(12, instance.Id); + Assert.Equal("John", instance.Name); + Assert.Equal(true, instance.ECommercePublished); + Assert.Equal(short.MaxValue, instance.Short); + Assert.Equal(long.MaxValue, instance.Long); + Assert.Equal(articles, instance.Articles); + Assert.Equal(articles[0], instance.Article); } + + public IEnumerable<(string Name, Type PropertyType)> GetProperties(Type type) => + type.GetProperties().OrderBy(p => p.Name).Select(p => (p.Name, p.PropertyType)); } diff --git a/src/UnitTests/Internal/MapperTests.cs b/src/UnitTests/Internal/MapperTests.cs index 24531120f3..67786371c0 100644 --- a/src/UnitTests/Internal/MapperTests.cs +++ b/src/UnitTests/Internal/MapperTests.cs @@ -1,26 +1,25 @@ using Xunit; using Shouldly; -namespace AutoMapper.UnitTests.Tests +namespace AutoMapper.UnitTests.Tests; + +public class MapperTests : NonValidatingSpecBase { - public class MapperTests : NonValidatingSpecBase + public class Source + { + + } + + public class Destination { - public class Source - { - - } - public class Destination - { - - } - - [Fact] - public void Should_find_configured_type_map_when_two_types_are_configured() - { - var config = new MapperConfiguration(cfg => cfg.CreateMap()); + } + + [Fact] + public void Should_find_configured_type_map_when_two_types_are_configured() + { + var config = new MapperConfiguration(cfg => cfg.CreateMap()); - config.FindTypeMapFor().ShouldNotBeNull(); - } + config.FindTypeMapFor().ShouldNotBeNull(); } } \ No newline at end of file diff --git a/src/UnitTests/Internal/ObjectFactoryTests.cs b/src/UnitTests/Internal/ObjectFactoryTests.cs index 5f510f2d3d..d65383c5c9 100644 --- a/src/UnitTests/Internal/ObjectFactoryTests.cs +++ b/src/UnitTests/Internal/ObjectFactoryTests.cs @@ -2,18 +2,17 @@ using Shouldly; using Xunit; -namespace AutoMapper.UnitTests +namespace AutoMapper.UnitTests; + +using Execution; +public class ObjectFactoryTests { - using Execution; - public class ObjectFactoryTests - { - [Fact] - public void Test_with_create_ctor() => ObjectFactory.CreateInstance(typeof(ObjectFactoryTests)).ShouldBeOfType(); - [Fact] - public void Test_with_value_object_create_ctor() => ObjectFactory.CreateInstance(typeof(DateTimeOffset)).ShouldBeOfType(); - [Fact] - public void Create_ctor_should_throw_when_default_constructor_is_missing() => - new Action(() => ObjectFactory.CreateInstance(typeof(AssemblyLoadEventArgs))) - .ShouldThrow().Message.ShouldStartWith(typeof(AssemblyLoadEventArgs).FullName); - } + [Fact] + public void Test_with_create_ctor() => ObjectFactory.CreateInstance(typeof(ObjectFactoryTests)).ShouldBeOfType(); + [Fact] + public void Test_with_value_object_create_ctor() => ObjectFactory.CreateInstance(typeof(DateTimeOffset)).ShouldBeOfType(); + [Fact] + public void Create_ctor_should_throw_when_default_constructor_is_missing() => + new Action(() => ObjectFactory.CreateInstance(typeof(AssemblyLoadEventArgs))) + .ShouldThrow().Message.ShouldStartWith(typeof(AssemblyLoadEventArgs).FullName); } \ No newline at end of file diff --git a/src/UnitTests/Internal/PrimitiveExtensionsTester.cs b/src/UnitTests/Internal/PrimitiveExtensionsTester.cs index 555bbe9481..24f554b239 100644 --- a/src/UnitTests/Internal/PrimitiveExtensionsTester.cs +++ b/src/UnitTests/Internal/PrimitiveExtensionsTester.cs @@ -6,45 +6,44 @@ using System.Linq.Expressions; using AutoMapper.Execution; -namespace AutoMapper.UnitTests +namespace AutoMapper.UnitTests; + +public class PrimitiveExtensionsTester { - public class PrimitiveExtensionsTester + interface Interface { - interface Interface - { - int Value { get; } - } + int Value { get; } + } - class DestinationClass : Interface - { - int Interface.Value { get { return 123; } } + class DestinationClass : Interface + { + int Interface.Value { get { return 123; } } - public int PrivateProperty { get; private set; } + public int PrivateProperty { get; private set; } - public int PublicProperty { get; set; } - } + public int PublicProperty { get; set; } + } - [Fact] - public void Should_find_explicitly_implemented_member() => typeof(DestinationClass).GetFieldOrProperty("Value").ShouldNotBeNull(); + [Fact] + public void Should_find_explicitly_implemented_member() => typeof(DestinationClass).GetFieldOrProperty("Value").ShouldNotBeNull(); - [Fact] - public void GetMembersChain() - { - Expression> e = x => x.Date.AddDays(1).Date.AddHours(2).AddMinutes(2).Date.DayOfWeek; - var chain = e.GetMembersChain().Select(m => m.Name).ToArray(); - chain.ShouldBe(new[] { "Date", "AddDays", "Date", "AddHours", "AddMinutes", "Date", "DayOfWeek" }); - } - [Fact] - public void IsMemberPath() - { - Expression> e = x => x.Date.AddDays(1).Date.AddHours(2).AddMinutes(2).Date.DayOfWeek; - e.IsMemberPath(out _).ShouldBeFalse(); - e = x => x.Date.Date.DayOfWeek; - e.IsMemberPath(out _).ShouldBeTrue(); - e = x => x.DayOfWeek; - e.IsMemberPath(out _).ShouldBeTrue(); - e = x => x.AddDays(1).Date.DayOfWeek; - e.IsMemberPath(out _).ShouldBeFalse(); - } + [Fact] + public void GetMembersChain() + { + Expression> e = x => x.Date.AddDays(1).Date.AddHours(2).AddMinutes(2).Date.DayOfWeek; + var chain = e.GetMembersChain().Select(m => m.Name).ToArray(); + chain.ShouldBe(new[] { "Date", "AddDays", "Date", "AddHours", "AddMinutes", "Date", "DayOfWeek" }); + } + [Fact] + public void IsMemberPath() + { + Expression> e = x => x.Date.AddDays(1).Date.AddHours(2).AddMinutes(2).Date.DayOfWeek; + e.IsMemberPath(out _).ShouldBeFalse(); + e = x => x.Date.Date.DayOfWeek; + e.IsMemberPath(out _).ShouldBeTrue(); + e = x => x.DayOfWeek; + e.IsMemberPath(out _).ShouldBeTrue(); + e = x => x.AddDays(1).Date.DayOfWeek; + e.IsMemberPath(out _).ShouldBeFalse(); } } \ No newline at end of file diff --git a/src/UnitTests/Internal/TypeMapFactorySpecs.cs b/src/UnitTests/Internal/TypeMapFactorySpecs.cs index abd006bc46..7b79b193be 100644 --- a/src/UnitTests/Internal/TypeMapFactorySpecs.cs +++ b/src/UnitTests/Internal/TypeMapFactorySpecs.cs @@ -4,172 +4,171 @@ using Shouldly; using AutoMapper.Configuration.Conventions; -namespace AutoMapper.UnitTests.Tests +namespace AutoMapper.UnitTests.Tests; + +using AutoMapper.Internal; +using System; + +public class StubNamingConvention : INamingConvention { - using AutoMapper.Internal; - using System; + public Regex SplittingExpression { get; set; } + public string SeparatorCharacter { get; set; } + public string[] Split(string input) => SplittingExpression.Matches(input).Select(m=>m.Value).ToArray(); +} - public class StubNamingConvention : INamingConvention +public class When_constructing_type_maps_with_matching_property_names : NonValidatingSpecBase +{ + public class Source { - public Regex SplittingExpression { get; set; } - public string SeparatorCharacter { get; set; } - public string[] Split(string input) => SplittingExpression.Matches(input).Select(m=>m.Value).ToArray(); + public int Value { get; set; } + public int SomeOtherValue { get; set; } } - public class When_constructing_type_maps_with_matching_property_names : NonValidatingSpecBase + public class Destination { - public class Source - { - public int Value { get; set; } - public int SomeOtherValue { get; set; } - } - - public class Destination - { - public int Value { get; set; } - public int SomeOtherValue { get; set; } - } + public int Value { get; set; } + public int SomeOtherValue { get; set; } + } - private class TestProfile : Profile - { - public override string ProfileName => "Test"; - } + private class TestProfile : Profile + { + public override string ProfileName => "Test"; + } - [Fact] - public void Should_map_properties_with_same_name() - { - var mappingOptions = new TestProfile(); - //mappingOptions.SourceMemberNamingConvention = new PascalCaseNamingConvention(); - //mappingOptions.DestinationMemberNamingConvention = new PascalCaseNamingConvention(); - var profile = new ProfileMap(mappingOptions); + [Fact] + public void Should_map_properties_with_same_name() + { + var mappingOptions = new TestProfile(); + //mappingOptions.SourceMemberNamingConvention = new PascalCaseNamingConvention(); + //mappingOptions.DestinationMemberNamingConvention = new PascalCaseNamingConvention(); + var profile = new ProfileMap(mappingOptions); - var typeMap = new TypeMap(typeof(Source), typeof(Destination), profile, null); + var typeMap = new TypeMap(typeof(Source), typeof(Destination), profile, null); - var propertyMaps = typeMap.PropertyMaps; + var propertyMaps = typeMap.PropertyMaps; - propertyMaps.Count().ShouldBe(2); - } + propertyMaps.Count().ShouldBe(2); } - public class When_using_a_custom_source_naming_convention : AutoMapperSpecBase +} +public class When_using_a_custom_source_naming_convention : AutoMapperSpecBase +{ + private class Source { - private class Source - { - public SubSource some__source { get; set; } - } - private class SubSource - { - public int value { get; set; } - } - private class Destination - { - public int SomeSourceValue { get; set; } - } - private class TestProfile : Profile - { - public TestProfile() => SourceMemberNamingConvention = new StubNamingConvention{ SeparatorCharacter = "__", SplittingExpression = new Regex(@"[\p{Ll}\p{Lu}0-9]+(?=__?)") }; - } - protected override MapperConfiguration CreateConfiguration() => new(c => c.AddProfile()); - [Fact] - public void Should_split_using_naming_convention_rules() => AssertConfigurationIsValid(); + public SubSource some__source { get; set; } } - public class When_using_a_custom_destination_naming_convention : AutoMapperSpecBase + private class SubSource { - private class Source - { - public SubSource SomeSource { get; set; } - } - private class SubSource - { - public int Value { get; set; } - } - private class Destination - { - public int some__source__value { get; set; } - } - private class TestProfile : Profile - { - public TestProfile() => DestinationMemberNamingConvention = new StubNamingConvention{ SeparatorCharacter = "__", SplittingExpression = new Regex(@"[\p{Ll}\p{Lu}0-9]+(?=__?)") }; - } - protected override MapperConfiguration CreateConfiguration() => new(c => c.AddProfile()); - [Fact] - public void Should_split_using_naming_convention_rules() => AssertConfigurationIsValid(); + public int value { get; set; } + } + private class Destination + { + public int SomeSourceValue { get; set; } } + private class TestProfile : Profile + { + public TestProfile() => SourceMemberNamingConvention = new StubNamingConvention{ SeparatorCharacter = "__", SplittingExpression = new Regex(@"[\p{Ll}\p{Lu}0-9]+(?=__?)") }; + } + protected override MapperConfiguration CreateConfiguration() => new(c => c.AddProfile()); + [Fact] + public void Should_split_using_naming_convention_rules() => AssertConfigurationIsValid(); +} +public class When_using_a_custom_destination_naming_convention : AutoMapperSpecBase +{ + private class Source + { + public SubSource SomeSource { get; set; } + } + private class SubSource + { + public int Value { get; set; } + } + private class Destination + { + public int some__source__value { get; set; } + } + private class TestProfile : Profile + { + public TestProfile() => DestinationMemberNamingConvention = new StubNamingConvention{ SeparatorCharacter = "__", SplittingExpression = new Regex(@"[\p{Ll}\p{Lu}0-9]+(?=__?)") }; + } + protected override MapperConfiguration CreateConfiguration() => new(c => c.AddProfile()); + [Fact] + public void Should_split_using_naming_convention_rules() => AssertConfigurationIsValid(); +} - public class When_using_a_source_member_name_replacer : NonValidatingSpecBase +public class When_using_a_source_member_name_replacer : NonValidatingSpecBase +{ + public class Source { - public class Source - { - public int Value { get; set; } - public int Ävíator { get; set; } - public int SubAirlinaFlight { get; set; } - } + public int Value { get; set; } + public int Ävíator { get; set; } + public int SubAirlinaFlight { get; set; } + } - public class Destination - { - public int Value { get; set; } - public int Aviator { get; set; } - public int SubAirlineFlight { get; set; } - } + public class Destination + { + public int Value { get; set; } + public int Aviator { get; set; } + public int SubAirlineFlight { get; set; } + } - [Fact] - public void Should_map_properties_with_different_names() - { - var config = new MapperConfiguration(cfg => - { - cfg.ReplaceMemberName("A", "Ä"); - cfg.ReplaceMemberName("i", "í"); - cfg.ReplaceMemberName("Airline", "Airlina"); - cfg.CreateMap(); - }); - - var mapper = config.CreateMapper(); - var dest = mapper.Map(new Source {Ävíator = 3, SubAirlinaFlight = 4, Value = 5}); - dest.Aviator.ShouldBe(3); - dest.SubAirlineFlight.ShouldBe(4); - dest.Value.ShouldBe(5); - } + [Fact] + public void Should_map_properties_with_different_names() + { + var config = new MapperConfiguration(cfg => + { + cfg.ReplaceMemberName("A", "Ä"); + cfg.ReplaceMemberName("i", "í"); + cfg.ReplaceMemberName("Airline", "Airlina"); + cfg.CreateMap(); + }); + + var mapper = config.CreateMapper(); + var dest = mapper.Map(new Source {Ävíator = 3, SubAirlinaFlight = 4, Value = 5}); + dest.Aviator.ShouldBe(3); + dest.SubAirlineFlight.ShouldBe(4); + dest.Value.ShouldBe(5); } +} - public class When_using_a_source_member_name_replacer_with_profile : NonValidatingSpecBase +public class When_using_a_source_member_name_replacer_with_profile : NonValidatingSpecBase +{ + public class Source { - public class Source - { - public int Value { get; set; } - public int Ävíator { get; set; } - public int SubAirlinaFlight { get; set; } - } + public int Value { get; set; } + public int Ävíator { get; set; } + public int SubAirlinaFlight { get; set; } + } - public class Destination - { - public int Value { get; set; } - public int Aviator { get; set; } - public int SubAirlineFlight { get; set; } - } + public class Destination + { + public int Value { get; set; } + public int Aviator { get; set; } + public int SubAirlineFlight { get; set; } + } - public class TestProfile : Profile + public class TestProfile : Profile + { + public TestProfile() { - public TestProfile() - { - CreateMap(); - } + CreateMap(); } + } - [Fact] - public void Should_map_properties_with_different_names() - { - var config = new MapperConfiguration(cfg => - { - cfg.ReplaceMemberName("A", "Ä"); - cfg.ReplaceMemberName("i", "í"); - cfg.ReplaceMemberName("Airline", "Airlina"); - cfg.AddProfile(); - }); - - var mapper = config.CreateMapper(); - var dest = mapper.Map(new Source { Ävíator = 3, SubAirlinaFlight = 4, Value = 5 }); - dest.Aviator.ShouldBe(3); - dest.SubAirlineFlight.ShouldBe(4); - dest.Value.ShouldBe(5); - } + [Fact] + public void Should_map_properties_with_different_names() + { + var config = new MapperConfiguration(cfg => + { + cfg.ReplaceMemberName("A", "Ä"); + cfg.ReplaceMemberName("i", "í"); + cfg.ReplaceMemberName("Airline", "Airlina"); + cfg.AddProfile(); + }); + + var mapper = config.CreateMapper(); + var dest = mapper.Map(new Source { Ävíator = 3, SubAirlinaFlight = 4, Value = 5 }); + dest.Aviator.ShouldBe(3); + dest.SubAirlineFlight.ShouldBe(4); + dest.Value.ShouldBe(5); } } \ No newline at end of file diff --git a/src/UnitTests/MapToAttributeTest.cs b/src/UnitTests/MapToAttributeTest.cs index 6f86fe03d1..46cb564834 100644 --- a/src/UnitTests/MapToAttributeTest.cs +++ b/src/UnitTests/MapToAttributeTest.cs @@ -8,90 +8,89 @@ using System.Linq; using AutoMapper.Internal; -namespace AutoMapper.UnitTests +namespace AutoMapper.UnitTests; + +public abstract class SourceToDestinationMapperAttribute : Attribute { - public abstract class SourceToDestinationMapperAttribute : Attribute - { - public abstract bool IsMatch(TypeDetails typeInfo, MemberInfo memberInfo, Type destType, Type destMemberType, string nameToSearch); - } + public abstract bool IsMatch(TypeDetails typeInfo, MemberInfo memberInfo, Type destType, Type destMemberType, string nameToSearch); +} - [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] - public class MapToAttribute : SourceToDestinationMapperAttribute - { - public string MatchingName { get; } +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] +public class MapToAttribute : SourceToDestinationMapperAttribute +{ + public string MatchingName { get; } - public MapToAttribute(string matchingName) - => MatchingName = matchingName; + public MapToAttribute(string matchingName) + => MatchingName = matchingName; - public override bool IsMatch(TypeDetails typeInfo, MemberInfo memberInfo, Type destType, Type destMemberType, string nameToSearch) - => string.Compare(MatchingName, nameToSearch, StringComparison.OrdinalIgnoreCase) == 0; - } - public class SourceToDestinationNameMapperAttributesMember : ISourceToDestinationNameMapper - { - private static readonly SourceMember[] Empty = new SourceMember[0]; - private readonly Dictionary _allSourceMembers = new Dictionary(); + public override bool IsMatch(TypeDetails typeInfo, MemberInfo memberInfo, Type destType, Type destMemberType, string nameToSearch) + => string.Compare(MatchingName, nameToSearch, StringComparison.OrdinalIgnoreCase) == 0; +} +public class SourceToDestinationNameMapperAttributesMember : ISourceToDestinationNameMapper +{ + private static readonly SourceMember[] Empty = new SourceMember[0]; + private readonly Dictionary _allSourceMembers = new Dictionary(); - public MemberInfo GetSourceMember(TypeDetails sourceTypeDetails, Type destType, Type destMemberType, string nameToSearch) + public MemberInfo GetSourceMember(TypeDetails sourceTypeDetails, Type destType, Type destMemberType, string nameToSearch) + { + if (!_allSourceMembers.TryGetValue(sourceTypeDetails, out SourceMember[] sourceMembers)) { - if (!_allSourceMembers.TryGetValue(sourceTypeDetails, out SourceMember[] sourceMembers)) - { - sourceMembers = sourceTypeDetails.ReadAccessors.Select(sourceMember => new SourceMember(sourceMember)).Where(s => s.Attribute != null).ToArray(); - _allSourceMembers[sourceTypeDetails] = sourceMembers.Length == 0 ? Empty : sourceMembers; - } - return sourceMembers.FirstOrDefault(d => d.Attribute.IsMatch(sourceTypeDetails, d.Member, destType, destMemberType, nameToSearch)).Member; + sourceMembers = sourceTypeDetails.ReadAccessors.Select(sourceMember => new SourceMember(sourceMember)).Where(s => s.Attribute != null).ToArray(); + _allSourceMembers[sourceTypeDetails] = sourceMembers.Length == 0 ? Empty : sourceMembers; } - public void Merge(ISourceToDestinationNameMapper otherNamedMapper) + return sourceMembers.FirstOrDefault(d => d.Attribute.IsMatch(sourceTypeDetails, d.Member, destType, destMemberType, nameToSearch)).Member; + } + public void Merge(ISourceToDestinationNameMapper otherNamedMapper) + { + } + readonly struct SourceMember + { + public SourceMember(MemberInfo sourceMember) { + Member = sourceMember; + Attribute = sourceMember.GetCustomAttribute(inherit: true); } - readonly struct SourceMember - { - public SourceMember(MemberInfo sourceMember) - { - Member = sourceMember; - Attribute = sourceMember.GetCustomAttribute(inherit: true); - } - public MemberInfo Member { get; } - public SourceToDestinationMapperAttribute Attribute { get; } - } + public MemberInfo Member { get; } + public SourceToDestinationMapperAttribute Attribute { get; } } - public class MapToAttributeTest : AutoMapperSpecBase +} +public class MapToAttributeTest : AutoMapperSpecBase +{ + public class CategoryDto { - public class CategoryDto - { - public string Id { get; set; } + public string Id { get; set; } - public string MyValueProperty { get; set; } - } + public string MyValueProperty { get; set; } + } - public class Category - { - public string Id { get; set; } + public class Category + { + public string Id { get; set; } - [MapTo("MyValueProperty")] - public string Key { get; set; } - } + [MapTo("MyValueProperty")] + public string Key { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.Internal().MemberConfiguration.NameToMemberMappers.Add(new SourceToDestinationNameMapperAttributesMember()); + cfg.CreateProfile("New Profile", profile => { - cfg.Internal().MemberConfiguration.NameToMemberMappers.Add(new SourceToDestinationNameMapperAttributesMember()); - cfg.CreateProfile("New Profile", profile => - { - profile.CreateMap(); - }); + profile.CreateMap(); }); + }); - [Fact] - public void Sould_Map_MapToAttribute_To_Property_With_Matching_Name() + [Fact] + public void Sould_Map_MapToAttribute_To_Property_With_Matching_Name() + { + var category = new Category { - var category = new Category - { - Id = "3", - Key = "MyKey" - }; - CategoryDto result = Mapper.Map(category); - result.Id.ShouldBe("3"); - result.MyValueProperty.ShouldBe("MyKey"); - } + Id = "3", + Key = "MyKey" + }; + CategoryDto result = Mapper.Map(category); + result.Id.ShouldBe("3"); + result.MyValueProperty.ShouldBe("MyKey"); } } \ No newline at end of file diff --git a/src/UnitTests/Mappers/ConstructorMapperTests.cs b/src/UnitTests/Mappers/ConstructorMapperTests.cs index 3897cb289f..7df0e3ded4 100644 --- a/src/UnitTests/Mappers/ConstructorMapperTests.cs +++ b/src/UnitTests/Mappers/ConstructorMapperTests.cs @@ -1,19 +1,18 @@ using Shouldly; using Xunit; -namespace AutoMapper.UnitTests.Mappers +namespace AutoMapper.UnitTests.Mappers; + +public class ConstructorMapperTests : AutoMapperSpecBase { - public class ConstructorMapperTests : AutoMapperSpecBase + class Destination { - class Destination + public Destination(string value) { - public Destination(string value) - { - Value = value; - } - public string Value { get; } + Value = value; } - protected override MapperConfiguration CreateConfiguration() => new(_=> { }); - [Fact] - public void Should_use_constructor() => Mapper.Map("value").Value.ShouldBe("value"); + public string Value { get; } } + protected override MapperConfiguration CreateConfiguration() => new(_=> { }); + [Fact] + public void Should_use_constructor() => Mapper.Map("value").Value.ShouldBe("value"); } \ No newline at end of file diff --git a/src/UnitTests/Mappers/ConversionOperators.cs b/src/UnitTests/Mappers/ConversionOperators.cs index d40d1189e2..a543fee618 100644 --- a/src/UnitTests/Mappers/ConversionOperators.cs +++ b/src/UnitTests/Mappers/ConversionOperators.cs @@ -2,190 +2,189 @@ using Shouldly; using System; -namespace AutoMapper.UnitTests +namespace AutoMapper.UnitTests; + +public class Nullable_conversion_operator : NonValidatingSpecBase { - public class Nullable_conversion_operator : NonValidatingSpecBase + public class QueryableValue { - public class QueryableValue - { - public T Value { get; set; } - public static implicit operator QueryableValue(T obj) => new() { Value = obj }; - public static implicit operator T(QueryableValue obj) => obj.Value; - } - class Destination - { - public QueryableValue MyProperty { get; set; } = null!; - } - class Source - { - public int? MyProperty { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(c => c.CreateMap()); - [Fact] - public void Should_work() => Map(new Source { MyProperty = 42 }).MyProperty.Value.ShouldBe(42); + public T Value { get; set; } + public static implicit operator QueryableValue(T obj) => new() { Value = obj }; + public static implicit operator T(QueryableValue obj) => obj.Value; } - public class When_mapping_to_classes_with_implicit_conversion_operators_on_the_destination + class Destination { - private Bar _bar; + public QueryableValue MyProperty { get; set; } = null!; + } + class Source + { + public int? MyProperty { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(c => c.CreateMap()); + [Fact] + public void Should_work() => Map(new Source { MyProperty = 42 }).MyProperty.Value.ShouldBe(42); +} +public class When_mapping_to_classes_with_implicit_conversion_operators_on_the_destination +{ + private Bar _bar; - public class Foo - { - public string Value { get; set; } - } + public class Foo + { + public string Value { get; set; } + } - public class Bar - { - public string OtherValue { get; set; } + public class Bar + { + public string OtherValue { get; set; } - public static implicit operator Bar(Foo other) + public static implicit operator Bar(Foo other) + { + return new Bar { - return new Bar - { - OtherValue = other.Value - }; - } - + OtherValue = other.Value + }; } - [Fact] - public void Should_use_the_implicit_conversion_operator() - { - var source = new Foo { Value = "Hello" }; - var config = new MapperConfiguration(cfg => { }); + } - _bar = config.CreateMapper().Map(source); + [Fact] + public void Should_use_the_implicit_conversion_operator() + { + var source = new Foo { Value = "Hello" }; + var config = new MapperConfiguration(cfg => { }); - _bar.OtherValue.ShouldBe("Hello"); - } + _bar = config.CreateMapper().Map(source); + + _bar.OtherValue.ShouldBe("Hello"); } - - public class When_mapping_to_classes_with_implicit_conversion_operators_on_the_source +} + +public class When_mapping_to_classes_with_implicit_conversion_operators_on_the_source +{ + private Bar _bar; + + public class Foo { - private Bar _bar; + public string Value { get; set; } - public class Foo + public static implicit operator Bar(Foo other) { - public string Value { get; set; } - - public static implicit operator Bar(Foo other) - { - return new Bar - { - OtherValue = other.Value - }; - } - - public static implicit operator string(Foo other) + return new Bar { - return other.Value; - } - + OtherValue = other.Value + }; } - public class InheritedFoo : Foo - { } - - public class Bar + public static implicit operator string(Foo other) { - public string OtherValue { get; set; } + return other.Value; } - [Fact] - public void Should_use_the_implicit_conversion_operator() - { - var source = new Foo { Value = "Hello" }; + } - var config = new MapperConfiguration(cfg => { }); - _bar = config.CreateMapper().Map(source); + public class InheritedFoo : Foo + { } - _bar.OtherValue.ShouldBe("Hello"); - } + public class Bar + { + public string OtherValue { get; set; } + } - [Fact] - public void Should_use_the_inherited_implicit_conversion_operator() - { - var source = new InheritedFoo { Value = "Hello" }; + [Fact] + public void Should_use_the_implicit_conversion_operator() + { + var source = new Foo { Value = "Hello" }; - var config = new MapperConfiguration(cfg => { }); - _bar = config.CreateMapper().Map(source); + var config = new MapperConfiguration(cfg => { }); + _bar = config.CreateMapper().Map(source); - _bar.OtherValue.ShouldBe("Hello"); - } + _bar.OtherValue.ShouldBe("Hello"); } - public class When_mapping_to_classes_with_explicit_conversion_operator_on_the_destination + [Fact] + public void Should_use_the_inherited_implicit_conversion_operator() { - private Bar _bar; + var source = new InheritedFoo { Value = "Hello" }; - public class Foo - { - public string Value { get; set; } - } + var config = new MapperConfiguration(cfg => { }); + _bar = config.CreateMapper().Map(source); - public class Bar - { - public string OtherValue { get; set; } + _bar.OtherValue.ShouldBe("Hello"); + } +} - public static explicit operator Bar(Foo other) - { - return new Bar - { - OtherValue = other.Value - }; - } - } +public class When_mapping_to_classes_with_explicit_conversion_operator_on_the_destination +{ + private Bar _bar; - [Fact] - public void Should_use_the_explicit_conversion_operator() - { - var config = new MapperConfiguration(cfg => { }); - _bar = config.CreateMapper().Map(new Foo { Value = "Hello" }); - _bar.OtherValue.ShouldBe("Hello"); - } + public class Foo + { + public string Value { get; set; } } - public class When_mapping_to_classes_with_explicit_conversion_operator_on_the_source + public class Bar { - private Bar _bar; + public string OtherValue { get; set; } - public class Foo + public static explicit operator Bar(Foo other) { - public string Value { get; set; } - - public static explicit operator Bar(Foo other) + return new Bar { - return new Bar - { - OtherValue = other.Value - }; - } + OtherValue = other.Value + }; } + } - public class InheritedFoo : Foo - { } + [Fact] + public void Should_use_the_explicit_conversion_operator() + { + var config = new MapperConfiguration(cfg => { }); + _bar = config.CreateMapper().Map(new Foo { Value = "Hello" }); + _bar.OtherValue.ShouldBe("Hello"); + } +} - public class Bar - { - public string OtherValue { get; set; } - } +public class When_mapping_to_classes_with_explicit_conversion_operator_on_the_source +{ + private Bar _bar; - [Fact] - public void Should_use_the_explicit_conversion_operator() + public class Foo + { + public string Value { get; set; } + + public static explicit operator Bar(Foo other) { - var config = new MapperConfiguration(cfg => { }); - _bar = config.CreateMapper().Map(new Foo { Value = "Hello" }); - _bar.OtherValue.ShouldBe("Hello"); + return new Bar + { + OtherValue = other.Value + }; } + } - [Fact] - public void Should_use_the_inherited_explicit_conversion_operator() - { - var source = new InheritedFoo { Value = "Hello" }; + public class InheritedFoo : Foo + { } - var config = new MapperConfiguration(cfg => { }); - _bar = config.CreateMapper().Map(source); + public class Bar + { + public string OtherValue { get; set; } + } - _bar.OtherValue.ShouldBe("Hello"); - } + [Fact] + public void Should_use_the_explicit_conversion_operator() + { + var config = new MapperConfiguration(cfg => { }); + _bar = config.CreateMapper().Map(new Foo { Value = "Hello" }); + _bar.OtherValue.ShouldBe("Hello"); + } + + [Fact] + public void Should_use_the_inherited_explicit_conversion_operator() + { + var source = new InheritedFoo { Value = "Hello" }; + + var config = new MapperConfiguration(cfg => { }); + _bar = config.CreateMapper().Map(source); + + _bar.OtherValue.ShouldBe("Hello"); } } diff --git a/src/UnitTests/Mappers/ConvertMapperTests.cs b/src/UnitTests/Mappers/ConvertMapperTests.cs index 72ddddbcc9..f0b8b34a4c 100644 --- a/src/UnitTests/Mappers/ConvertMapperTests.cs +++ b/src/UnitTests/Mappers/ConvertMapperTests.cs @@ -4,72 +4,71 @@ using System; using Xunit; -namespace AutoMapper.UnitTests.Mappers +namespace AutoMapper.UnitTests.Mappers; + +public class ConvertMapperTests : AutoMapperSpecBase { - public class ConvertMapperTests : AutoMapperSpecBase - { - protected override MapperConfiguration CreateConfiguration() => new(c => { }); + protected override MapperConfiguration CreateConfiguration() => new(c => { }); - [Fact] - public void A_few_cases() - { - Mapper.Map(1).ShouldBeTrue(); - Mapper.Map(0).ShouldBeFalse(); - Mapper.Map(1).Value.ShouldBeTrue(); - Mapper.Map(0).Value.ShouldBeFalse(); - Mapper.Map(12).ShouldBe((ulong)12); - Mapper.Map(12).ShouldBe((ulong)12); - Mapper.Map(true).ShouldBe((byte)1); - Mapper.Map(false).ShouldBe((byte)0); - Mapper.Map(true).ShouldBe((byte)1); - Mapper.Map(false).ShouldBe((byte)0); - Mapper.Map(12).ShouldBe(12); - Mapper.Map(12).ShouldBe(12); - Mapper.Map(12).ShouldBe(12); - Mapper.Map(12).ShouldBe(12); - Mapper.Map(12).ShouldBe(12); - Mapper.Map(12).ShouldBe(12); - Mapper.Map(12).ShouldBe(12); - Mapper.Map(12).ShouldBe(12); - Mapper.Map(12).ShouldBe(12); - Mapper.Map(12).ShouldBe(12); - Mapper.Map(12).ShouldBe(12); - Mapper.Map(12).ShouldBe(12); - } + [Fact] + public void A_few_cases() + { + Mapper.Map(1).ShouldBeTrue(); + Mapper.Map(0).ShouldBeFalse(); + Mapper.Map(1).Value.ShouldBeTrue(); + Mapper.Map(0).Value.ShouldBeFalse(); + Mapper.Map(12).ShouldBe((ulong)12); + Mapper.Map(12).ShouldBe((ulong)12); + Mapper.Map(true).ShouldBe((byte)1); + Mapper.Map(false).ShouldBe((byte)0); + Mapper.Map(true).ShouldBe((byte)1); + Mapper.Map(false).ShouldBe((byte)0); + Mapper.Map(12).ShouldBe(12); + Mapper.Map(12).ShouldBe(12); + Mapper.Map(12).ShouldBe(12); + Mapper.Map(12).ShouldBe(12); + Mapper.Map(12).ShouldBe(12); + Mapper.Map(12).ShouldBe(12); + Mapper.Map(12).ShouldBe(12); + Mapper.Map(12).ShouldBe(12); + Mapper.Map(12).ShouldBe(12); + Mapper.Map(12).ShouldBe(12); + Mapper.Map(12).ShouldBe(12); + Mapper.Map(12).ShouldBe(12); + } - [Fact] - public void From_string() - { - Mapper.Map("12").ShouldBe((byte)12); - Mapper.Map("12").ShouldBe((sbyte)12); - Mapper.Map("12").ShouldBe(12); - Mapper.Map("12").ShouldBe(12); - Mapper.Map("12").ShouldBe(12); - Mapper.Map("12").ShouldBe((ushort)12); - Mapper.Map("12").ShouldBe((ulong)12); - Configuration.FindMapper(new TypePair(typeof(string), typeof(DateTime))).ShouldBeOfType(); - var date = DateTime.Now; - Mapper.Map(date.ToString("O")).ShouldBe(date); - } + [Fact] + public void From_string() + { + Mapper.Map("12").ShouldBe((byte)12); + Mapper.Map("12").ShouldBe((sbyte)12); + Mapper.Map("12").ShouldBe(12); + Mapper.Map("12").ShouldBe(12); + Mapper.Map("12").ShouldBe(12); + Mapper.Map("12").ShouldBe((ushort)12); + Mapper.Map("12").ShouldBe((ulong)12); + Configuration.FindMapper(new TypePair(typeof(string), typeof(DateTime))).ShouldBeOfType(); + var date = DateTime.Now; + Mapper.Map(date.ToString("O")).ShouldBe(date); + } - [Fact] - public void From_null_string_to_nullable_int() - { - Mapper.Map(null).ShouldBeNull(); - } + [Fact] + public void From_null_string_to_nullable_int() + { + Mapper.Map(null).ShouldBeNull(); + } - [Fact] - public void ParseMapper() - { - Configuration.FindMapper(new TypePair(typeof(string), typeof(Guid))).ShouldBeOfType(); - var guid = Guid.NewGuid(); - Mapper.Map(guid.ToString()).ShouldBe(guid); - Configuration.FindMapper(new TypePair(typeof(string), typeof(TimeSpan))).ShouldBeOfType(); - var timeSpan = TimeSpan.FromMinutes(1); - Mapper.Map(timeSpan.ToString()).ShouldBe(timeSpan); - Configuration.FindMapper(new TypePair(typeof(string), typeof(DateTimeOffset))).ShouldBeOfType(); - var dateTimeOffset = DateTimeOffset.Now; - Mapper.Map(dateTimeOffset.ToString("O")).ShouldBe(dateTimeOffset); - } + [Fact] + public void ParseMapper() + { + Configuration.FindMapper(new TypePair(typeof(string), typeof(Guid))).ShouldBeOfType(); + var guid = Guid.NewGuid(); + Mapper.Map(guid.ToString()).ShouldBe(guid); + Configuration.FindMapper(new TypePair(typeof(string), typeof(TimeSpan))).ShouldBeOfType(); + var timeSpan = TimeSpan.FromMinutes(1); + Mapper.Map(timeSpan.ToString()).ShouldBe(timeSpan); + Configuration.FindMapper(new TypePair(typeof(string), typeof(DateTimeOffset))).ShouldBeOfType(); + var dateTimeOffset = DateTimeOffset.Now; + Mapper.Map(dateTimeOffset.ToString("O")).ShouldBe(dateTimeOffset); } } \ No newline at end of file diff --git a/src/UnitTests/Mappers/CustomMapperTests.cs b/src/UnitTests/Mappers/CustomMapperTests.cs index b03c5b1a65..d9633f6c49 100644 --- a/src/UnitTests/Mappers/CustomMapperTests.cs +++ b/src/UnitTests/Mappers/CustomMapperTests.cs @@ -6,203 +6,202 @@ using AutoMapper.Internal; using System.ComponentModel; using System.Globalization; -namespace AutoMapper.UnitTests.Mappers +namespace AutoMapper.UnitTests.Mappers; + +using static TypeDescriptor; +public class When_specifying_mapping_with_the_BCL_type_converter_class : NonValidatingSpecBase { - using static TypeDescriptor; - public class When_specifying_mapping_with_the_BCL_type_converter_class : NonValidatingSpecBase + protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.Internal().Mappers.Add(new TypeConverterMapper())); + [TypeConverter(typeof(CustomTypeConverter))] + public class Source { - protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.Internal().Mappers.Add(new TypeConverterMapper())); - [TypeConverter(typeof(CustomTypeConverter))] - public class Source - { - public int Value { get; set; } - } - public class Destination - { - public int OtherValue { get; set; } - } - public class CustomTypeConverter : TypeConverter - { - public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) => destinationType == typeof(Destination); - public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) => - new Destination { OtherValue = ((Source)value).Value + 10 }; - public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) => sourceType == typeof(Destination); - public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) => - new Source { Value = ((Destination)value).OtherValue - 10 }; - } - [Fact] - public void Should_convert_from_type_using_the_custom_type_converter() => Mapper.Map(new Source { Value = 5 }).OtherValue.ShouldBe(15); - [Fact] - public void Should_convert_to_type_using_the_custom_type_converter() => Mapper.Map(new Destination{ OtherValue = 15 }).Value.ShouldBe(5); - public class TypeConverterMapper : ObjectMapper + public int Value { get; set; } + } + public class Destination + { + public int OtherValue { get; set; } + } + public class CustomTypeConverter : TypeConverter + { + public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) => destinationType == typeof(Destination); + public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) => + new Destination { OtherValue = ((Source)value).Value + 10 }; + public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) => sourceType == typeof(Destination); + public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) => + new Source { Value = ((Destination)value).OtherValue - 10 }; + } + [Fact] + public void Should_convert_from_type_using_the_custom_type_converter() => Mapper.Map(new Source { Value = 5 }).OtherValue.ShouldBe(15); + [Fact] + public void Should_convert_to_type_using_the_custom_type_converter() => Mapper.Map(new Destination{ OtherValue = 15 }).Value.ShouldBe(5); + public class TypeConverterMapper : ObjectMapper + { + public override bool IsMatch(TypePair context) => + GetConverter(context.SourceType).CanConvertTo(context.DestinationType) || GetConverter(context.DestinationType).CanConvertFrom(context.SourceType); + public override object Map(object source, object destination, Type sourceType, Type destinationType, ResolutionContext context) { - public override bool IsMatch(TypePair context) => - GetConverter(context.SourceType).CanConvertTo(context.DestinationType) || GetConverter(context.DestinationType).CanConvertFrom(context.SourceType); - public override object Map(object source, object destination, Type sourceType, Type destinationType, ResolutionContext context) - { - var typeConverter = GetConverter(sourceType); - return typeConverter.CanConvertTo(destinationType) ? typeConverter.ConvertTo(source, destinationType) : GetConverter(destinationType).ConvertFrom(source); - } + var typeConverter = GetConverter(sourceType); + return typeConverter.CanConvertTo(destinationType) ? typeConverter.ConvertTo(source, destinationType) : GetConverter(destinationType).ConvertFrom(source); } } - public class When_adding_a_custom_mapper : AutoMapperSpecBase +} +public class When_adding_a_custom_mapper : AutoMapperSpecBase +{ + protected override MapperConfiguration CreateConfiguration() => new(cfg => { - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ForMember(dest => dest.Destination, opt => opt.MapFrom(src => src.Source)); - cfg.Internal().Mappers.Add(new TestObjectMapper()); - }); + cfg.CreateMap() + .ForMember(dest => dest.Destination, opt => opt.MapFrom(src => src.Source)); + cfg.Internal().Mappers.Add(new TestObjectMapper()); + }); - public class TestObjectMapper : IObjectMapper + public class TestObjectMapper : IObjectMapper + { + public object Map(ResolutionContext context) { - public object Map(ResolutionContext context) - { - return new DestinationType(); - } - - public bool IsMatch(TypePair context) - { - return context.SourceType == typeof(SourceType) && context.DestinationType == typeof(DestinationType); - } - - public Expression MapExpression(IGlobalConfiguration configurationProvider, ProfileMap profileMap, - MemberMap memberMap, - Expression sourceExpression, Expression destExpression) - { - Expression> expr = () => new DestinationType(); - - return expr.Body; - } + return new DestinationType(); } - public class ClassA + public bool IsMatch(TypePair context) { - public SourceType Source { get; set; } + return context.SourceType == typeof(SourceType) && context.DestinationType == typeof(DestinationType); } - public class ClassB + public Expression MapExpression(IGlobalConfiguration configurationProvider, ProfileMap profileMap, + MemberMap memberMap, + Expression sourceExpression, Expression destExpression) { - public DestinationType Destination { get; set; } - } + Expression> expr = () => new DestinationType(); - public class SourceType - { - public int Value { get; set; } + return expr.Body; } + } - public class DestinationType - { - public bool Value { get; set; } - } - [Fact] - public void Validate() => AssertConfigurationIsValid(); + public class ClassA + { + public SourceType Source { get; set; } } - public class When_adding_a_simple_custom_mapper : AutoMapperSpecBase + public class ClassB { - ClassB _destination; + public DestinationType Destination { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ForMember(dest => dest.Destination, opt => opt.MapFrom(src => src.Source)); - cfg.Internal().Mappers.Add(new TestObjectMapper()); - }); + public class SourceType + { + public int Value { get; set; } + } - protected override void Because_of() - { - _destination = new ClassB { Destination = new DestinationType() }; - Mapper.Map(new ClassA { Source = new SourceType() }, _destination); - } + public class DestinationType + { + public bool Value { get; set; } + } + [Fact] + public void Validate() => AssertConfigurationIsValid(); +} - [Fact] - public void Should_use_the_object_mapper() - { - _destination.Destination.ShouldBeSameAs(TestObjectMapper.Instance); - } +public class When_adding_a_simple_custom_mapper : AutoMapperSpecBase +{ + ClassB _destination; - public class TestObjectMapper : ObjectMapper - { - public static DestinationType Instance = new DestinationType(); - - public override DestinationType Map(SourceType source, DestinationType destination, Type sourceType, Type destinationType, ResolutionContext context) - { - source.ShouldNotBeNull(); - destination.ShouldNotBeNull(); - context.ShouldNotBeNull(); - sourceType.ShouldBe(typeof(SourceType)); - destinationType.ShouldBe(typeof(DestinationType)); - return Instance; - } - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .ForMember(dest => dest.Destination, opt => opt.MapFrom(src => src.Source)); + cfg.Internal().Mappers.Add(new TestObjectMapper()); + }); - public class ClassA - { - public SourceType Source { get; set; } - } + protected override void Because_of() + { + _destination = new ClassB { Destination = new DestinationType() }; + Mapper.Map(new ClassA { Source = new SourceType() }, _destination); + } - public class ClassB - { - public DestinationType Destination { get; set; } - } + [Fact] + public void Should_use_the_object_mapper() + { + _destination.Destination.ShouldBeSameAs(TestObjectMapper.Instance); + } - public class SourceType - { - public int Value { get; set; } - } + public class TestObjectMapper : ObjectMapper + { + public static DestinationType Instance = new DestinationType(); - public class DestinationType + public override DestinationType Map(SourceType source, DestinationType destination, Type sourceType, Type destinationType, ResolutionContext context) { - public bool Value { get; set; } + source.ShouldNotBeNull(); + destination.ShouldNotBeNull(); + context.ShouldNotBeNull(); + sourceType.ShouldBe(typeof(SourceType)); + destinationType.ShouldBe(typeof(DestinationType)); + return Instance; } } - public class When_adding_an_object_based_custom_mapper : AutoMapperSpecBase + public class ClassA { - Destination _destination; + public SourceType Source { get; set; } + } - class Source - { - public ConsoleColor? Color { get; set; } - } + public class ClassB + { + public DestinationType Destination { get; set; } + } - class Destination - { - public string Color { get; set; } - } + public class SourceType + { + public int Value { get; set; } + } - class EnumMapper : ObjectMapper - { - public override bool IsMatch(TypePair types) - { - var underlyingType = Nullable.GetUnderlyingType(types.SourceType) ?? types.SourceType; - return underlyingType.IsEnum && types.DestinationType == typeof(string); - } - - public override string Map(object source, string destination, Type sourceType, Type destinationType, ResolutionContext context) - { - sourceType.ShouldBe(typeof(ConsoleColor?)); - destinationType.ShouldBe(typeof(string)); - return "Test"; - } - } + public class DestinationType + { + public bool Value { get; set; } + } +} - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - cfg.Internal().Mappers.Insert(0, new EnumMapper()); - }); +public class When_adding_an_object_based_custom_mapper : AutoMapperSpecBase +{ + Destination _destination; + + class Source + { + public ConsoleColor? Color { get; set; } + } + + class Destination + { + public string Color { get; set; } + } - protected override void Because_of() + class EnumMapper : ObjectMapper + { + public override bool IsMatch(TypePair types) { - _destination = Mapper.Map(new Source { Color = ConsoleColor.Black }); + var underlyingType = Nullable.GetUnderlyingType(types.SourceType) ?? types.SourceType; + return underlyingType.IsEnum && types.DestinationType == typeof(string); } - [Fact] - public void Should_map_with_underlying_type() + public override string Map(object source, string destination, Type sourceType, Type destinationType, ResolutionContext context) { - _destination.Color.ShouldBe("Test"); + sourceType.ShouldBe(typeof(ConsoleColor?)); + destinationType.ShouldBe(typeof(string)); + return "Test"; } } + + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + cfg.Internal().Mappers.Insert(0, new EnumMapper()); + }); + + protected override void Because_of() + { + _destination = Mapper.Map(new Source { Color = ConsoleColor.Black }); + } + + [Fact] + public void Should_map_with_underlying_type() + { + _destination.Color.ShouldBe("Test"); + } } \ No newline at end of file diff --git a/src/UnitTests/Mappers/DynamicMapperTests.cs b/src/UnitTests/Mappers/DynamicMapperTests.cs index e60182ad90..58166df21d 100644 --- a/src/UnitTests/Mappers/DynamicMapperTests.cs +++ b/src/UnitTests/Mappers/DynamicMapperTests.cs @@ -4,221 +4,220 @@ using Shouldly; using Xunit; -namespace AutoMapper.UnitTests.Mappers.Dynamic +namespace AutoMapper.UnitTests.Mappers.Dynamic; + +class Destination +{ + public string Foo { get; set; } + public string Bar { get; set; } + internal string Jack { get; set; } + public int[] Data { get; set; } + public int Baz { get; set; } +} + +public class DynamicDictionary : DynamicObject { - class Destination + private readonly Dictionary dictionary = new Dictionary(); + + public override bool TryGetMember(GetMemberBinder binder, out object result) { - public string Foo { get; set; } - public string Bar { get; set; } - internal string Jack { get; set; } - public int[] Data { get; set; } - public int Baz { get; set; } + return dictionary.TryGetValue(binder.Name, out result); } - public class DynamicDictionary : DynamicObject + public override bool TrySetMember(SetMemberBinder binder, object value) { - private readonly Dictionary dictionary = new Dictionary(); + dictionary[binder.Name] = value; + return true; + } - public override bool TryGetMember(GetMemberBinder binder, out object result) - { - return dictionary.TryGetValue(binder.Name, out result); - } + public int Count => dictionary.Count; +} - public override bool TrySetMember(SetMemberBinder binder, object value) +public class When_mapping_to_dynamic_from_getter_only_property +{ + class Source + { + public Source() { - dictionary[binder.Name] = value; - return true; + Value = 24; } - public int Count => dictionary.Count; + public int Value { get; } } - public class When_mapping_to_dynamic_from_getter_only_property + [Fact] + public void Should_map_source_properties() { - class Source - { - public Source() - { - Value = 24; - } + var config = new MapperConfiguration(cfg => { }); + dynamic destination = config.CreateMapper().Map(new Source()); + ((int)destination.Count).ShouldBe(1); + Assert.Equal(24, destination.Value); + } +} - public int Value { get; } - } +public class When_mapping_to_dynamic +{ + dynamic _destination; - [Fact] - public void Should_map_source_properties() - { - var config = new MapperConfiguration(cfg => { }); - dynamic destination = config.CreateMapper().Map(new Source()); - ((int)destination.Count).ShouldBe(1); - Assert.Equal(24, destination.Value); - } + [Fact] + public void Should_map_source_properties() + { + var config = new MapperConfiguration(cfg => { }); + var data = new[] { 1, 2, 3 }; + _destination = config.CreateMapper().Map(new Destination { Foo = "Foo", Bar = "Bar", Data = data, Baz = 12 }); + ((int)_destination.Count).ShouldBe(4); + Assert.Equal("Foo", _destination.Foo); + Assert.Equal("Bar", _destination.Bar); + Assert.Equal(12, _destination.Baz); + ((int[])_destination.Data).SequenceEqual(data).ShouldBeTrue(); } +} - public class When_mapping_to_dynamic - { - dynamic _destination; +public class When_mapping_from_dynamic +{ + Destination _destination; - [Fact] - public void Should_map_source_properties() - { - var config = new MapperConfiguration(cfg => { }); - var data = new[] { 1, 2, 3 }; - _destination = config.CreateMapper().Map(new Destination { Foo = "Foo", Bar = "Bar", Data = data, Baz = 12 }); - ((int)_destination.Count).ShouldBe(4); - Assert.Equal("Foo", _destination.Foo); - Assert.Equal("Bar", _destination.Bar); - Assert.Equal(12, _destination.Baz); - ((int[])_destination.Data).SequenceEqual(data).ShouldBeTrue(); - } + [Fact] + public void Should_map_destination_properties() + { + dynamic source = new DynamicDictionary(); + source.Foo = "Foo"; + source.Bar = "Bar"; + source.Jack = "Jack"; + var config = new MapperConfiguration(cfg => { }); + _destination = config.CreateMapper().Map((object)source); + _destination.Foo.ShouldBe("Foo"); + _destination.Bar.ShouldBe("Bar"); + _destination.Jack.ShouldBeNull(); } +} + +public class When_mapping_struct_from_dynamic +{ + Destination _destination; - public class When_mapping_from_dynamic + struct Destination { - Destination _destination; + public string Foo { get; set; } + public string Bar { get; set; } + internal string Jack { get; set; } + } - [Fact] - public void Should_map_destination_properties() - { - dynamic source = new DynamicDictionary(); - source.Foo = "Foo"; - source.Bar = "Bar"; - source.Jack = "Jack"; - var config = new MapperConfiguration(cfg => { }); - _destination = config.CreateMapper().Map((object)source); - _destination.Foo.ShouldBe("Foo"); - _destination.Bar.ShouldBe("Bar"); - _destination.Jack.ShouldBeNull(); - } + [Fact] + public void Should_map_destination_properties() + { + dynamic source = new DynamicDictionary(); + source.Foo = "Foo"; + source.Bar = "Bar"; + source.Jack = "Jack"; + var config = new MapperConfiguration(cfg => { }); + _destination = config.CreateMapper().Map((object)source); + _destination.Foo.ShouldBe("Foo"); + _destination.Bar.ShouldBe("Bar"); + _destination.Jack.ShouldBeNull(); } +} - public class When_mapping_struct_from_dynamic +public class When_mapping_from_dynamic_with_missing_property +{ + [Fact] + public void Should_map_existing_properties() { - Destination _destination; + dynamic source = new DynamicDictionary(); + source.Foo = "Foo"; + var config = new MapperConfiguration(cfg => { }); + var destination = config.CreateMapper().Map((object)source); + destination.Foo.ShouldBe("Foo"); + destination.Bar.ShouldBeNull(); + } + [Fact] + public void Should_keep_existing_value() + { + dynamic source = new DynamicDictionary(); + source.Foo = "Foo"; + var config = new MapperConfiguration(cfg => { }); + var destination = new Destination { Baz = 42 }; + config.CreateMapper().Map((object)source, destination); + destination.Foo.ShouldBe("Foo"); + destination.Baz.ShouldBe(42); + } +} - struct Destination - { - public string Foo { get; set; } - public string Bar { get; set; } - internal string Jack { get; set; } - } +public class When_mapping_from_dynamic_null_to_int +{ + Destination _destination; - [Fact] - public void Should_map_destination_properties() - { - dynamic source = new DynamicDictionary(); - source.Foo = "Foo"; - source.Bar = "Bar"; - source.Jack = "Jack"; - var config = new MapperConfiguration(cfg => { }); - _destination = config.CreateMapper().Map((object)source); - _destination.Foo.ShouldBe("Foo"); - _destination.Bar.ShouldBe("Bar"); - _destination.Jack.ShouldBeNull(); - } + [Fact] + public void Should_map_to_zero() + { + dynamic source = new DynamicDictionary(); + source.Foo = "Foo"; + source.Baz = null; + var config = new MapperConfiguration(cfg => { }); + _destination = config.CreateMapper().Map((object)source); + _destination.Foo.ShouldBe("Foo"); + _destination.Bar.ShouldBeNull(); + _destination.Baz.ShouldBe(0); } +} - public class When_mapping_from_dynamic_with_missing_property +public class When_mapping_from_dynamic_to_dynamic +{ + dynamic _destination; + + [Fact] + public void Should_map() { - [Fact] - public void Should_map_existing_properties() - { - dynamic source = new DynamicDictionary(); - source.Foo = "Foo"; - var config = new MapperConfiguration(cfg => { }); - var destination = config.CreateMapper().Map((object)source); - destination.Foo.ShouldBe("Foo"); - destination.Bar.ShouldBeNull(); - } - [Fact] - public void Should_keep_existing_value() - { - dynamic source = new DynamicDictionary(); - source.Foo = "Foo"; - var config = new MapperConfiguration(cfg => { }); - var destination = new Destination { Baz = 42 }; - config.CreateMapper().Map((object)source, destination); - destination.Foo.ShouldBe("Foo"); - destination.Baz.ShouldBe(42); - } + dynamic source = new DynamicDictionary(); + source.Foo = "Foo"; + source.Bar = "Bar"; + var config = new MapperConfiguration(cfg => { }); + _destination = config.CreateMapper().Map((object)source); + Assert.Equal("Foo", _destination.Foo); + Assert.Equal("Bar", _destination.Bar); } +} - public class When_mapping_from_dynamic_null_to_int +public class When_mapping_from_dynamic_to_nullable +{ + class DestinationWithNullable { - Destination _destination; - - [Fact] - public void Should_map_to_zero() - { - dynamic source = new DynamicDictionary(); - source.Foo = "Foo"; - source.Baz = null; - var config = new MapperConfiguration(cfg => { }); - _destination = config.CreateMapper().Map((object)source); - _destination.Foo.ShouldBe("Foo"); - _destination.Bar.ShouldBeNull(); - _destination.Baz.ShouldBe(0); - } + public string StringValue { get; set; } + public int? NullIntValue { get; set; } } - public class When_mapping_from_dynamic_to_dynamic + [Fact] + public void Should_map_with_non_null_source() { - dynamic _destination; - - [Fact] - public void Should_map() - { - dynamic source = new DynamicDictionary(); - source.Foo = "Foo"; - source.Bar = "Bar"; - var config = new MapperConfiguration(cfg => { }); - _destination = config.CreateMapper().Map((object)source); - Assert.Equal("Foo", _destination.Foo); - Assert.Equal("Bar", _destination.Bar); - } + dynamic source = new DynamicDictionary(); + source.StringValue = "Test"; + source.NullIntValue = 5; + var config = new MapperConfiguration(cfg => { }); + var destination = config.CreateMapper().Map((object)source); + Assert.Equal("Test", destination.StringValue); + Assert.Equal(5, destination.NullIntValue); } - public class When_mapping_from_dynamic_to_nullable + [Fact] + public void Should_map_with_source_missing() { - class DestinationWithNullable - { - public string StringValue { get; set; } - public int? NullIntValue { get; set; } - } - - [Fact] - public void Should_map_with_non_null_source() - { - dynamic source = new DynamicDictionary(); - source.StringValue = "Test"; - source.NullIntValue = 5; - var config = new MapperConfiguration(cfg => { }); - var destination = config.CreateMapper().Map((object)source); - Assert.Equal("Test", destination.StringValue); - Assert.Equal(5, destination.NullIntValue); - } - - [Fact] - public void Should_map_with_source_missing() - { - dynamic source = new DynamicDictionary(); - source.StringValue = "Test"; - var config = new MapperConfiguration(cfg => { }); - var destination = config.CreateMapper().Map((object)source); - Assert.Equal("Test", destination.StringValue); - Assert.Equal((int?)null, destination.NullIntValue); - } + dynamic source = new DynamicDictionary(); + source.StringValue = "Test"; + var config = new MapperConfiguration(cfg => { }); + var destination = config.CreateMapper().Map((object)source); + Assert.Equal("Test", destination.StringValue); + Assert.Equal((int?)null, destination.NullIntValue); + } - [Fact] - public void Should_map_with_null_source() - { - dynamic source = new DynamicDictionary(); - source.StringValue = "Test"; - source.NullIntValue = null; - var config = new MapperConfiguration(cfg => { }); - var destination = config.CreateMapper().Map((object)source); - Assert.Equal("Test", destination.StringValue); - Assert.Equal((int?)null, destination.NullIntValue); - } + [Fact] + public void Should_map_with_null_source() + { + dynamic source = new DynamicDictionary(); + source.StringValue = "Test"; + source.NullIntValue = null; + var config = new MapperConfiguration(cfg => { }); + var destination = config.CreateMapper().Map((object)source); + Assert.Equal("Test", destination.StringValue); + Assert.Equal((int?)null, destination.NullIntValue); } } \ No newline at end of file diff --git a/src/UnitTests/Mappers/NameValueCollectionMapperTests.cs b/src/UnitTests/Mappers/NameValueCollectionMapperTests.cs index 058a62aff1..7a973ef6e4 100644 --- a/src/UnitTests/Mappers/NameValueCollectionMapperTests.cs +++ b/src/UnitTests/Mappers/NameValueCollectionMapperTests.cs @@ -4,50 +4,49 @@ using Shouldly; using Xunit; -namespace AutoMapper.UnitTests.Mappers +namespace AutoMapper.UnitTests.Mappers; + +public class NameValueCollectionMapperTests { - public class NameValueCollectionMapperTests + public class Map { - public class Map + [Fact] + public void ReturnsTheDestinationWhenPassedOne() { - [Fact] - public void ReturnsTheDestinationWhenPassedOne() - { - var config = new MapperConfiguration(cfg => { }); - IMapper mapper = new Mapper(config); + var config = new MapperConfiguration(cfg => { }); + IMapper mapper = new Mapper(config); - var destination = new NameValueCollection(); + var destination = new NameValueCollection(); - var result = mapper.Map((NameValueCollection)null, destination); + var result = mapper.Map((NameValueCollection)null, destination); - result.ShouldBeSameAs(destination); - } + result.ShouldBeSameAs(destination); + } - [Fact] - public void ReturnsEmptyCollectionWhenSourceCollectionIsEmpty() - { - var config = new MapperConfiguration(cfg => { }); - IMapper mapper = new Mapper(config); + [Fact] + public void ReturnsEmptyCollectionWhenSourceCollectionIsEmpty() + { + var config = new MapperConfiguration(cfg => { }); + IMapper mapper = new Mapper(config); - var result = mapper.Map(new NameValueCollection(), (NameValueCollection)null); + var result = mapper.Map(new NameValueCollection(), (NameValueCollection)null); - result.ShouldBeEmpty(); - } + result.ShouldBeEmpty(); + } - [Fact] - public void ReturnsMappedObjectWithExpectedValuesWhenSourceCollectionHasOneItem() - { - var config = new MapperConfiguration(cfg => { }); - IMapper mapper = new Mapper(config); - var sourceValue = new NameValueCollection() { { "foo", "bar" } }; + [Fact] + public void ReturnsMappedObjectWithExpectedValuesWhenSourceCollectionHasOneItem() + { + var config = new MapperConfiguration(cfg => { }); + IMapper mapper = new Mapper(config); + var sourceValue = new NameValueCollection() { { "foo", "bar" } }; - var result = mapper.Map(sourceValue, new NameValueCollection()); + var result = mapper.Map(sourceValue, new NameValueCollection()); - 1.ShouldBe(result.Count); - "foo".ShouldBe(result.AllKeys[0]); - "bar".ShouldBe(result["foo"]); - } + 1.ShouldBe(result.Count); + "foo".ShouldBe(result.AllKeys[0]); + "bar".ShouldBe(result["foo"]); } - } + } diff --git a/src/UnitTests/Mappers/ReadOnlyDictionaryMapperTests.cs b/src/UnitTests/Mappers/ReadOnlyDictionaryMapperTests.cs index bcc151b905..163089f4f6 100644 --- a/src/UnitTests/Mappers/ReadOnlyDictionaryMapperTests.cs +++ b/src/UnitTests/Mappers/ReadOnlyDictionaryMapperTests.cs @@ -3,80 +3,79 @@ using Shouldly; using Xunit; -namespace AutoMapper.UnitTests.Mappers.ReadOnlyDictionaryMapper +namespace AutoMapper.UnitTests.Mappers.ReadOnlyDictionaryMapper; + +public class When_mapping_to_interface_readonly_dictionary : AutoMapperSpecBase { - public class When_mapping_to_interface_readonly_dictionary : AutoMapperSpecBase + public class Source { - public class Source - { - public IReadOnlyDictionary Values { get; set; } - } + public IReadOnlyDictionary Values { get; set; } + } - public class Destination - { - public IReadOnlyDictionary Values { get; set; } - } + public class Destination + { + public IReadOnlyDictionary Values { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(config => - { - config.CreateMap(); - }); + protected override MapperConfiguration CreateConfiguration() => new(config => + { + config.CreateMap(); + }); - [Fact] - public void Should_map_readonly_values() + [Fact] + public void Should_map_readonly_values() + { + var values = new Dictionary + { + {1, 1}, + {2, 2}, + {3, 3}, + {4, 4}, + }; + var source = new Source { - var values = new Dictionary - { - {1, 1}, - {2, 2}, - {3, 3}, - {4, 4}, - }; - var source = new Source - { - Values = values - }; + Values = values + }; - var dest = Mapper.Map(source); + var dest = Mapper.Map(source); - dest.Values.ShouldBe(values); - } + dest.Values.ShouldBe(values); } - public class When_mapping_to_concrete_readonly_dictionary : AutoMapperSpecBase +} +public class When_mapping_to_concrete_readonly_dictionary : AutoMapperSpecBase +{ + public class Source { - public class Source - { - public ReadOnlyDictionary Values { get; set; } - } + public ReadOnlyDictionary Values { get; set; } + } - public class Destination - { - public ReadOnlyDictionary Values { get; set; } - } + public class Destination + { + public ReadOnlyDictionary Values { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(config => - { - config.CreateMap(); - }); + protected override MapperConfiguration CreateConfiguration() => new(config => + { + config.CreateMap(); + }); - [Fact] - public void Should_map_readonly_values() + [Fact] + public void Should_map_readonly_values() + { + var values = new Dictionary + { + {1, 1}, + {2, 2}, + {3, 3}, + {4, 4}, + }; + var source = new Source { - var values = new Dictionary - { - {1, 1}, - {2, 2}, - {3, 3}, - {4, 4}, - }; - var source = new Source - { - Values = new ReadOnlyDictionary(values) - }; + Values = new ReadOnlyDictionary(values) + }; - var dest = Mapper.Map(source); + var dest = Mapper.Map(source); - dest.Values.ShouldBe(values); - } + dest.Values.ShouldBe(values); } } \ No newline at end of file diff --git a/src/UnitTests/Mappers/StringDictionaryMapperTests.cs b/src/UnitTests/Mappers/StringDictionaryMapperTests.cs index e3b3f1bac2..dca397a9b7 100644 --- a/src/UnitTests/Mappers/StringDictionaryMapperTests.cs +++ b/src/UnitTests/Mappers/StringDictionaryMapperTests.cs @@ -7,328 +7,327 @@ using Xunit; using StringDictionary = System.Collections.Generic.Dictionary; -namespace AutoMapper.UnitTests.Mappers +namespace AutoMapper.UnitTests.Mappers; + +class Destination +{ + public string Foo { get; set; } + public string Bar { get; set; } + public int Baz { get; set; } + public InnerDestination Inner { get; } = new InnerDestination(); + public InnerDestination NullInner { get; } + public InnerDestination SettableInner { get; set; } +} +class InnerDestination +{ + public int Value { get; set; } + public InnerDestination Child { get; set; } +} +public class When_mapping_to_StringDictionary : NonValidatingSpecBase { - class Destination + StringDictionary _destination; + + protected override MapperConfiguration CreateConfiguration() => new(cfg => { }); + + protected override void Because_of() { - public string Foo { get; set; } - public string Bar { get; set; } - public int Baz { get; set; } - public InnerDestination Inner { get; } = new InnerDestination(); - public InnerDestination NullInner { get; } - public InnerDestination SettableInner { get; set; } + _destination = Mapper.Map(new Destination { Foo = "Foo", Bar = "Bar" }); } - class InnerDestination + + [Fact] + public void Should_map_source_properties() { - public int Value { get; set; } - public InnerDestination Child { get; set; } + _destination["Foo"].ShouldBe("Foo"); + _destination["Bar"].ShouldBe("Bar"); } - public class When_mapping_to_StringDictionary : NonValidatingSpecBase - { - StringDictionary _destination; + [Fact] + public void Should_map_struct() => Map(new KeyValuePair(1, "one")).ShouldBe(new StringDictionary { { "Key", 1 }, {"Value", "one"} }); +} +public class When_mapping_from_StringDictionary : NonValidatingSpecBase +{ + Destination _destination; - protected override MapperConfiguration CreateConfiguration() => new(cfg => { }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => { }); - protected override void Because_of() - { - _destination = Mapper.Map(new Destination { Foo = "Foo", Bar = "Bar" }); - } + protected override void Because_of() + { + var source = new StringDictionary() { { "Foo", "Foo" }, { "Bar", "Bar" } }; + _destination = Mapper.Map(source); + } - [Fact] - public void Should_map_source_properties() - { - _destination["Foo"].ShouldBe("Foo"); - _destination["Bar"].ShouldBe("Bar"); - } - [Fact] - public void Should_map_struct() => Map(new KeyValuePair(1, "one")).ShouldBe(new StringDictionary { { "Key", 1 }, {"Value", "one"} }); + [Fact] + public void Should_map_destination_properties() + { + _destination.Foo.ShouldBe("Foo"); + _destination.Bar.ShouldBe("Bar"); + _destination.Baz.ShouldBe(0); } - public class When_mapping_from_StringDictionary : NonValidatingSpecBase + [Fact] + public void When_mapping_inner_properties() { - Destination _destination; - - protected override MapperConfiguration CreateConfiguration() => new(cfg => { }); + var source = new StringDictionary() { { "Inner.Value", "5" }, { "NullInner.Value", "5" }, { "SettableInner.Value", "6" }, { "SettableInner.Child.Value", "7" }, + { "Inner.Child.Value", "8" }}; + var destination = Mapper.Map(source); + destination.Inner.Value.ShouldBe(5); + destination.NullInner.ShouldBeNull(); + destination.SettableInner.Value.ShouldBe(6); + destination.SettableInner.Child.Value.ShouldBe(7); + destination.Inner.Child.Value.ShouldBe(8); + } +} - protected override void Because_of() - { - var source = new StringDictionary() { { "Foo", "Foo" }, { "Bar", "Bar" } }; - _destination = Mapper.Map(source); - } +public class When_mapping_struct_from_StringDictionary : NonValidatingSpecBase +{ + Destination _destination; - [Fact] - public void Should_map_destination_properties() - { - _destination.Foo.ShouldBe("Foo"); - _destination.Bar.ShouldBe("Bar"); - _destination.Baz.ShouldBe(0); - } - [Fact] - public void When_mapping_inner_properties() - { - var source = new StringDictionary() { { "Inner.Value", "5" }, { "NullInner.Value", "5" }, { "SettableInner.Value", "6" }, { "SettableInner.Child.Value", "7" }, - { "Inner.Child.Value", "8" }}; - var destination = Mapper.Map(source); - destination.Inner.Value.ShouldBe(5); - destination.NullInner.ShouldBeNull(); - destination.SettableInner.Value.ShouldBe(6); - destination.SettableInner.Child.Value.ShouldBe(7); - destination.Inner.Child.Value.ShouldBe(8); - } + struct Destination + { + public string Foo { get; set; } + public string Bar { get; set; } } - public class When_mapping_struct_from_StringDictionary : NonValidatingSpecBase + protected override MapperConfiguration CreateConfiguration() => new(cfg => { }); + + protected override void Because_of() { - Destination _destination; + var source = new StringDictionary() { { "Foo", "Foo" }, { "Bar", "Bar" } }; + _destination = Mapper.Map(source); + } - struct Destination - { - public string Foo { get; set; } - public string Bar { get; set; } - } + [Fact] + public void Should_map_destination_properties() + { + _destination.Foo.ShouldBe("Foo"); + _destination.Bar.ShouldBe("Bar"); + } + [Fact] + public void Should_map_non_generic() + { + var source = new StringDictionary() { { "Foo", "Foo" }, { "Bar", "Bar" } }; + var destination = (Destination) Mapper.Map(source, null, typeof(Destination)); + destination.Foo.ShouldBe("Foo"); + destination.Bar.ShouldBe("Bar"); + } +} - protected override MapperConfiguration CreateConfiguration() => new(cfg => { }); +public class When_mapping_from_StringDictionary_with_missing_property : NonValidatingSpecBase +{ + Destination _destination; - protected override void Because_of() - { - var source = new StringDictionary() { { "Foo", "Foo" }, { "Bar", "Bar" } }; - _destination = Mapper.Map(source); - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => { }); - [Fact] - public void Should_map_destination_properties() - { - _destination.Foo.ShouldBe("Foo"); - _destination.Bar.ShouldBe("Bar"); - } - [Fact] - public void Should_map_non_generic() - { - var source = new StringDictionary() { { "Foo", "Foo" }, { "Bar", "Bar" } }; - var destination = (Destination) Mapper.Map(source, null, typeof(Destination)); - destination.Foo.ShouldBe("Foo"); - destination.Bar.ShouldBe("Bar"); - } + protected override void Because_of() + { + var source = new StringDictionary() { { "Foo", "Foo" } }; + _destination = Mapper.Map(source); } - public class When_mapping_from_StringDictionary_with_missing_property : NonValidatingSpecBase + [Fact] + public void Should_map_existing_properties() { - Destination _destination; + _destination.Foo.ShouldBe("Foo"); + _destination.Bar.ShouldBeNull(); + _destination.Baz.ShouldBe(0); + } +} - protected override MapperConfiguration CreateConfiguration() => new(cfg => { }); +public class When_mapping_from_StringDictionary_null_to_int : NonValidatingSpecBase +{ + Destination _destination; - protected override void Because_of() - { - var source = new StringDictionary() { { "Foo", "Foo" } }; - _destination = Mapper.Map(source); - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => { }); - [Fact] - public void Should_map_existing_properties() - { - _destination.Foo.ShouldBe("Foo"); - _destination.Bar.ShouldBeNull(); - _destination.Baz.ShouldBe(0); - } + protected override void Because_of() + { + var source = new StringDictionary() { { "Foo", "Foo" }, { "Baz", null } }; + _destination = Mapper.Map(source); } - public class When_mapping_from_StringDictionary_null_to_int : NonValidatingSpecBase + [Fact] + public void Should_map_to_zero() { - Destination _destination; + _destination.Foo.ShouldBe("Foo"); + _destination.Bar.ShouldBeNull(); + _destination.Baz.ShouldBe(0); + } +} - protected override MapperConfiguration CreateConfiguration() => new(cfg => { }); +public class When_mapping_from_StringDictionary_with_whitespace : NonValidatingSpecBase +{ + Destination _destination; - protected override void Because_of() - { - var source = new StringDictionary() { { "Foo", "Foo" }, { "Baz", null } }; - _destination = Mapper.Map(source); - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => { }); - [Fact] - public void Should_map_to_zero() - { - _destination.Foo.ShouldBe("Foo"); - _destination.Bar.ShouldBeNull(); - _destination.Baz.ShouldBe(0); - } + protected override void Because_of() + { + var source = new StringDictionary() { { " Foo", "Foo" }, { " Bar", "Bar" }, { " Baz ", 2 } }; + _destination = Mapper.Map(source); } - public class When_mapping_from_StringDictionary_with_whitespace : NonValidatingSpecBase + [Fact] + public void Should_map() { - Destination _destination; + _destination.Foo.ShouldBe("Foo"); + _destination.Bar.ShouldBe("Bar"); + _destination.Baz.ShouldBe(2); + } +} - protected override MapperConfiguration CreateConfiguration() => new(cfg => { }); +public class When_mapping_from_StringDictionary_multiple_matching_keys : NonValidatingSpecBase +{ + StringDictionary _source; - protected override void Because_of() - { - var source = new StringDictionary() { { " Foo", "Foo" }, { " Bar", "Bar" }, { " Baz ", 2 } }; - _destination = Mapper.Map(source); - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => { }); - [Fact] - public void Should_map() - { - _destination.Foo.ShouldBe("Foo"); - _destination.Bar.ShouldBe("Bar"); - _destination.Baz.ShouldBe(2); - } + protected override void Because_of() + { + _source = new StringDictionary() { { " Foo", "Foo1" }, { " Foo", "Foo2" }, { "Bar", "Bar" }, { "Baz", 2 } }; } - public class When_mapping_from_StringDictionary_multiple_matching_keys : NonValidatingSpecBase + [Fact] + public void Should_throw_when_mapping() { - StringDictionary _source; + Should.Throw(() => + { + Mapper.Map(_source); + }).InnerException.ShouldBeOfType().Types.ShouldBe(new TypePair(typeof(IDictionary), typeof(Destination))); + } +} - protected override MapperConfiguration CreateConfiguration() => new(cfg => { }); +public class When_mapping_from_StringDictionary_to_StringDictionary : NonValidatingSpecBase +{ + StringDictionary _destination; - protected override void Because_of() - { - _source = new StringDictionary() { { " Foo", "Foo1" }, { " Foo", "Foo2" }, { "Bar", "Bar" }, { "Baz", 2 } }; - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => { }); - [Fact] - public void Should_throw_when_mapping() - { - Should.Throw(() => - { - Mapper.Map(_source); - }).InnerException.ShouldBeOfType().Types.ShouldBe(new TypePair(typeof(IDictionary), typeof(Destination))); - } + protected override void Because_of() + { + var source = new StringDictionary() { { "Foo", "Foo" }, { "Bar", "Bar" }, { "Bar ", "Bar_" } }; + _destination = Mapper.Map(source); } - public class When_mapping_from_StringDictionary_to_StringDictionary : NonValidatingSpecBase + [Fact] + public void Should_map() { - StringDictionary _destination; - - protected override MapperConfiguration CreateConfiguration() => new(cfg => { }); - - protected override void Because_of() - { - var source = new StringDictionary() { { "Foo", "Foo" }, { "Bar", "Bar" }, { "Bar ", "Bar_" } }; - _destination = Mapper.Map(source); - } + _destination["Foo"].ShouldBe("Foo"); + _destination["Bar"].ShouldBe("Bar"); + _destination["Bar "].ShouldBe("Bar_"); + } +} - [Fact] - public void Should_map() - { - _destination["Foo"].ShouldBe("Foo"); - _destination["Bar"].ShouldBe("Bar"); - _destination["Bar "].ShouldBe("Bar_"); - } +public class When_mapping_from_StringDictionary_to_existing_destination : AutoMapperSpecBase +{ + public abstract class SomeBase + { + protected int _x = 100; + public abstract int X { get; } + protected int _y = 200; + public abstract int Y { get; } } - public class When_mapping_from_StringDictionary_to_existing_destination : AutoMapperSpecBase + public class SomeBody : SomeBase { - public abstract class SomeBase - { - protected int _x = 100; - public abstract int X { get; } - protected int _y = 200; - public abstract int Y { get; } - } + public override int X { get { return _x + 10; } } - public class SomeBody : SomeBase - { - public override int X { get { return _x + 10; } } + public override int Y { get { return _y + 20; } } + private int _z = 300; + public int Z { get { return _z + 30; } } + public int Value { get; set; } + public Collection Integers { get; } = new(); + } - public override int Y { get { return _y + 20; } } - private int _z = 300; - public int Z { get { return _z + 30; } } - public int Value { get; set; } - public Collection Integers { get; } = new(); - } + public class SomeOne : SomeBase + { + public override int X { get { return _x - 10; } } - public class SomeOne : SomeBase - { - public override int X { get { return _x - 10; } } + public override int Y { get { return _y - 20; } } + private int _a = 300; + public int A { get { return _a - 30; } } + } - public override int Y { get { return _y - 20; } } - private int _a = 300; - public int A { get { return _a - 30; } } - } + protected override MapperConfiguration CreateConfiguration() => new(c => c.CreateMap()); - protected override MapperConfiguration CreateConfiguration() => new(c => c.CreateMap()); + [Fact] + public void Should_map_ok() + { + var someBase = new SomeBody(); + var someOne = new StringDictionary { ["Integers"] = Enumerable.Range(1, 10).ToArray() }; - [Fact] - public void Should_map_ok() - { - var someBase = new SomeBody(); - var someOne = new StringDictionary { ["Integers"] = Enumerable.Range(1, 10).ToArray() }; + Mapper.Map(someOne, someBase); - Mapper.Map(someOne, someBase); + someBase.Integers.ShouldBe(someOne["Integers"]); + } - someBase.Integers.ShouldBe(someOne["Integers"]); - } + public class Destination + { + public DateTime? NullableDate { get; set; } + public int? NullableInt { get; set; } + public int Int { get; set; } + public SomeBody SomeBody { get; set; } = new SomeBody { Value = 15 }; + public SomeOne SomeOne { get; set; } = new SomeOne(); + public string String { get; set; } = "value"; + } - public class Destination - { - public DateTime? NullableDate { get; set; } - public int? NullableInt { get; set; } - public int Int { get; set; } - public SomeBody SomeBody { get; set; } = new SomeBody { Value = 15 }; - public SomeOne SomeOne { get; set; } = new SomeOne(); - public string String { get; set; } = "value"; - } - - [Fact] - public void Should_override_existing_values() - { - var source = new StringDictionary(); - source["Int"] = 10; - source["NullableDate"] = null; - source["NullableInt"] = null; - source["String"] = null; - source["SomeBody"] = new SomeOne(); - source["SomeOne"] = null; - var destination = new Destination { NullableInt = 1, NullableDate = DateTime.Now }; - var someBody = destination.SomeBody; - - Mapper.Map(source, destination); - - destination.Int.ShouldBe(10); - destination.NullableInt.ShouldBeNull(); - destination.NullableDate.ShouldBeNull(); - destination.SomeBody.ShouldBe(someBody); - destination.SomeBody.Value.ShouldBe(15); - destination.String.ShouldBeNull(); - destination.SomeOne.ShouldBeNull(); - } + [Fact] + public void Should_override_existing_values() + { + var source = new StringDictionary(); + source["Int"] = 10; + source["NullableDate"] = null; + source["NullableInt"] = null; + source["String"] = null; + source["SomeBody"] = new SomeOne(); + source["SomeOne"] = null; + var destination = new Destination { NullableInt = 1, NullableDate = DateTime.Now }; + var someBody = destination.SomeBody; + + Mapper.Map(source, destination); + + destination.Int.ShouldBe(10); + destination.NullableInt.ShouldBeNull(); + destination.NullableDate.ShouldBeNull(); + destination.SomeBody.ShouldBe(someBody); + destination.SomeBody.Value.ShouldBe(15); + destination.String.ShouldBeNull(); + destination.SomeOne.ShouldBeNull(); } +} - public class When_mapping_from_StringDictionary_to_abstract_type : AutoMapperSpecBase +public class When_mapping_from_StringDictionary_to_abstract_type : AutoMapperSpecBase +{ + public abstract class SomeBase { - public abstract class SomeBase - { - protected int _x = 100; - public abstract int X { get; } - protected int _y = 200; - public abstract int Y { get; } - } + protected int _x = 100; + public abstract int X { get; } + protected int _y = 200; + public abstract int Y { get; } + } - public class SomeBody : SomeBase - { - public override int X { get { return _x + 10; } } + public class SomeBody : SomeBase + { + public override int X { get { return _x + 10; } } - public override int Y { get { return _y + 20; } } - private int _z = 300; - public int Z { get { return _z + 30; } } - } + public override int Y { get { return _y + 20; } } + private int _z = 300; + public int Z { get { return _z + 30; } } + } - public class SomeOne : SomeBase - { - public override int X { get { return _x - 10; } } + public class SomeOne : SomeBase + { + public override int X { get { return _x - 10; } } - public override int Y { get { return _y - 20; } } - private int _a = 300; - public int A { get { return _a - 30; } } - } + public override int Y { get { return _y - 20; } } + private int _a = 300; + public int A { get { return _a - 30; } } + } - protected override MapperConfiguration CreateConfiguration() => new(c => c.CreateMap()); + protected override MapperConfiguration CreateConfiguration() => new(c => c.CreateMap()); - [Fact] - public void Should_throw() - { - new Action(() => Mapper.Map(new StringDictionary())) - .ShouldThrowException(ex => - ex.InnerException.Message.ShouldStartWith($"Cannot create an instance of abstract type {typeof(SomeBase)}.")); - } + [Fact] + public void Should_throw() + { + new Action(() => Mapper.Map(new StringDictionary())) + .ShouldThrowException(ex => + ex.InnerException.Message.ShouldStartWith($"Cannot create an instance of abstract type {typeof(SomeBase)}.")); } } \ No newline at end of file diff --git a/src/UnitTests/Mappers/TypeHelperTests.cs b/src/UnitTests/Mappers/TypeHelperTests.cs index 49ab2ee5a6..af41519a97 100644 --- a/src/UnitTests/Mappers/TypeHelperTests.cs +++ b/src/UnitTests/Mappers/TypeHelperTests.cs @@ -5,30 +5,29 @@ using Shouldly; using Xunit; -namespace AutoMapper.UnitTests.Mappers +namespace AutoMapper.UnitTests.Mappers; + +public class TypeHelperTests { - public class TypeHelperTests + [Fact] + public void CanReturnElementTypeOnCollectionThatImplementsTheSameGenericInterfaceMultipleTimes() { - [Fact] - public void CanReturnElementTypeOnCollectionThatImplementsTheSameGenericInterfaceMultipleTimes() - { - Type myType = typeof(ChargeCollection); + Type myType = typeof(ChargeCollection); - Type elementType = ReflectionHelper.GetElementType(myType); + Type elementType = ReflectionHelper.GetElementType(myType); - elementType.ShouldNotBeNull(); - } + elementType.ShouldNotBeNull(); + } - public class Charge { } + public class Charge { } - public interface IChargeCollection : IEnumerable { } + public interface IChargeCollection : IEnumerable { } - public class ChargeCollection : Collection, IChargeCollection + public class ChargeCollection : Collection, IChargeCollection + { + public new IEnumerator GetEnumerator() { - public new IEnumerator GetEnumerator() - { - return null; - } + return null; } } } diff --git a/src/UnitTests/MappingExceptions.cs b/src/UnitTests/MappingExceptions.cs index 356d15da16..2411bc60b0 100644 --- a/src/UnitTests/MappingExceptions.cs +++ b/src/UnitTests/MappingExceptions.cs @@ -3,97 +3,96 @@ using Xunit; using Shouldly; -namespace AutoMapper.UnitTests.MappingExceptions +namespace AutoMapper.UnitTests.MappingExceptions; + +public class When_encountering_a_member_mapping_problem_during_mapping : NonValidatingSpecBase { - public class When_encountering_a_member_mapping_problem_during_mapping : NonValidatingSpecBase + public class Source { - public class Source - { - public string Value { get; set; } - } + public string Value { get; set; } + } - public class Dest - { - public int Value { get; set; } - } + public class Dest + { + public int Value { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + }); + + [Fact] + public void Should_provide_a_contextual_exception() + { + var source = new Source { Value = "adsf" }; + typeof(AutoMapperMappingException).ShouldBeThrownBy(() => Mapper.Map(source)); + } - [Fact] - public void Should_provide_a_contextual_exception() + [Fact] + public void Should_have_contextual_mapping_information() + { + var source = new Source { Value = "adsf" }; + AutoMapperMappingException thrown = null; + try { - var source = new Source { Value = "adsf" }; - typeof(AutoMapperMappingException).ShouldBeThrownBy(() => Mapper.Map(source)); + Mapper.Map(source); } - - [Fact] - public void Should_have_contextual_mapping_information() + catch (AutoMapperMappingException ex) { - var source = new Source { Value = "adsf" }; - AutoMapperMappingException thrown = null; - try - { - Mapper.Map(source); - } - catch (AutoMapperMappingException ex) - { - thrown = ex; - } - thrown.ShouldNotBeNull(); - thrown.TypeMap.ShouldNotBeNull(); - thrown.MemberMap.ShouldNotBeNull(); + thrown = ex; } + thrown.ShouldNotBeNull(); + thrown.TypeMap.ShouldNotBeNull(); + thrown.MemberMap.ShouldNotBeNull(); } +} - public class When_encountering_a_path_mapping_problem_during_mapping : NonValidatingSpecBase +public class When_encountering_a_path_mapping_problem_during_mapping : NonValidatingSpecBase +{ + public class Source { - public class Source - { - public string Value { get; set; } - } + public string Value { get; set; } + } - public class Dest - { - public Sub SubValue { get; set; } + public class Dest + { + public Sub SubValue { get; set; } - public class Sub - { - public int Value { get; set; } - } + public class Sub + { + public int Value { get; set; } } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ForPath(d => d.SubValue.Value, opt => opt.MapFrom(src => src.Value)); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .ForPath(d => d.SubValue.Value, opt => opt.MapFrom(src => src.Value)); + }); + + [Fact] + public void Should_provide_a_contextual_exception() + { + var source = new Source { Value = "adsf" }; + typeof(AutoMapperMappingException).ShouldBeThrownBy(() => Mapper.Map(source)); + } - [Fact] - public void Should_provide_a_contextual_exception() + [Fact] + public void Should_have_contextual_mapping_information() + { + var source = new Source { Value = "adsf" }; + AutoMapperMappingException thrown = null; + try { - var source = new Source { Value = "adsf" }; - typeof(AutoMapperMappingException).ShouldBeThrownBy(() => Mapper.Map(source)); + Mapper.Map(source); } - - [Fact] - public void Should_have_contextual_mapping_information() + catch (AutoMapperMappingException ex) { - var source = new Source { Value = "adsf" }; - AutoMapperMappingException thrown = null; - try - { - Mapper.Map(source); - } - catch (AutoMapperMappingException ex) - { - thrown = ex; - } - thrown.ShouldNotBeNull(); - thrown.TypeMap.ShouldNotBeNull(); - thrown.MemberMap.ShouldNotBeNull(); + thrown = ex; } + thrown.ShouldNotBeNull(); + thrown.TypeMap.ShouldNotBeNull(); + thrown.MemberMap.ShouldNotBeNull(); } } \ No newline at end of file diff --git a/src/UnitTests/MappingExpressionFeatureWithReverseTest.cs b/src/UnitTests/MappingExpressionFeatureWithReverseTest.cs index 4594214b7e..7bade8b588 100644 --- a/src/UnitTests/MappingExpressionFeatureWithReverseTest.cs +++ b/src/UnitTests/MappingExpressionFeatureWithReverseTest.cs @@ -6,255 +6,254 @@ using System.Linq; using Xunit; -namespace AutoMapper.UnitTests +namespace AutoMapper.UnitTests; + +public class MappingExpressionFeatureWithReverseTest { - public class MappingExpressionFeatureWithReverseTest + [Fact] + public void Adding_same_feature_multiple_times_should_replace_eachother() { - [Fact] - public void Adding_same_feature_multiple_times_should_replace_eachother() + var featureA = new MappingExpressionFeatureA(1); + var featureB = new MappingExpressionFeatureB(1); + var config = new MapperConfiguration(cfg => + { + cfg.CreateMap() + .SetFeature(new MappingExpressionFeatureA(3)) + .SetFeature(new MappingExpressionFeatureA(2)) + .SetFeature(featureA) + .SetFeature(new MappingExpressionFeatureB(3)) + .SetFeature(new MappingExpressionFeatureB(2)) + .SetFeature(featureB) + .ReverseMap(); + }); + + + var typeMap = config.FindTypeMapFor(); + typeMap.Features.Count().ShouldBe(2); + + var typeMapReverse = config.FindTypeMapFor(); + typeMapReverse.Features.Count().ShouldBe(2); + + Validate(featureA); + Validate(featureB); + + void Validate(MappingExpressionFeatureBase feature) { - var featureA = new MappingExpressionFeatureA(1); - var featureB = new MappingExpressionFeatureB(1); - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap() - .SetFeature(new MappingExpressionFeatureA(3)) - .SetFeature(new MappingExpressionFeatureA(2)) - .SetFeature(featureA) - .SetFeature(new MappingExpressionFeatureB(3)) - .SetFeature(new MappingExpressionFeatureB(2)) - .SetFeature(featureB) - .ReverseMap(); - }); - - - var typeMap = config.FindTypeMapFor(); - typeMap.Features.Count().ShouldBe(2); - - var typeMapReverse = config.FindTypeMapFor(); - typeMapReverse.Features.Count().ShouldBe(2); - - Validate(featureA); - Validate(featureB); - - void Validate(MappingExpressionFeatureBase feature) - { - feature.ConfigureTypeMaps.ShouldBeOfLength(1); - feature.ReverseMaps.ShouldBeOfLength(1); - } + feature.ConfigureTypeMaps.ShouldBeOfLength(1); + feature.ReverseMaps.ShouldBeOfLength(1); } + } + + [Fact] + public void Add_single_feature_with_reverse() + { + var featureA = new MappingExpressionFeatureA(1); + var config = new MapperConfiguration(cfg => + { + cfg.CreateMap() + .SetFeature(featureA) + .ReverseMap(); + }); + + var typeMap = config.FindTypeMapFor(); + typeMap.Features.Count().ShouldBe(1); + + var typeMapReverse = config.FindTypeMapFor(); + typeMapReverse.Features.Count().ShouldBe(1); + + Validate(featureA); - [Fact] - public void Add_single_feature_with_reverse() + void Validate(MappingExpressionFeatureBase feature) + where TFeature : TypeMapFeatureBase { - var featureA = new MappingExpressionFeatureA(1); - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap() - .SetFeature(featureA) - .ReverseMap(); - }); - - var typeMap = config.FindTypeMapFor(); - typeMap.Features.Count().ShouldBe(1); - - var typeMapReverse = config.FindTypeMapFor(); - typeMapReverse.Features.Count().ShouldBe(1); - - Validate(featureA); - - void Validate(MappingExpressionFeatureBase feature) - where TFeature : TypeMapFeatureBase - { - feature.ConfigureTypeMaps.ShouldBeOfLength(1); - feature.ReverseMaps.ShouldBeOfLength(1); - - var typeMapFeature = typeMap.Features.Get(); - typeMapFeature.ShouldNotBeNull(); - typeMapFeature.Value.ShouldBe(feature.Value); - typeMapFeature.SealedCount.ShouldBe(1); - - var typeMapFeatureReverse = typeMapReverse.Features.Get(); - typeMapFeatureReverse.ShouldNotBeNull(); - typeMapFeatureReverse.Value.ShouldBe(feature.Value + 1); - typeMapFeatureReverse.SealedCount.ShouldBe(1); - } + feature.ConfigureTypeMaps.ShouldBeOfLength(1); + feature.ReverseMaps.ShouldBeOfLength(1); + + var typeMapFeature = typeMap.Features.Get(); + typeMapFeature.ShouldNotBeNull(); + typeMapFeature.Value.ShouldBe(feature.Value); + typeMapFeature.SealedCount.ShouldBe(1); + + var typeMapFeatureReverse = typeMapReverse.Features.Get(); + typeMapFeatureReverse.ShouldNotBeNull(); + typeMapFeatureReverse.Value.ShouldBe(feature.Value + 1); + typeMapFeatureReverse.SealedCount.ShouldBe(1); } + } + + [Fact] + public void Add_multiple_features_with_reverse() + { + var featureA = new MappingExpressionFeatureA(1); + var featureB = new MappingExpressionFeatureB(2); + var config = new MapperConfiguration(cfg => + { + cfg.CreateMap() + .SetFeature(featureA) + .SetFeature(featureB) + .ReverseMap(); + }); + + var typeMap = config.FindTypeMapFor(); + typeMap.Features.Count().ShouldBe(2); + + var typeMapReverse = config.FindTypeMapFor(); + typeMapReverse.Features.Count().ShouldBe(2); + + Validate(featureA); + Validate(featureB); - [Fact] - public void Add_multiple_features_with_reverse() + void Validate(MappingExpressionFeatureBase feature) + where TFeature : TypeMapFeatureBase { - var featureA = new MappingExpressionFeatureA(1); - var featureB = new MappingExpressionFeatureB(2); - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap() - .SetFeature(featureA) - .SetFeature(featureB) - .ReverseMap(); - }); - - var typeMap = config.FindTypeMapFor(); - typeMap.Features.Count().ShouldBe(2); - - var typeMapReverse = config.FindTypeMapFor(); - typeMapReverse.Features.Count().ShouldBe(2); - - Validate(featureA); - Validate(featureB); - - void Validate(MappingExpressionFeatureBase feature) - where TFeature : TypeMapFeatureBase - { - feature.ConfigureTypeMaps.ShouldBeOfLength(1); - feature.ReverseMaps.ShouldBeOfLength(1); - - var typeMapFeature = typeMap.Features.Get(); - typeMapFeature.ShouldNotBeNull(); - typeMapFeature.Value.ShouldBe(feature.Value); - typeMapFeature.SealedCount.ShouldBe(1); - - var typeMapFeatureReverse = typeMapReverse.Features.Get(); - typeMapFeatureReverse.ShouldNotBeNull(); - typeMapFeatureReverse.Value.ShouldBe(feature.Value + 1); - typeMapFeatureReverse.SealedCount.ShouldBe(1); - } + feature.ConfigureTypeMaps.ShouldBeOfLength(1); + feature.ReverseMaps.ShouldBeOfLength(1); + + var typeMapFeature = typeMap.Features.Get(); + typeMapFeature.ShouldNotBeNull(); + typeMapFeature.Value.ShouldBe(feature.Value); + typeMapFeature.SealedCount.ShouldBe(1); + + var typeMapFeatureReverse = typeMapReverse.Features.Get(); + typeMapFeatureReverse.ShouldNotBeNull(); + typeMapFeatureReverse.Value.ShouldBe(feature.Value + 1); + typeMapFeatureReverse.SealedCount.ShouldBe(1); } + } - [Fact] - public void Add_multiple_features_with_reverse_overriden() + [Fact] + public void Add_multiple_features_with_reverse_overriden() + { + var featureA = new MappingExpressionFeatureA(1); + var featureB = new MappingExpressionFeatureB(2); + var overridenFeatureB = new MappingExpressionFeatureB(10); + var config = new MapperConfiguration(cfg => + { + cfg.CreateMap() + .SetFeature(featureA) + .SetFeature(featureB) + .ReverseMap() + .SetFeature(overridenFeatureB); + }); + + var typeMap = config.FindTypeMapFor(); + typeMap.Features.Count().ShouldBe(2); + + var typeMapReverse = config.FindTypeMapFor(); + typeMapReverse.Features.Count().ShouldBe(2); + + Validate(featureA, typeMap); + Validate(featureB, typeMap); + Validate(featureA, typeMapReverse, value: featureA.Value + 1); + Validate(overridenFeatureB, typeMapReverse, 0); + + void Validate(MappingExpressionFeatureBase feature, TypeMap map, int reverseExecutedCount = 1, int? value = null) + where TFeature : TypeMapFeatureBase { - var featureA = new MappingExpressionFeatureA(1); - var featureB = new MappingExpressionFeatureB(2); - var overridenFeatureB = new MappingExpressionFeatureB(10); - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap() - .SetFeature(featureA) - .SetFeature(featureB) - .ReverseMap() - .SetFeature(overridenFeatureB); - }); - - var typeMap = config.FindTypeMapFor(); - typeMap.Features.Count().ShouldBe(2); - - var typeMapReverse = config.FindTypeMapFor(); - typeMapReverse.Features.Count().ShouldBe(2); - - Validate(featureA, typeMap); - Validate(featureB, typeMap); - Validate(featureA, typeMapReverse, value: featureA.Value + 1); - Validate(overridenFeatureB, typeMapReverse, 0); - - void Validate(MappingExpressionFeatureBase feature, TypeMap map, int reverseExecutedCount = 1, int? value = null) - where TFeature : TypeMapFeatureBase - { - feature.ConfigureTypeMaps.ShouldBeOfLength(1); - feature.ReverseMaps.ShouldBeOfLength(reverseExecutedCount); - - var typeMapFeature = map.Features.Get(); - typeMapFeature.ShouldNotBeNull(); - typeMapFeature.Value.ShouldBe(value ?? feature.Value); - typeMapFeature.SealedCount.ShouldBe(1); - } + feature.ConfigureTypeMaps.ShouldBeOfLength(1); + feature.ReverseMaps.ShouldBeOfLength(reverseExecutedCount); + + var typeMapFeature = map.Features.Get(); + typeMapFeature.ShouldNotBeNull(); + typeMapFeature.Value.ShouldBe(value ?? feature.Value); + typeMapFeature.SealedCount.ShouldBe(1); } + } - public class MappingExpressionFeatureA : MappingExpressionFeatureBase + public class MappingExpressionFeatureA : MappingExpressionFeatureBase + { + public MappingExpressionFeatureA(int value) : base(value, new TypeMapFeatureA(value), () => new MappingExpressionFeatureA(value + 1)) { - public MappingExpressionFeatureA(int value) : base(value, new TypeMapFeatureA(value), () => new MappingExpressionFeatureA(value + 1)) - { - } } + } - public class MappingExpressionFeatureB : MappingExpressionFeatureBase + public class MappingExpressionFeatureB : MappingExpressionFeatureBase + { + public MappingExpressionFeatureB(int value) : base(value, new TypeMapFeatureB(value), () => new MappingExpressionFeatureB(value + 1)) { - public MappingExpressionFeatureB(int value) : base(value, new TypeMapFeatureB(value), () => new MappingExpressionFeatureB(value + 1)) - { - } } + } - public abstract class MappingExpressionFeatureBase : MappingExpressionFeatureBase - where TFeature : IRuntimeFeature + public abstract class MappingExpressionFeatureBase : MappingExpressionFeatureBase + where TFeature : IRuntimeFeature + { + private readonly TFeature _feature; + + protected MappingExpressionFeatureBase(int value, TFeature feature, Func reverseMappingExpressionFeature) + : base(value, reverseMappingExpressionFeature) { - private readonly TFeature _feature; - - protected MappingExpressionFeatureBase(int value, TFeature feature, Func reverseMappingExpressionFeature) - : base(value, reverseMappingExpressionFeature) - { - _feature = feature; - } - - public override void Configure(TypeMap typeMap) - { - ConfigureTypeMaps.Add(typeMap); - typeMap.Features.Set(_feature); - } + _feature = feature; } - public abstract class MappingExpressionFeatureBase : IMappingFeature + public override void Configure(TypeMap typeMap) { - public int Value { get; } - public List ConfigureTypeMaps { get; } = new List(); - public List ReverseMaps { get; } = new List(); - - private readonly Func _reverseMappingExpressionFeature; - - protected MappingExpressionFeatureBase(int value, Func reverseMappingExpressionFeature) - { - Value = value; - _reverseMappingExpressionFeature = reverseMappingExpressionFeature; - } - - public abstract void Configure(TypeMap typeMap); - - public IMappingFeature Reverse() - { - var reverse = _reverseMappingExpressionFeature(); - ReverseMaps.Add(reverse); - return reverse; - } + ConfigureTypeMaps.Add(typeMap); + typeMap.Features.Set(_feature); } + } + + public abstract class MappingExpressionFeatureBase : IMappingFeature + { + public int Value { get; } + public List ConfigureTypeMaps { get; } = new List(); + public List ReverseMaps { get; } = new List(); + + private readonly Func _reverseMappingExpressionFeature; + + protected MappingExpressionFeatureBase(int value, Func reverseMappingExpressionFeature) + { + Value = value; + _reverseMappingExpressionFeature = reverseMappingExpressionFeature; + } + + public abstract void Configure(TypeMap typeMap); - public class TypeMapFeatureA : TypeMapFeatureBase + public IMappingFeature Reverse() { - public TypeMapFeatureA(int value) : base(value) - { - } + var reverse = _reverseMappingExpressionFeature(); + ReverseMaps.Add(reverse); + return reverse; } + } - public class TypeMapFeatureB : TypeMapFeatureBase + public class TypeMapFeatureA : TypeMapFeatureBase + { + public TypeMapFeatureA(int value) : base(value) { - public TypeMapFeatureB(int value) : base(value) - { - } } + } - public abstract class TypeMapFeatureBase : IRuntimeFeature + public class TypeMapFeatureB : TypeMapFeatureBase + { + public TypeMapFeatureB(int value) : base(value) { - public int SealedCount { get; private set; } - public int Value { get; } - - public TypeMapFeatureBase(int value) - { - Value = value; - } - - void IRuntimeFeature.Seal(IGlobalConfiguration configurationProvider) - { - SealedCount++; - } } + } + public abstract class TypeMapFeatureBase : IRuntimeFeature + { + public int SealedCount { get; private set; } + public int Value { get; } - public class Source + public TypeMapFeatureBase(int value) { - public int Value { get; set; } + Value = value; } - public class Dest + void IRuntimeFeature.Seal(IGlobalConfiguration configurationProvider) { - public int Value { get; set; } + SealedCount++; } } + + + public class Source + { + public int Value { get; set; } + } + + public class Dest + { + public int Value { get; set; } + } } \ No newline at end of file diff --git a/src/UnitTests/MappingExpressionFeatureWithoutReverseTest.cs b/src/UnitTests/MappingExpressionFeatureWithoutReverseTest.cs index 24c3a52564..c574bdfc68 100644 --- a/src/UnitTests/MappingExpressionFeatureWithoutReverseTest.cs +++ b/src/UnitTests/MappingExpressionFeatureWithoutReverseTest.cs @@ -5,307 +5,306 @@ using System.Linq; using Xunit; -namespace AutoMapper.UnitTests +namespace AutoMapper.UnitTests; + +public class MappingExpressionFeatureWithoutReverseTest { - public class MappingExpressionFeatureWithoutReverseTest + [Fact] + public void Adding_same_feature_should_replace_eachother() { - [Fact] - public void Adding_same_feature_should_replace_eachother() + var featureA = new MappingExpressionFeatureA(1); + var featureB = new MappingExpressionFeatureB(2); + var config = new MapperConfiguration(cfg => + { + cfg.CreateMap() + .SetFeature(new MappingExpressionFeatureA(3)) + .SetFeature(new MappingExpressionFeatureA(2)) + .SetFeature(featureA) + .SetFeature(new MappingExpressionFeatureB(3)) + .SetFeature(new MappingExpressionFeatureB(2)) + .SetFeature(featureB) + .ReverseMap(); + }); + + + var typeMap = config.FindTypeMapFor(); + typeMap.Features.Count().ShouldBe(2); + + var typeMapReverse = config.ResolveTypeMap(typeof(Dest), typeof(Source)); + typeMapReverse.Features.Count().ShouldBe(0); + + Validate(featureA); + Validate(featureB); + + void Validate(MappingExpressionFeatureBase feature) { - var featureA = new MappingExpressionFeatureA(1); - var featureB = new MappingExpressionFeatureB(2); - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap() - .SetFeature(new MappingExpressionFeatureA(3)) - .SetFeature(new MappingExpressionFeatureA(2)) - .SetFeature(featureA) - .SetFeature(new MappingExpressionFeatureB(3)) - .SetFeature(new MappingExpressionFeatureB(2)) - .SetFeature(featureB) - .ReverseMap(); - }); - - - var typeMap = config.FindTypeMapFor(); - typeMap.Features.Count().ShouldBe(2); - - var typeMapReverse = config.ResolveTypeMap(typeof(Dest), typeof(Source)); - typeMapReverse.Features.Count().ShouldBe(0); - - Validate(featureA); - Validate(featureB); - - void Validate(MappingExpressionFeatureBase feature) - { - feature.ConfigureTypeMaps.ShouldBeOfLength(1); - feature.ReverseExecutedCount.ShouldBe(1); - } + feature.ConfigureTypeMaps.ShouldBeOfLength(1); + feature.ReverseExecutedCount.ShouldBe(1); } + } - [Fact] - public void Add_single_feature() + [Fact] + public void Add_single_feature() + { + var featureA = new MappingExpressionFeatureA(1); + var config = new MapperConfiguration(cfg => { - var featureA = new MappingExpressionFeatureA(1); - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap() - .SetFeature(featureA) - .ReverseMap(); - }); - - var typeMap = config.FindTypeMapFor(); - typeMap.Features.Count().ShouldBe(1); - - var typeMapReverse = config.ResolveTypeMap(typeof(Dest), typeof(Source)); - typeMapReverse.Features.Count().ShouldBe(0); - - Validate(featureA); - - void Validate(MappingExpressionFeatureBase feature) - where TFeature : TypeMapFeatureBase - { - feature.ConfigureTypeMaps.ShouldBeOfLength(1); - feature.ReverseExecutedCount.ShouldBe(1); - - var typeMapFeature = typeMap.Features.Get(); - typeMapFeature.ShouldNotBeNull(); - typeMapFeature.Value.ShouldBe(feature.Value); - typeMapFeature.SealedCount.ShouldBe(1); - } + cfg.CreateMap() + .SetFeature(featureA) + .ReverseMap(); + }); + + var typeMap = config.FindTypeMapFor(); + typeMap.Features.Count().ShouldBe(1); + + var typeMapReverse = config.ResolveTypeMap(typeof(Dest), typeof(Source)); + typeMapReverse.Features.Count().ShouldBe(0); + + Validate(featureA); + + void Validate(MappingExpressionFeatureBase feature) + where TFeature : TypeMapFeatureBase + { + feature.ConfigureTypeMaps.ShouldBeOfLength(1); + feature.ReverseExecutedCount.ShouldBe(1); + + var typeMapFeature = typeMap.Features.Get(); + typeMapFeature.ShouldNotBeNull(); + typeMapFeature.Value.ShouldBe(feature.Value); + typeMapFeature.SealedCount.ShouldBe(1); } + } - [Fact] - public void Add_single_feature_with_reverse() + [Fact] + public void Add_single_feature_with_reverse() + { + var featureA = new MappingExpressionFeatureA(1); + var config = new MapperConfiguration(cfg => { - var featureA = new MappingExpressionFeatureA(1); - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap() - .SetFeature(featureA) - .ReverseMap(); - }); - - var typeMap = config.FindTypeMapFor(); - typeMap.Features.Count().ShouldBe(1); - - var typeMapReverse = config.FindTypeMapFor(); - typeMapReverse.Features.Count().ShouldBe(0); - - Validate(featureA); - - void Validate(MappingExpressionFeatureBase feature) - where TFeature : TypeMapFeatureBase - { - feature.ConfigureTypeMaps.ShouldBeOfLength(1); - feature.ReverseExecutedCount.ShouldBe(1); - - var typeMapFeature = typeMap.Features.Get(); - typeMapFeature.ShouldNotBeNull(); - typeMapFeature.Value.ShouldBe(feature.Value); - typeMapFeature.SealedCount.ShouldBe(1); - } + cfg.CreateMap() + .SetFeature(featureA) + .ReverseMap(); + }); + + var typeMap = config.FindTypeMapFor(); + typeMap.Features.Count().ShouldBe(1); + + var typeMapReverse = config.FindTypeMapFor(); + typeMapReverse.Features.Count().ShouldBe(0); + + Validate(featureA); + + void Validate(MappingExpressionFeatureBase feature) + where TFeature : TypeMapFeatureBase + { + feature.ConfigureTypeMaps.ShouldBeOfLength(1); + feature.ReverseExecutedCount.ShouldBe(1); + + var typeMapFeature = typeMap.Features.Get(); + typeMapFeature.ShouldNotBeNull(); + typeMapFeature.Value.ShouldBe(feature.Value); + typeMapFeature.SealedCount.ShouldBe(1); + } + } + + [Fact] + public void Add_multiple_features() + { + var featureA = new MappingExpressionFeatureA(1); + var featureB = new MappingExpressionFeatureB(2); + var config = new MapperConfiguration(cfg => + { + cfg.CreateMap() + .SetFeature(featureA) + .SetFeature(featureB) + .ReverseMap(); + }); + + + var typeMap = config.FindTypeMapFor(); + typeMap.Features.Count().ShouldBe(2); + + var typeMapReverse = config.ResolveTypeMap(typeof(Dest), typeof(Source)); + typeMapReverse.Features.Count().ShouldBe(0); + + Validate(featureA); + Validate(featureB); + + void Validate(MappingExpressionFeatureBase feature) + where TFeature : TypeMapFeatureBase + { + feature.ConfigureTypeMaps.ShouldBeOfLength(1); + feature.ReverseExecutedCount.ShouldBe(1); + + var typeMapFeature = typeMap.Features.Get(); + typeMapFeature.ShouldNotBeNull(); + typeMapFeature.Value.ShouldBe(feature.Value); + typeMapFeature.SealedCount.ShouldBe(1); } + } + + [Fact] + public void Add_multiple_features_with_reverse() + { + var featureA = new MappingExpressionFeatureA(1); + var featureB = new MappingExpressionFeatureB(2); + var config = new MapperConfiguration(cfg => + { + cfg.CreateMap() + .SetFeature(featureA) + .SetFeature(featureB) + .ReverseMap(); + }); + + var typeMap = config.FindTypeMapFor(); + typeMap.Features.Count().ShouldBe(2); + + var typeMapReverse = config.FindTypeMapFor(); + typeMapReverse.Features.Count().ShouldBe(0); - [Fact] - public void Add_multiple_features() + Validate(featureA); + Validate(featureB); + + void Validate(MappingExpressionFeatureBase feature) + where TFeature : TypeMapFeatureBase { - var featureA = new MappingExpressionFeatureA(1); - var featureB = new MappingExpressionFeatureB(2); - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap() - .SetFeature(featureA) - .SetFeature(featureB) - .ReverseMap(); - }); - - - var typeMap = config.FindTypeMapFor(); - typeMap.Features.Count().ShouldBe(2); - - var typeMapReverse = config.ResolveTypeMap(typeof(Dest), typeof(Source)); - typeMapReverse.Features.Count().ShouldBe(0); - - Validate(featureA); - Validate(featureB); - - void Validate(MappingExpressionFeatureBase feature) - where TFeature : TypeMapFeatureBase - { - feature.ConfigureTypeMaps.ShouldBeOfLength(1); - feature.ReverseExecutedCount.ShouldBe(1); - - var typeMapFeature = typeMap.Features.Get(); - typeMapFeature.ShouldNotBeNull(); - typeMapFeature.Value.ShouldBe(feature.Value); - typeMapFeature.SealedCount.ShouldBe(1); - } + feature.ConfigureTypeMaps.ShouldBeOfLength(1); + feature.ReverseExecutedCount.ShouldBe(1); + + var typeMapFeature = typeMap.Features.Get(); + typeMapFeature.ShouldNotBeNull(); + typeMapFeature.Value.ShouldBe(feature.Value); + typeMapFeature.SealedCount.ShouldBe(1); } + } - [Fact] - public void Add_multiple_features_with_reverse() + [Fact] + public void Add_multiple_features_with_reverse_overriden() + { + var featureA = new MappingExpressionFeatureA(1); + var featureB = new MappingExpressionFeatureB(2); + var overridenFeatureB = new MappingExpressionFeatureB(10); + var config = new MapperConfiguration(cfg => { - var featureA = new MappingExpressionFeatureA(1); - var featureB = new MappingExpressionFeatureB(2); - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap() - .SetFeature(featureA) - .SetFeature(featureB) - .ReverseMap(); - }); - - var typeMap = config.FindTypeMapFor(); - typeMap.Features.Count().ShouldBe(2); - - var typeMapReverse = config.FindTypeMapFor(); - typeMapReverse.Features.Count().ShouldBe(0); - - Validate(featureA); - Validate(featureB); - - void Validate(MappingExpressionFeatureBase feature) - where TFeature : TypeMapFeatureBase - { - feature.ConfigureTypeMaps.ShouldBeOfLength(1); - feature.ReverseExecutedCount.ShouldBe(1); - - var typeMapFeature = typeMap.Features.Get(); - typeMapFeature.ShouldNotBeNull(); - typeMapFeature.Value.ShouldBe(feature.Value); - typeMapFeature.SealedCount.ShouldBe(1); - } + cfg.CreateMap() + .SetFeature(featureA) + .SetFeature(featureB) + .ReverseMap() + .SetFeature(overridenFeatureB); + }); + + var typeMap = config.FindTypeMapFor(); + typeMap.Features.Count().ShouldBe(2); + + var typeMapReverse = config.FindTypeMapFor(); + typeMapReverse.Features.Count().ShouldBe(1); + + Validate(featureA, typeMap); + Validate(featureB, typeMap); + Validate(overridenFeatureB, typeMapReverse, 0); + + void Validate(MappingExpressionFeatureBase feature, TypeMap map, int reverseExecutedCount = 1) + where TFeature : TypeMapFeatureBase + { + feature.ConfigureTypeMaps.ShouldBeOfLength(1); + feature.ReverseExecutedCount.ShouldBe(reverseExecutedCount); + + var typeMapFeature = map.Features.Get(); + typeMapFeature.ShouldNotBeNull(); + typeMapFeature.Value.ShouldBe(feature.Value); + typeMapFeature.SealedCount.ShouldBe(1); } + } - [Fact] - public void Add_multiple_features_with_reverse_overriden() + public class MappingExpressionFeatureA : MappingExpressionFeatureBase + { + public MappingExpressionFeatureA(int value) : base(value, new TypeMapFeatureA(value)) { - var featureA = new MappingExpressionFeatureA(1); - var featureB = new MappingExpressionFeatureB(2); - var overridenFeatureB = new MappingExpressionFeatureB(10); - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap() - .SetFeature(featureA) - .SetFeature(featureB) - .ReverseMap() - .SetFeature(overridenFeatureB); - }); - - var typeMap = config.FindTypeMapFor(); - typeMap.Features.Count().ShouldBe(2); - - var typeMapReverse = config.FindTypeMapFor(); - typeMapReverse.Features.Count().ShouldBe(1); - - Validate(featureA, typeMap); - Validate(featureB, typeMap); - Validate(overridenFeatureB, typeMapReverse, 0); - - void Validate(MappingExpressionFeatureBase feature, TypeMap map, int reverseExecutedCount = 1) - where TFeature : TypeMapFeatureBase - { - feature.ConfigureTypeMaps.ShouldBeOfLength(1); - feature.ReverseExecutedCount.ShouldBe(reverseExecutedCount); - - var typeMapFeature = map.Features.Get(); - typeMapFeature.ShouldNotBeNull(); - typeMapFeature.Value.ShouldBe(feature.Value); - typeMapFeature.SealedCount.ShouldBe(1); - } } + } - public class MappingExpressionFeatureA : MappingExpressionFeatureBase + public class MappingExpressionFeatureB : MappingExpressionFeatureBase + { + public MappingExpressionFeatureB(int value) : base(value, new TypeMapFeatureB(value)) { - public MappingExpressionFeatureA(int value) : base(value, new TypeMapFeatureA(value)) - { - } } + } - public class MappingExpressionFeatureB : MappingExpressionFeatureBase + public abstract class MappingExpressionFeatureBase : MappingExpressionFeatureBase + where TFeature : IRuntimeFeature + { + private readonly TFeature _feature; + + protected MappingExpressionFeatureBase(int value, TFeature feature) + : base(value) { - public MappingExpressionFeatureB(int value) : base(value, new TypeMapFeatureB(value)) - { - } + _feature = feature; } - public abstract class MappingExpressionFeatureBase : MappingExpressionFeatureBase - where TFeature : IRuntimeFeature + public override void Configure(TypeMap typeMap) { - private readonly TFeature _feature; - - protected MappingExpressionFeatureBase(int value, TFeature feature) - : base(value) - { - _feature = feature; - } - - public override void Configure(TypeMap typeMap) - { - ConfigureTypeMaps.Add(typeMap); - typeMap.Features.Set(_feature); - } + ConfigureTypeMaps.Add(typeMap); + typeMap.Features.Set(_feature); } + } - public abstract class MappingExpressionFeatureBase : IMappingFeature + public abstract class MappingExpressionFeatureBase : IMappingFeature + { + public int Value { get; } + public List ConfigureTypeMaps { get; } = new List(); + public int ReverseExecutedCount { get; private set; } + + protected MappingExpressionFeatureBase(int value) { - public int Value { get; } - public List ConfigureTypeMaps { get; } = new List(); - public int ReverseExecutedCount { get; private set; } - - protected MappingExpressionFeatureBase(int value) - { - Value = value; - } - - public abstract void Configure(TypeMap typeMap); - - public IMappingFeature Reverse() - { - ReverseExecutedCount++; - return null; - } + Value = value; } - public class TypeMapFeatureA : TypeMapFeatureBase + public abstract void Configure(TypeMap typeMap); + + public IMappingFeature Reverse() { - public TypeMapFeatureA(int value) : base(value) - { - } + ReverseExecutedCount++; + return null; } + } - public class TypeMapFeatureB : TypeMapFeatureBase + public class TypeMapFeatureA : TypeMapFeatureBase + { + public TypeMapFeatureA(int value) : base(value) { - public TypeMapFeatureB(int value) : base(value) - { - } } + } - public abstract class TypeMapFeatureBase : IRuntimeFeature + public class TypeMapFeatureB : TypeMapFeatureBase + { + public TypeMapFeatureB(int value) : base(value) { - public int SealedCount { get; private set; } - public int Value { get; } - - public TypeMapFeatureBase(int value) - { - Value = value; - } - - void IRuntimeFeature.Seal(IGlobalConfiguration configurationProvider) - { - SealedCount++; - } } + } + + public abstract class TypeMapFeatureBase : IRuntimeFeature + { + public int SealedCount { get; private set; } + public int Value { get; } - public class Source + public TypeMapFeatureBase(int value) { - public int Value { get; set; } + Value = value; } - public class Dest + void IRuntimeFeature.Seal(IGlobalConfiguration configurationProvider) { - public int Value { get; set; } + SealedCount++; } } + + public class Source + { + public int Value { get; set; } + } + + public class Dest + { + public int Value { get; set; } + } } \ No newline at end of file diff --git a/src/UnitTests/MappingInheritance/ApplyIncludeBaseRecursively.cs b/src/UnitTests/MappingInheritance/ApplyIncludeBaseRecursively.cs index 27ff08dfaa..a4a9148222 100644 --- a/src/UnitTests/MappingInheritance/ApplyIncludeBaseRecursively.cs +++ b/src/UnitTests/MappingInheritance/ApplyIncludeBaseRecursively.cs @@ -3,132 +3,131 @@ using AutoMapper; using Xunit; -namespace AutoMapper.UnitTests.MappingInheritance +namespace AutoMapper.UnitTests.MappingInheritance; + +public class ApplyIncludeBaseRecursively : AutoMapperSpecBase { - public class ApplyIncludeBaseRecursively : AutoMapperSpecBase - { - ViewModel _destination; + ViewModel _destination; - public class BaseEntity - { - public string Property1 { get; set; } - } - public class SubBaseEntity : BaseEntity { } + public class BaseEntity + { + public string Property1 { get; set; } + } + public class SubBaseEntity : BaseEntity { } - public class SpecificEntity : SubBaseEntity - { - public bool Map { get; set; } - } + public class SpecificEntity : SubBaseEntity + { + public bool Map { get; set; } + } - public class ViewModel - { - public string Property2 { get; set; } - } + public class ViewModel + { + public string Property2 { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ForMember(vm => vm.Property2, opt => opt.MapFrom(e => e.Property1)); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .ForMember(vm => vm.Property2, opt => opt.MapFrom(e => e.Property1)); - cfg.CreateMap() - .IncludeBase(); + cfg.CreateMap() + .IncludeBase(); - cfg.CreateMap() - .IncludeBase() - .ForMember(vm => vm.Property2, opt => opt.Condition(e => e.Map)); - }); + cfg.CreateMap() + .IncludeBase() + .ForMember(vm => vm.Property2, opt => opt.Condition(e => e.Map)); + }); - protected override void Because_of() - { - _destination = Mapper.Map(new SpecificEntity{ Map = true, Property1 = "Test" }); - } + protected override void Because_of() + { + _destination = Mapper.Map(new SpecificEntity{ Map = true, Property1 = "Test" }); + } - [Fact] - public void Should_apply_all_included_base_maps() - { - _destination.Property2.ShouldBe("Test"); - } - } - public class IncludeOrder : AutoMapperSpecBase - { - public interface IDevice - { - int Id { get; set; } - } - public interface IDerivedDevice : IDevice - { - int AdditionalProperty { get; set; } - } - public class Device : IDevice - { - public int Id { get; set; } - } - public class DerivedDevice : Device, IDerivedDevice - { - public int AdditionalProperty { get; set; } - } - public class DeviceDto - { - public int Id { get; set; } + [Fact] + public void Should_apply_all_included_base_maps() + { + _destination.Property2.ShouldBe("Test"); + } +} +public class IncludeOrder : AutoMapperSpecBase +{ + public interface IDevice + { + int Id { get; set; } + } + public interface IDerivedDevice : IDevice + { + int AdditionalProperty { get; set; } + } + public class Device : IDevice + { + public int Id { get; set; } + } + public class DerivedDevice : Device, IDerivedDevice + { + public int AdditionalProperty { get; set; } + } + public class DeviceDto + { + public int Id { get; set; } - public int AdditionalProperty { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(MemberList.None).Include(); - cfg.CreateMap(); - }); - [Fact] - public void BaseFirst() - { - var source = new IDevice[] { new Device { Id = 2 }, new DerivedDevice { Id = 1, AdditionalProperty = 7 } }; - var destination = Map(source); - destination[0].Id.ShouldBe(2); - destination[0].AdditionalProperty.ShouldBe(0); - destination[1].Id.ShouldBe(1); - destination[1].AdditionalProperty.ShouldBe(7); - } - [Fact] - public void DerivedFirst() - { - var source = new IDevice[] { new DerivedDevice { Id = 1, AdditionalProperty = 7 }, new Device { Id = 2 } }; - var destination = Map(source); - destination[0].Id.ShouldBe(1); - destination[0].AdditionalProperty.ShouldBe(7); - destination[1].Id.ShouldBe(2); - destination[1].AdditionalProperty.ShouldBe(0); - } - } - public class CircularAs : NonValidatingSpecBase - { - public interface IDevice - { - int Id { get; set; } - } - public interface IDerivedDevice : IDevice - { - int AdditionalProperty { get; set; } - } - public class Device : IDevice - { - public int Id { get; set; } - } - public class DerivedDevice : Device, IDerivedDevice - { - public int AdditionalProperty { get; set; } - } - public class DeviceDto - { - public int Id { get; set; } - public int AdditionalProperty { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(MemberList.None).As(); - cfg.CreateMap(); - }); - [Fact] - public void Should_report_the_error() => new Action(AssertConfigurationIsValid).ShouldThrow().Message.ShouldBe( - "As must specify a derived type, not " + typeof(DeviceDto)); + public int AdditionalProperty { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(MemberList.None).Include(); + cfg.CreateMap(); + }); + [Fact] + public void BaseFirst() + { + var source = new IDevice[] { new Device { Id = 2 }, new DerivedDevice { Id = 1, AdditionalProperty = 7 } }; + var destination = Map(source); + destination[0].Id.ShouldBe(2); + destination[0].AdditionalProperty.ShouldBe(0); + destination[1].Id.ShouldBe(1); + destination[1].AdditionalProperty.ShouldBe(7); + } + [Fact] + public void DerivedFirst() + { + var source = new IDevice[] { new DerivedDevice { Id = 1, AdditionalProperty = 7 }, new Device { Id = 2 } }; + var destination = Map(source); + destination[0].Id.ShouldBe(1); + destination[0].AdditionalProperty.ShouldBe(7); + destination[1].Id.ShouldBe(2); + destination[1].AdditionalProperty.ShouldBe(0); + } +} +public class CircularAs : NonValidatingSpecBase +{ + public interface IDevice + { + int Id { get; set; } + } + public interface IDerivedDevice : IDevice + { + int AdditionalProperty { get; set; } + } + public class Device : IDevice + { + public int Id { get; set; } } + public class DerivedDevice : Device, IDerivedDevice + { + public int AdditionalProperty { get; set; } + } + public class DeviceDto + { + public int Id { get; set; } + public int AdditionalProperty { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(MemberList.None).As(); + cfg.CreateMap(); + }); + [Fact] + public void Should_report_the_error() => new Action(AssertConfigurationIsValid).ShouldThrow().Message.ShouldBe( + "As must specify a derived type, not " + typeof(DeviceDto)); } \ No newline at end of file diff --git a/src/UnitTests/MappingInheritance/ConventionMappedCollectionShouldMapBaseTypes.cs b/src/UnitTests/MappingInheritance/ConventionMappedCollectionShouldMapBaseTypes.cs index 40ddee1b30..ad4077d5a9 100644 --- a/src/UnitTests/MappingInheritance/ConventionMappedCollectionShouldMapBaseTypes.cs +++ b/src/UnitTests/MappingInheritance/ConventionMappedCollectionShouldMapBaseTypes.cs @@ -5,89 +5,88 @@ using Shouldly; using Xunit; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class ConventionMappedCollectionShouldMapBaseTypes { - public class ConventionMappedCollectionShouldMapBaseTypes - { - public class ItemBase{} - public class GeneralItem : ItemBase {} - public class SpecificItem : ItemBase {} + public class ItemBase{} + public class GeneralItem : ItemBase {} + public class SpecificItem : ItemBase {} - public class Container + public class Container + { + public Container () { - public Container () - { - Items = new List(); - } - public List Items { get; private set; } + Items = new List(); } + public List Items { get; private set; } + } - public class ItemDto {} - public class GeneralItemDto :ItemDto {} - public class SpecificItemDto :ItemDto {} + public class ItemDto {} + public class GeneralItemDto :ItemDto {} + public class SpecificItemDto :ItemDto {} - public class ContainerDto + public class ContainerDto + { + public ContainerDto() { - public ContainerDto() - { - Items = new List(); - } - public List Items { get; private set; } + Items = new List(); } + public List Items { get; private set; } + } - // Getting an exception casting from SpecificItemDto to GeneralItemDto - // because it is selecting too specific a mapping for the collection. - [Fact] - public void item_collection_should_map_by_base_type() + // Getting an exception casting from SpecificItemDto to GeneralItemDto + // because it is selecting too specific a mapping for the collection. + [Fact] + public void item_collection_should_map_by_base_type() + { + var config = new MapperConfiguration(cfg => { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap(); - cfg.CreateMap() - .Include() - .Include(); - cfg.CreateMap(); - cfg.CreateMap(); - }); + cfg.CreateMap(); + cfg.CreateMap() + .Include() + .Include(); + cfg.CreateMap(); + cfg.CreateMap(); + }); - var dto = config.CreateMapper().Map(new Container - { - Items = - { - new GeneralItem(), - new SpecificItem() - } - }); + var dto = config.CreateMapper().Map(new Container + { + Items = + { + new GeneralItem(), + new SpecificItem() + } + }); - dto.Items[0].ShouldBeOfType(); - dto.Items[1].ShouldBeOfType(); - } + dto.Items[0].ShouldBeOfType(); + dto.Items[1].ShouldBeOfType(); + } - [Fact] - public void item_collection_should_map_by_base_type_for_map_with_one_parameter() + [Fact] + public void item_collection_should_map_by_base_type_for_map_with_one_parameter() + { + var config = new MapperConfiguration(cfg => { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap(); - cfg.CreateMap() - .Include() - .Include(); - cfg.CreateMap(); - cfg.CreateMap(); - }); + cfg.CreateMap(); + cfg.CreateMap() + .Include() + .Include(); + cfg.CreateMap(); + cfg.CreateMap(); + }); - var dto = config.CreateMapper().Map(new Container - { - Items = - { - new GeneralItem(), - new SpecificItem() - } - }); + var dto = config.CreateMapper().Map(new Container + { + Items = + { + new GeneralItem(), + new SpecificItem() + } + }); - dto.Items[0].ShouldBeOfType(); - dto.Items[1].ShouldBeOfType(); - } + dto.Items[0].ShouldBeOfType(); + dto.Items[1].ShouldBeOfType(); } } diff --git a/src/UnitTests/MappingInheritance/IgnoreShouldBeInherited.cs b/src/UnitTests/MappingInheritance/IgnoreShouldBeInherited.cs index 832c2eef95..4a58fbe889 100644 --- a/src/UnitTests/MappingInheritance/IgnoreShouldBeInherited.cs +++ b/src/UnitTests/MappingInheritance/IgnoreShouldBeInherited.cs @@ -2,111 +2,110 @@ using Shouldly; using Xunit; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class IgnoreShouldBeInheritedRegardlessOfMapOrder : AutoMapperSpecBase { - public class IgnoreShouldBeInheritedRegardlessOfMapOrder : AutoMapperSpecBase + public class BaseDomain { - public class BaseDomain - { - } - - public class SpecificDomain : BaseDomain - { - public string SpecificProperty { get; set; } - } + } - public class Dto - { - public string SpecificProperty { get; set; } - } + public class SpecificDomain : BaseDomain + { + public string SpecificProperty { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - cfg.CreateMap() - .ForMember(d => d.SpecificProperty, m => m.Ignore()) - .Include(); - }); - - [Fact] - public void Should_map_ok() - { - var dto = Mapper.Map(new SpecificDomain { SpecificProperty = "Test" }); - dto.SpecificProperty.ShouldBeNull(); - } + public class Dto + { + public string SpecificProperty { get; set; } } - public class IgnoreShouldBeInherited : AutoMapperSpecBase + protected override MapperConfiguration CreateConfiguration() => new(cfg => { - public class BaseDomain - { - } + cfg.CreateMap(); + cfg.CreateMap() + .ForMember(d => d.SpecificProperty, m => m.Ignore()) + .Include(); + }); + + [Fact] + public void Should_map_ok() + { + var dto = Mapper.Map(new SpecificDomain { SpecificProperty = "Test" }); + dto.SpecificProperty.ShouldBeNull(); + } +} - public class SpecificDomain : BaseDomain - { - public string SpecificProperty { get; set; } - } +public class IgnoreShouldBeInherited : AutoMapperSpecBase +{ + public class BaseDomain + { + } - public class Dto - { - public string SpecificProperty { get; set; } - } + public class SpecificDomain : BaseDomain + { + public string SpecificProperty { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ForMember(d => d.SpecificProperty, m => m.Ignore()) - .Include(); - cfg.CreateMap(); - }); - - [Fact] - public void Should_map_ok() - { - var dto = Mapper.Map(new SpecificDomain { SpecificProperty = "Test" }); - dto.SpecificProperty.ShouldBeNull(); - } + public class Dto + { + public string SpecificProperty { get; set; } } - public class IgnoreShouldBeInheritedWithOpenGenerics : AutoMapperSpecBase + protected override MapperConfiguration CreateConfiguration() => new(cfg => { - public abstract class BaseUserDto - { - public TIdType Id { get; set; } - public string Name { get; set; } - } + cfg.CreateMap() + .ForMember(d => d.SpecificProperty, m => m.Ignore()) + .Include(); + cfg.CreateMap(); + }); + + [Fact] + public void Should_map_ok() + { + var dto = Mapper.Map(new SpecificDomain { SpecificProperty = "Test" }); + dto.SpecificProperty.ShouldBeNull(); + } +} - public class ConcreteUserDto : BaseUserDto - { - } +public class IgnoreShouldBeInheritedWithOpenGenerics : AutoMapperSpecBase +{ + public abstract class BaseUserDto + { + public TIdType Id { get; set; } + public string Name { get; set; } + } - public abstract class BaseUserEntity - { - public TIdType Id { get; set; } - public string Name { get; set; } - } + public class ConcreteUserDto : BaseUserDto + { + } - public class ConcreteUserEntity : BaseUserEntity - { - } + public abstract class BaseUserEntity + { + public TIdType Id { get; set; } + public string Name { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(typeof(BaseUserDto<>), typeof(BaseUserEntity<>)).ForMember("Id", opt => opt.Ignore()); - cfg.CreateMap(typeof(ConcreteUserDto), typeof(ConcreteUserEntity)).IncludeBase(typeof(BaseUserDto), typeof(BaseUserEntity)); - }); + public class ConcreteUserEntity : BaseUserEntity + { + } - [Fact] - public void Should_map_ok() + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(typeof(BaseUserDto<>), typeof(BaseUserEntity<>)).ForMember("Id", opt => opt.Ignore()); + cfg.CreateMap(typeof(ConcreteUserDto), typeof(ConcreteUserEntity)).IncludeBase(typeof(BaseUserDto), typeof(BaseUserEntity)); + }); + + [Fact] + public void Should_map_ok() + { + var user = new ConcreteUserDto { - var user = new ConcreteUserDto - { - Id = "my-id", - Name = "my-User" - }; - var userEntity = Mapper.Map(user); - userEntity.Id.ShouldBeNull(); - userEntity.Name.ShouldBe("my-User"); - } + Id = "my-id", + Name = "my-User" + }; + var userEntity = Mapper.Map(user); + userEntity.Id.ShouldBeNull(); + userEntity.Name.ShouldBe("my-User"); } } diff --git a/src/UnitTests/MappingInheritance/IgnoreShouldBeInheritedIfConventionCannotMap.cs b/src/UnitTests/MappingInheritance/IgnoreShouldBeInheritedIfConventionCannotMap.cs index cdd1ce3b03..423299e1ab 100644 --- a/src/UnitTests/MappingInheritance/IgnoreShouldBeInheritedIfConventionCannotMap.cs +++ b/src/UnitTests/MappingInheritance/IgnoreShouldBeInheritedIfConventionCannotMap.cs @@ -4,53 +4,52 @@ using System.Text; using Xunit; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class IgnoreShouldBeInheritedIfConventionCannotMap { - public class IgnoreShouldBeInheritedIfConventionCannotMap + public class BaseDomain { - public class BaseDomain - { - } + } - public class StandardDomain : BaseDomain - { - - } + public class StandardDomain : BaseDomain + { + + } - public class SpecificDomain : StandardDomain - { - } + public class SpecificDomain : StandardDomain + { + } - public class MoreSpecificDomain : SpecificDomain - { - - } + public class MoreSpecificDomain : SpecificDomain + { + + } - public class Dto - { - public string SpecificProperty { get; set; } - } + public class Dto + { + public string SpecificProperty { get; set; } + } - [Fact] - public void inhertited_ignore_should_be_overridden_passes_validation() + [Fact] + public void inhertited_ignore_should_be_overridden_passes_validation() + { + var config = new MapperConfiguration(cfg => { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap() - .ForMember(d => d.SpecificProperty, m => m.Ignore()) - .Include(); + cfg.CreateMap() + .ForMember(d => d.SpecificProperty, m => m.Ignore()) + .Include(); - cfg.CreateMap() - .Include(); + cfg.CreateMap() + .Include(); - cfg.CreateMap() - .Include(); + cfg.CreateMap() + .Include(); - cfg.CreateMap(); - }); + cfg.CreateMap(); + }); - config.AssertConfigurationIsValid(); - } + config.AssertConfigurationIsValid(); } } diff --git a/src/UnitTests/MappingInheritance/IncludeAllDerived.cs b/src/UnitTests/MappingInheritance/IncludeAllDerived.cs index 0dac73f5dc..30f6cbabc0 100644 --- a/src/UnitTests/MappingInheritance/IncludeAllDerived.cs +++ b/src/UnitTests/MappingInheritance/IncludeAllDerived.cs @@ -1,45 +1,44 @@ using Shouldly; using Xunit; -namespace AutoMapper.UnitTests.MappingInheritance +namespace AutoMapper.UnitTests.MappingInheritance; + +public class IncludeAllDerived : AutoMapperSpecBase { - public class IncludeAllDerived : AutoMapperSpecBase + public class A { - public class A - { - public int Value { get; set; } - } - public class B : A { } - public class C : B { } - public class D : A { } + public int Value { get; set; } + } + public class B : A { } + public class C : B { } + public class D : A { } - public class ADto - { - public int Value { get; set; } - } + public class ADto + { + public int Value { get; set; } + } - public class BDto : ADto { } - public class CDto : BDto { } - public class DDto : ADto { } + public class BDto : ADto { } + public class CDto : BDto { } + public class DDto : ADto { } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ForMember(d => d.Value, opt => opt.MapFrom(src => 5)) - .IncludeAllDerived(); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .ForMember(d => d.Value, opt => opt.MapFrom(src => 5)) + .IncludeAllDerived(); - cfg.CreateMap(); - cfg.CreateMap(); - cfg.CreateMap(); - }); + cfg.CreateMap(); + cfg.CreateMap(); + cfg.CreateMap(); + }); - [Fact] - public void Should_apply_configuration_to_all_derived() - { - Mapper.Map(new A {Value = 10}).Value.ShouldBe(5); - Mapper.Map(new B {Value = 10}).Value.ShouldBe(5); - Mapper.Map(new C {Value = 10}).Value.ShouldBe(5); - Mapper.Map(new D {Value = 10}).Value.ShouldBe(5); - } + [Fact] + public void Should_apply_configuration_to_all_derived() + { + Mapper.Map(new A {Value = 10}).Value.ShouldBe(5); + Mapper.Map(new B {Value = 10}).Value.ShouldBe(5); + Mapper.Map(new C {Value = 10}).Value.ShouldBe(5); + Mapper.Map(new D {Value = 10}).Value.ShouldBe(5); } } \ No newline at end of file diff --git a/src/UnitTests/MappingInheritance/IncludeBaseBug.cs b/src/UnitTests/MappingInheritance/IncludeBaseBug.cs index 24d7a182c3..71125f878b 100644 --- a/src/UnitTests/MappingInheritance/IncludeBaseBug.cs +++ b/src/UnitTests/MappingInheritance/IncludeBaseBug.cs @@ -1,173 +1,172 @@ -namespace AutoMapper.UnitTests.MappingInheritance +namespace AutoMapper.UnitTests.MappingInheritance; + +using Shouldly; +using System; +using Xunit; +public class Include : AutoMapperSpecBase { - using Shouldly; - using System; - using Xunit; - public class Include : AutoMapperSpecBase - { - public class From - { - public int Value { get; set; } - public int ChildValue { get; set; } - } + public class From + { + public int Value { get; set; } + public int ChildValue { get; set; } + } - public class Concrete - { - public int ConcreteValue { get; set; } - } + public class Concrete + { + public int ConcreteValue { get; set; } + } - public abstract class AbstractChild : Concrete - { - public int AbstractValue { get; set; } - } + public abstract class AbstractChild : Concrete + { + public int AbstractValue { get; set; } + } - public class Derivation : AbstractChild - { - public int DerivedValue { get; set; } - } + public class Derivation : AbstractChild + { + public int DerivedValue { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ForMember(d => d.ConcreteValue, o => o.MapFrom(s => s == null ? default(int) : s.ChildValue)) - .Include(); - cfg.CreateMap() - .ForMember(d => d.AbstractValue, o => o.Ignore()) - .Include(); - cfg.CreateMap() - .ForMember(d => d.DerivedValue, o => o.Ignore()); - cfg.AllowNullDestinationValues = false; - }); - [Fact] - public void Should_map_ok() - { - var dest = Mapper.Map(null, typeof(From), typeof(Concrete)); - dest.ShouldBeOfType(); - ReferenceEquals(dest.GetType(), typeof(Concrete)).ShouldBeTrue(); - } - } - public class BaseNotMatching : AutoMapperSpecBase - { - public class From - { - public int Value { get; set; } - public int ChildValue { get; set; } - } - public class FromDerived : From - { - public int AbstractValue { get; set; } - } - public class Concrete - { - public int ConcreteValue { get; set; } - } - public abstract class AbstractChild : Concrete - { - public int AbstractValue { get; set; } - } - public class Derivation : AbstractChild - { - public int DerivedValue { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ForMember(d => d.ConcreteValue, o => o.MapFrom(s => s == null ? default(int) : s.ChildValue)) - .Include(); - cfg.CreateMap(MemberList.None) - .Include(); - cfg.CreateMap() - .ForMember(d => d.DerivedValue, o => o.Ignore()); - }); - [Fact] - public void Derived_matches() - { - var dest = Mapper.Map(new FromDerived { AbstractValue = 42 }); - dest.AbstractValue.ShouldBe(42); - } - } - public class BaseMatchingDifferentType : AutoMapperSpecBase - { - public class From - { - public int Value { get; set; } - public int ChildValue { get; set; } - public DateTime AbstractValue { get; set; } - } - public class FromDerived : From - { - public new int AbstractValue { get; set; } - } - public class Concrete - { - public int ConcreteValue { get; set; } - } - public abstract class AbstractChild : Concrete - { - public int AbstractValue { get; set; } - } - public class Derivation : AbstractChild - { - public int DerivedValue { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ForMember(d => d.ConcreteValue, o => o.MapFrom(s => s == null ? default(int) : s.ChildValue)) - .Include(); - cfg.CreateMap(MemberList.None) - .Include(); - cfg.CreateMap() - .ForMember(d => d.DerivedValue, o => o.Ignore()); - }); - [Fact] - public void Derived_matches() - { - var dest = Mapper.Map(new FromDerived { AbstractValue = 42 }); - dest.AbstractValue.ShouldBe(42); - } - } - public class IgnoreBaseMatching : AutoMapperSpecBase - { - public class From - { - public int Value { get; set; } - public int ChildValue { get; set; } - public int AbstractValue { get; set; } - } - public class FromDerived : From - { - } - public class Concrete - { - public int ConcreteValue { get; set; } - } - public abstract class AbstractChild : Concrete - { - public int AbstractValue { get; set; } - } - public class Derivation : AbstractChild - { - public int DerivedValue { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ForMember(d => d.ConcreteValue, o => o.MapFrom(s => s == null ? default(int) : s.ChildValue)) - .Include(); - cfg.CreateMap(MemberList.None) - .Include(); - cfg.CreateMap() - .ForMember(d => d.AbstractValue, o => o.Ignore()) - .ForMember(d => d.DerivedValue, o => o.Ignore()); - }); - [Fact] - public void Derived_ignores() - { - var dest = Mapper.Map(new FromDerived { AbstractValue = 42 }); - dest.AbstractValue.ShouldBe(0); - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .ForMember(d => d.ConcreteValue, o => o.MapFrom(s => s == null ? default(int) : s.ChildValue)) + .Include(); + cfg.CreateMap() + .ForMember(d => d.AbstractValue, o => o.Ignore()) + .Include(); + cfg.CreateMap() + .ForMember(d => d.DerivedValue, o => o.Ignore()); + cfg.AllowNullDestinationValues = false; + }); + [Fact] + public void Should_map_ok() + { + var dest = Mapper.Map(null, typeof(From), typeof(Concrete)); + dest.ShouldBeOfType(); + ReferenceEquals(dest.GetType(), typeof(Concrete)).ShouldBeTrue(); + } +} +public class BaseNotMatching : AutoMapperSpecBase +{ + public class From + { + public int Value { get; set; } + public int ChildValue { get; set; } + } + public class FromDerived : From + { + public int AbstractValue { get; set; } + } + public class Concrete + { + public int ConcreteValue { get; set; } + } + public abstract class AbstractChild : Concrete + { + public int AbstractValue { get; set; } + } + public class Derivation : AbstractChild + { + public int DerivedValue { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .ForMember(d => d.ConcreteValue, o => o.MapFrom(s => s == null ? default(int) : s.ChildValue)) + .Include(); + cfg.CreateMap(MemberList.None) + .Include(); + cfg.CreateMap() + .ForMember(d => d.DerivedValue, o => o.Ignore()); + }); + [Fact] + public void Derived_matches() + { + var dest = Mapper.Map(new FromDerived { AbstractValue = 42 }); + dest.AbstractValue.ShouldBe(42); + } +} +public class BaseMatchingDifferentType : AutoMapperSpecBase +{ + public class From + { + public int Value { get; set; } + public int ChildValue { get; set; } + public DateTime AbstractValue { get; set; } + } + public class FromDerived : From + { + public new int AbstractValue { get; set; } + } + public class Concrete + { + public int ConcreteValue { get; set; } + } + public abstract class AbstractChild : Concrete + { + public int AbstractValue { get; set; } + } + public class Derivation : AbstractChild + { + public int DerivedValue { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .ForMember(d => d.ConcreteValue, o => o.MapFrom(s => s == null ? default(int) : s.ChildValue)) + .Include(); + cfg.CreateMap(MemberList.None) + .Include(); + cfg.CreateMap() + .ForMember(d => d.DerivedValue, o => o.Ignore()); + }); + [Fact] + public void Derived_matches() + { + var dest = Mapper.Map(new FromDerived { AbstractValue = 42 }); + dest.AbstractValue.ShouldBe(42); + } +} +public class IgnoreBaseMatching : AutoMapperSpecBase +{ + public class From + { + public int Value { get; set; } + public int ChildValue { get; set; } + public int AbstractValue { get; set; } + } + public class FromDerived : From + { + } + public class Concrete + { + public int ConcreteValue { get; set; } + } + public abstract class AbstractChild : Concrete + { + public int AbstractValue { get; set; } + } + public class Derivation : AbstractChild + { + public int DerivedValue { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .ForMember(d => d.ConcreteValue, o => o.MapFrom(s => s == null ? default(int) : s.ChildValue)) + .Include(); + cfg.CreateMap(MemberList.None) + .Include(); + cfg.CreateMap() + .ForMember(d => d.AbstractValue, o => o.Ignore()) + .ForMember(d => d.DerivedValue, o => o.Ignore()); + }); + [Fact] + public void Derived_ignores() + { + var dest = Mapper.Map(new FromDerived { AbstractValue = 42 }); + dest.AbstractValue.ShouldBe(0); } } \ No newline at end of file diff --git a/src/UnitTests/MappingInheritance/IncludeBaseShouldNotCreateMaps.cs b/src/UnitTests/MappingInheritance/IncludeBaseShouldNotCreateMaps.cs index 6747fe80cd..1fc074d9e8 100644 --- a/src/UnitTests/MappingInheritance/IncludeBaseShouldNotCreateMaps.cs +++ b/src/UnitTests/MappingInheritance/IncludeBaseShouldNotCreateMaps.cs @@ -1,36 +1,35 @@ using System; using Xunit; -namespace AutoMapper.UnitTests.MappingInheritance +namespace AutoMapper.UnitTests.MappingInheritance; + +public class IncludeBaseShouldNotCreateMaps : AutoMapperSpecBase { - public class IncludeBaseShouldNotCreateMaps : AutoMapperSpecBase + public abstract class BaseBaseSource { } + public class BaseSource : BaseBaseSource { - public abstract class BaseBaseSource { } - public class BaseSource : BaseBaseSource - { - public string Foo { get; set; } - } - public class Source : BaseSource { } + public string Foo { get; set; } + } + public class Source : BaseSource { } - public abstract class BaseBaseDest - { - public string Foo { get; set; } - } - public class BaseDest : BaseBaseDest { } - public class Dest : BaseDest { } + public abstract class BaseBaseDest + { + public string Foo { get; set; } + } + public class BaseDest : BaseBaseDest { } + public class Dest : BaseDest { } - public class TestProfile : Profile + public class TestProfile : Profile + { + public TestProfile() { - public TestProfile() - { - CreateMap(); - CreateMap() - .IncludeBase(); - } + CreateMap(); + CreateMap() + .IncludeBase(); } - - protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.AddProfile()); - [Fact] - public void Validate() => AssertConfigurationIsValid(); } + + protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.AddProfile()); + [Fact] + public void Validate() => AssertConfigurationIsValid(); } \ No newline at end of file diff --git a/src/UnitTests/MappingInheritance/IncludeBaseShouldValidateTypes.cs b/src/UnitTests/MappingInheritance/IncludeBaseShouldValidateTypes.cs index 8369935474..353a6a6f48 100644 --- a/src/UnitTests/MappingInheritance/IncludeBaseShouldValidateTypes.cs +++ b/src/UnitTests/MappingInheritance/IncludeBaseShouldValidateTypes.cs @@ -2,20 +2,19 @@ using System; using Xunit; -namespace AutoMapper.UnitTests +namespace AutoMapper.UnitTests; + +public class IncludeBaseShouldValidateTypes { - public class IncludeBaseShouldValidateTypes + [Fact] + public void Should_throw() { - [Fact] - public void Should_throw() + new Action(() => + { + var c = new MapperConfiguration(cfg => cfg.CreateMap().IncludeBase()); + }).ShouldThrowException(ex => { - new Action(() => - { - var c = new MapperConfiguration(cfg => cfg.CreateMap().IncludeBase()); - }).ShouldThrowException(ex => - { - ex.Message.ShouldStartWith($"{typeof(string)} is not derived from {typeof(int)}."); - }); - } + ex.Message.ShouldStartWith($"{typeof(string)} is not derived from {typeof(int)}."); + }); } } \ No newline at end of file diff --git a/src/UnitTests/MappingInheritance/IncludeBaseWithNonGenericUsage.cs b/src/UnitTests/MappingInheritance/IncludeBaseWithNonGenericUsage.cs index 3d3550d868..091c431033 100644 --- a/src/UnitTests/MappingInheritance/IncludeBaseWithNonGenericUsage.cs +++ b/src/UnitTests/MappingInheritance/IncludeBaseWithNonGenericUsage.cs @@ -2,68 +2,67 @@ using Shouldly; using Xunit; -namespace AutoMapper.UnitTests.MappingInheritance -{ - public class IncludeBaseWithNonGenericUsage : AutoMapperSpecBase - { - class Source : SourceBase - { } +namespace AutoMapper.UnitTests.MappingInheritance; - class Destination : DestinationBase - { } - - abstract class SourceBase - { - public T Id; - public string Timestamp; - } +public class IncludeBaseWithNonGenericUsage : AutoMapperSpecBase +{ + class Source : SourceBase + { } - abstract class DestinationBase - { - public T Id; - public string Time; - } + class Destination : DestinationBase + { } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - // It does not matter if generic type is or <>, result is the same. - cfg.CreateMap(typeof(SourceBase), typeof(DestinationBase)) - .ForMember("Time", mo => mo.MapFrom("Timestamp")); - cfg.CreateMap(typeof(Source), typeof(Destination)) - .IncludeBase(typeof(SourceBase), typeof(DestinationBase)); - }); - [Fact] - public void Validate() => AssertConfigurationIsValid(); + abstract class SourceBase + { + public T Id; + public string Timestamp; } - public class IncludeBaseWithGenericUsage : AutoMapperSpecBase + + abstract class DestinationBase { - class Source : SourceBase - { } + public T Id; + public string Time; + } - class Destination : DestinationBase - { } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + // It does not matter if generic type is or <>, result is the same. + cfg.CreateMap(typeof(SourceBase), typeof(DestinationBase)) + .ForMember("Time", mo => mo.MapFrom("Timestamp")); + cfg.CreateMap(typeof(Source), typeof(Destination)) + .IncludeBase(typeof(SourceBase), typeof(DestinationBase)); + }); + [Fact] + public void Validate() => AssertConfigurationIsValid(); +} +public class IncludeBaseWithGenericUsage : AutoMapperSpecBase +{ + class Source : SourceBase + { } - abstract class SourceBase - { - public T Id; - public string Timestamp; - } + class Destination : DestinationBase + { } - abstract class DestinationBase - { - public T Id; - public string Time; - } + abstract class SourceBase + { + public T Id; + public string Timestamp; + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - // It does not matter if generic type is or <>, result is the same. - cfg.CreateMap, DestinationBase>() - .ForMember("Time", mo => mo.MapFrom("Timestamp")); - cfg.CreateMap() - .IncludeBase, DestinationBase>(); - }); - [Fact] - public void Validate() => AssertConfigurationIsValid(); + abstract class DestinationBase + { + public T Id; + public string Time; } + + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + // It does not matter if generic type is or <>, result is the same. + cfg.CreateMap, DestinationBase>() + .ForMember("Time", mo => mo.MapFrom("Timestamp")); + cfg.CreateMap() + .IncludeBase, DestinationBase>(); + }); + [Fact] + public void Validate() => AssertConfigurationIsValid(); } \ No newline at end of file diff --git a/src/UnitTests/MappingInheritance/IncludedBaseMappingShouldInheritBaseMappings.cs b/src/UnitTests/MappingInheritance/IncludedBaseMappingShouldInheritBaseMappings.cs index 863fd9907f..c9fc825dd8 100644 --- a/src/UnitTests/MappingInheritance/IncludedBaseMappingShouldInheritBaseMappings.cs +++ b/src/UnitTests/MappingInheritance/IncludedBaseMappingShouldInheritBaseMappings.cs @@ -1,352 +1,351 @@ using Shouldly; using Xunit; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +using AutoMapper; +using CustomMapping; + +public class IncludedMappingShouldInheritBaseMappings : NonValidatingSpecBase { - using AutoMapper; - using CustomMapping; - public class IncludedMappingShouldInheritBaseMappings : NonValidatingSpecBase + public class ModelObject { + public string DifferentBaseString { get; set; } + } - public class ModelObject - { - public string DifferentBaseString { get; set; } - } + public class ModelSubObject : ModelObject + { + public string SubString { get; set; } + } + + public class DtoObject + { + public string BaseString { get; set; } + } + + public class DtoSubObject : DtoObject + { + public string SubString { get; set; } + } - public class ModelSubObject : ModelObject + public class OtherDto + { + public string SubString { get; set; } + } + + [Fact] + public void included_mapping_should_inherit_base_mappings_should_not_throw() + { + var config = new MapperConfiguration(cfg => { - public string SubString { get; set; } - } + cfg.CreateMap() + .ForMember(d => d.BaseString, m => m.MapFrom(s => s.DifferentBaseString)) + .Include(); + cfg.CreateMap(); + }); + config.AssertConfigurationIsValid(); + } - public class DtoObject + [Fact] + public void included_mapping_should_inherit_base_ignore_mappings_should_not_throw() + { + var config = new MapperConfiguration(cfg => { - public string BaseString { get; set; } - } + cfg.CreateMap() + .ForMember(d => d.BaseString, m => m.Ignore()) + .Include(); + cfg.CreateMap(); + }); + config.AssertConfigurationIsValid(); + } - public class DtoSubObject : DtoObject + [Fact] + public void more_specific_map_should_override_base_ignore_passes_validation() + { + var config = new MapperConfiguration(cfg => { - public string SubString { get; set; } - } + cfg.CreateMap() + .ForMember(d => d.BaseString, m => m.Ignore()) + .Include(); + cfg.CreateMap() + .ForMember(d => d.BaseString, m => m.MapFrom(s => s.DifferentBaseString)); + }); + config.AssertConfigurationIsValid(); + } - public class OtherDto + [Fact] + public void more_specific_map_should_override_base_ignore_with_one_parameter() + { + var config = new MapperConfiguration(cfg => { - public string SubString { get; set; } - } + cfg.CreateMap() + .ForMember(d => d.BaseString, m => m.Ignore()) + .Include(); + cfg.CreateMap() + .ForMember(d => d.BaseString, m => m.MapFrom(s => s.DifferentBaseString)); + }); + + var mapper = config.CreateMapper(); - [Fact] - public void included_mapping_should_inherit_base_mappings_should_not_throw() + var dto = mapper.Map(new ModelSubObject { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap() - .ForMember(d => d.BaseString, m => m.MapFrom(s => s.DifferentBaseString)) - .Include(); - cfg.CreateMap(); - }); - config.AssertConfigurationIsValid(); - } - - [Fact] - public void included_mapping_should_inherit_base_ignore_mappings_should_not_throw() + DifferentBaseString = "123", + SubString = "456" + }); + + "123".ShouldBe(dto.BaseString); + "456".ShouldBe(dto.SubString); + } + + [Fact] + public void more_specific_map_should_override_base_ignore() + { + var config = new MapperConfiguration(cfg => { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap() - .ForMember(d => d.BaseString, m => m.Ignore()) - .Include(); - cfg.CreateMap(); - }); - config.AssertConfigurationIsValid(); - } - - [Fact] - public void more_specific_map_should_override_base_ignore_passes_validation() + cfg.CreateMap() + .ForMember(d => d.BaseString, m => m.Ignore()) + .Include(); + cfg.CreateMap() + .ForMember(d => d.BaseString, m => m.MapFrom(s => s.DifferentBaseString)); + }); + var mapper = config.CreateMapper(); + var dto = mapper.Map(new ModelSubObject { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap() - .ForMember(d => d.BaseString, m => m.Ignore()) - .Include(); - cfg.CreateMap() - .ForMember(d => d.BaseString, m => m.MapFrom(s => s.DifferentBaseString)); - }); - config.AssertConfigurationIsValid(); - } - - [Fact] - public void more_specific_map_should_override_base_ignore_with_one_parameter() + DifferentBaseString = "123", + SubString = "456" + }); + + "123".ShouldBe(dto.BaseString); + "456".ShouldBe(dto.SubString); + } + + [Fact] + public void more_specific_map_should_override_base_mapping_passes_validation() + { + var config = new MapperConfiguration(cfg => { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap() - .ForMember(d => d.BaseString, m => m.Ignore()) - .Include(); - cfg.CreateMap() - .ForMember(d => d.BaseString, m => m.MapFrom(s => s.DifferentBaseString)); - }); - - var mapper = config.CreateMapper(); - - var dto = mapper.Map(new ModelSubObject - { - DifferentBaseString = "123", - SubString = "456" - }); - - "123".ShouldBe(dto.BaseString); - "456".ShouldBe(dto.SubString); - } - - [Fact] - public void more_specific_map_should_override_base_ignore() + cfg.CreateMap() + .ForMember(d => d.BaseString, m => m.MapFrom(s => s.DifferentBaseString)) + .Include(); + cfg.CreateMap() + .ForMember(d => d.BaseString, m => m.MapFrom(src => "789")); + }); + config.AssertConfigurationIsValid(); + } + [Fact] + public void more_specific_map_should_override_base_mapping_with_one_parameter() + { + var config = new MapperConfiguration(cfg => { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap() - .ForMember(d => d.BaseString, m => m.Ignore()) - .Include(); - cfg.CreateMap() - .ForMember(d => d.BaseString, m => m.MapFrom(s => s.DifferentBaseString)); - }); - var mapper = config.CreateMapper(); - var dto = mapper.Map(new ModelSubObject - { - DifferentBaseString = "123", - SubString = "456" - }); - - "123".ShouldBe(dto.BaseString); - "456".ShouldBe(dto.SubString); - } - - [Fact] - public void more_specific_map_should_override_base_mapping_passes_validation() + cfg.CreateMap() + .ForMember(d => d.BaseString, m => m.MapFrom(s => s.DifferentBaseString)) + .Include(); + cfg.CreateMap() + .ForMember(d => d.BaseString, m => m.MapFrom(src => "789")); + }); + + var mapper = config.CreateMapper(); + var dto = mapper.Map(new ModelSubObject + { + DifferentBaseString = "123", + SubString = "456" + }); + + "789".ShouldBe(dto.BaseString); + "456".ShouldBe(dto.SubString); + } + + [Fact] + public void more_specific_map_should_override_base_mapping() + { + var config = new MapperConfiguration(cfg => { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap() - .ForMember(d => d.BaseString, m => m.MapFrom(s => s.DifferentBaseString)) - .Include(); - cfg.CreateMap() - .ForMember(d => d.BaseString, m => m.MapFrom(src => "789")); - }); - config.AssertConfigurationIsValid(); - } - [Fact] - public void more_specific_map_should_override_base_mapping_with_one_parameter() + cfg.CreateMap() + .ForMember(d => d.BaseString, m => m.MapFrom(s => s.DifferentBaseString)) + .Include(); + cfg.CreateMap() + .ForMember(d => d.BaseString, m => m.MapFrom(src => "789")); + }); + var mapper = config.CreateMapper(); + var dto = mapper.Map(new ModelSubObject + { + DifferentBaseString = "123", + SubString = "456" + }); + + "789".ShouldBe(dto.BaseString); + "456".ShouldBe(dto.SubString); + } + + [Fact] + public void included_mapping_should_not_inherit_base_mappings_for_other_with_one_parameter() + { + var config = new MapperConfiguration(cfg => { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap() - .ForMember(d => d.BaseString, m => m.MapFrom(s => s.DifferentBaseString)) - .Include(); - cfg.CreateMap() - .ForMember(d => d.BaseString, m => m.MapFrom(src => "789")); - }); - - var mapper = config.CreateMapper(); - var dto = mapper.Map(new ModelSubObject - { - DifferentBaseString = "123", - SubString = "456" - }); - - "789".ShouldBe(dto.BaseString); - "456".ShouldBe(dto.SubString); - } - - [Fact] - public void more_specific_map_should_override_base_mapping() + cfg.CreateMap() + .ForMember(d => d.BaseString, m => m.MapFrom(s => s.DifferentBaseString)) + .Include(); + + cfg.CreateMap(); + cfg.CreateMap(); + }); + + var mapper = config.CreateMapper(); + var dto = mapper.Map(new ModelSubObject { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap() - .ForMember(d => d.BaseString, m => m.MapFrom(s => s.DifferentBaseString)) - .Include(); - cfg.CreateMap() - .ForMember(d => d.BaseString, m => m.MapFrom(src => "789")); - }); - var mapper = config.CreateMapper(); - var dto = mapper.Map(new ModelSubObject - { - DifferentBaseString = "123", - SubString = "456" - }); - - "789".ShouldBe(dto.BaseString); - "456".ShouldBe(dto.SubString); - } - - [Fact] - public void included_mapping_should_not_inherit_base_mappings_for_other_with_one_parameter() + DifferentBaseString = "123", + SubString = "456" + }); + + "456".ShouldBe(dto.SubString); + } + + [Fact] + public void included_mapping_should_not_inherit_base_mappings_for_other() + { + var config = new MapperConfiguration(cfg => { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap() - .ForMember(d => d.BaseString, m => m.MapFrom(s => s.DifferentBaseString)) - .Include(); - - cfg.CreateMap(); - cfg.CreateMap(); - }); - - var mapper = config.CreateMapper(); - var dto = mapper.Map(new ModelSubObject - { - DifferentBaseString = "123", - SubString = "456" - }); - - "456".ShouldBe(dto.SubString); - } - - [Fact] - public void included_mapping_should_not_inherit_base_mappings_for_other() + cfg.CreateMap() + .ForMember(d => d.BaseString, m => m.MapFrom(s => s.DifferentBaseString)) + .Include(); + + cfg.CreateMap(); + cfg.CreateMap(); + }); + var mapper = config.CreateMapper(); + var dto = mapper.Map(new ModelSubObject { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap() - .ForMember(d => d.BaseString, m => m.MapFrom(s => s.DifferentBaseString)) - .Include(); - - cfg.CreateMap(); - cfg.CreateMap(); - }); - var mapper = config.CreateMapper(); - var dto = mapper.Map(new ModelSubObject - { - DifferentBaseString = "123", - SubString = "456" - }); - - "456".ShouldBe(dto.SubString); - } - - [Fact] - public void included_mapping_should_not_inherit_base_mappings_for_other_should_not_throw() + DifferentBaseString = "123", + SubString = "456" + }); + + "456".ShouldBe(dto.SubString); + } + + [Fact] + public void included_mapping_should_not_inherit_base_mappings_for_other_should_not_throw() + { + var config = new MapperConfiguration(cfg => { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap() - .ForMember(d => d.BaseString, m => m.MapFrom(s => s.DifferentBaseString)) - .Include(); - - cfg.CreateMap(); - cfg.CreateMap(); - }); - config.AssertConfigurationIsValid(); - } - [Fact] - public void include_should_allow_automapper_to_select_more_specific_included_type_with_one_parameter() + cfg.CreateMap() + .ForMember(d => d.BaseString, m => m.MapFrom(s => s.DifferentBaseString)) + .Include(); + + cfg.CreateMap(); + cfg.CreateMap(); + }); + config.AssertConfigurationIsValid(); + } + [Fact] + public void include_should_allow_automapper_to_select_more_specific_included_type_with_one_parameter() + { + var config = new MapperConfiguration(cfg => { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap() - .ForMember(d => d.BaseString, m => m.MapFrom(s => s.DifferentBaseString)) - .Include(); - - cfg.CreateMap(); - }); - var mapper = config.CreateMapper(); - var dto = mapper.Map(new ModelSubObject - { - DifferentBaseString = "123", - SubString = "456" - }); - - dto.ShouldBeOfType(); - } - - [Fact] - public void include_should_allow_automapper_to_select_more_specific_included_type() + cfg.CreateMap() + .ForMember(d => d.BaseString, m => m.MapFrom(s => s.DifferentBaseString)) + .Include(); + + cfg.CreateMap(); + }); + var mapper = config.CreateMapper(); + var dto = mapper.Map(new ModelSubObject { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap() - .ForMember(d => d.BaseString, m => m.MapFrom(s => s.DifferentBaseString)) - .Include(); - - cfg.CreateMap(); - }); - var mapper = config.CreateMapper(); - var dto = mapper.Map(new ModelSubObject - { - DifferentBaseString = "123", - SubString = "456" - }); - - dto.ShouldBeOfType(); - } - - [Fact] - public void include_should_apply_condition() + DifferentBaseString = "123", + SubString = "456" + }); + + dto.ShouldBeOfType(); + } + + [Fact] + public void include_should_allow_automapper_to_select_more_specific_included_type() + { + var config = new MapperConfiguration(cfg => { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap() - .ForMember(d => d.BaseString, m => - { - m.Condition(src => !string.IsNullOrWhiteSpace(src.DifferentBaseString)); - m.MapFrom(s => s.DifferentBaseString); - }) - .Include(); - - cfg.CreateMap(); - }); - var dest = new DtoSubObject - { - BaseString = "12345" - }; - var mapper = config.CreateMapper(); - mapper.Map(new ModelSubObject - { - DifferentBaseString = "", - }, dest); - - dest.BaseString.ShouldBe("12345"); - } - - [Fact] - public void include_should_apply_null_substitute() + cfg.CreateMap() + .ForMember(d => d.BaseString, m => m.MapFrom(s => s.DifferentBaseString)) + .Include(); + + cfg.CreateMap(); + }); + var mapper = config.CreateMapper(); + var dto = mapper.Map(new ModelSubObject { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap() - .ForMember(d => d.BaseString, m => - { - m.MapFrom(s => s.DifferentBaseString); - m.NullSubstitute("12345"); - }) - .Include(); - - cfg.CreateMap(); - }); - var mapper = config.CreateMapper(); - var dest = mapper.Map(new ModelSubObject()); - - dest.BaseString.ShouldBe("12345"); - } + DifferentBaseString = "123", + SubString = "456" + }); + + dto.ShouldBeOfType(); } - public class OverrideDifferentMapFrom : AutoMapperSpecBase + [Fact] + public void include_should_apply_condition() { - class Source + var config = new MapperConfiguration(cfg => { - } - class Destination + cfg.CreateMap() + .ForMember(d => d.BaseString, m => + { + m.Condition(src => !string.IsNullOrWhiteSpace(src.DifferentBaseString)); + m.MapFrom(s => s.DifferentBaseString); + }) + .Include(); + + cfg.CreateMap(); + }); + var dest = new DtoSubObject { - public int Value { get; set; } - } - class DestinationDerived : Destination + BaseString = "12345" + }; + var mapper = config.CreateMapper(); + mapper.Map(new ModelSubObject { - } - protected override MapperConfiguration CreateConfiguration() => new(cfg=> + DifferentBaseString = "", + }, dest); + + dest.BaseString.ShouldBe("12345"); + } + + [Fact] + public void include_should_apply_null_substitute() + { + var config = new MapperConfiguration(cfg => { - cfg.CreateMap().ForMember(d => d.Value, o => o.MapFrom((s, d) => 1)); - cfg.CreateMap().IncludeBase().ForMember(d => d.Value, o => o.MapFrom(s => 2)); + cfg.CreateMap() + .ForMember(d => d.BaseString, m => + { + m.MapFrom(s => s.DifferentBaseString); + m.NullSubstitute("12345"); + }) + .Include(); + + cfg.CreateMap(); }); - [Fact] - public void Should_use_derived_mapfrom() => Map(new Source()).Value.ShouldBe(2); + var mapper = config.CreateMapper(); + var dest = mapper.Map(new ModelSubObject()); + + dest.BaseString.ShouldBe("12345"); + } +} + +public class OverrideDifferentMapFrom : AutoMapperSpecBase +{ + class Source + { } + class Destination + { + public int Value { get; set; } + } + class DestinationDerived : Destination + { + } + protected override MapperConfiguration CreateConfiguration() => new(cfg=> + { + cfg.CreateMap().ForMember(d => d.Value, o => o.MapFrom((s, d) => 1)); + cfg.CreateMap().IncludeBase().ForMember(d => d.Value, o => o.MapFrom(s => 2)); + }); + [Fact] + public void Should_use_derived_mapfrom() => Map(new Source()).Value.ShouldBe(2); } diff --git a/src/UnitTests/MappingInheritance/IncludedMappingShouldInheritBaseMappings.cs b/src/UnitTests/MappingInheritance/IncludedMappingShouldInheritBaseMappings.cs index f889b14fbd..972ee0c0f1 100644 --- a/src/UnitTests/MappingInheritance/IncludedMappingShouldInheritBaseMappings.cs +++ b/src/UnitTests/MappingInheritance/IncludedMappingShouldInheritBaseMappings.cs @@ -3,365 +3,364 @@ using System.Linq; using Xunit; -namespace AutoMapper.UnitTests +namespace AutoMapper.UnitTests; + +public class ReadonlyCollectionPropertiesOverride : AutoMapperSpecBase { - public class ReadonlyCollectionPropertiesOverride : AutoMapperSpecBase + protected override MapperConfiguration CreateConfiguration() => new(cfg => { - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .Include() - .ForMember(d=>d.CodeList, o => o.UseDestinationValue()); - cfg.CreateMap().ForMember(d=>d.CodeList, o => o.DoNotUseDestinationValue()); - }); - public class SourceBase - { - public ICollection CodeList { get; } = new List(); - } - public class Source : SourceBase - { - } - public class DestinationBase - { - public ICollection CodeList { get; set; } = new HashSet(); - } - public class Destination : DestinationBase - { - } - [Fact] - public void ShouldMapOk() => Mapper.Map(new Source { CodeList = { "DMItemCode1" } }).CodeList.ShouldNotBeOfType>(); + cfg.CreateMap() + .Include() + .ForMember(d=>d.CodeList, o => o.UseDestinationValue()); + cfg.CreateMap().ForMember(d=>d.CodeList, o => o.DoNotUseDestinationValue()); + }); + public class SourceBase + { + public ICollection CodeList { get; } = new List(); } - public class ReadonlyCollectionProperties : AutoMapperSpecBase + public class Source : SourceBase { - protected override MapperConfiguration CreateConfiguration() => new(cfg=> - { - cfg.CreateMap() - .ForMember(d => d.CodeList, o => o.MapFrom(s => s.CodeList)) - .ForMember(d => d.KeyValuesOtherName, o => o.MapFrom(s => new[] { new KeyValueModel { Key = "key1", Value = "value1" } })) - .Include(); - cfg.CreateMap(); - }); - public class DomainModelBase - { - public ICollection CodeList { get; } = new List(); - } - public class DomainModel : DomainModelBase - { - } - public class ModelBase - { - public ICollection KeyValuesOtherName { get; } = new List(); - public ICollection CodeList { get; } = new List(); - } - public class Model : ModelBase - { - } - public class KeyValueModel - { - public string Key { get; set; } - public string Value { get; set; } - } - [Fact] - public void ShouldMapOk() - { - var domainModel = new DomainModel { CodeList = { "DMItemCode1" } }; - var result = Mapper.Map(domainModel); - result.CodeList.First().ShouldBe("DMItemCode1"); - var keyValue = result.KeyValuesOtherName.First(); - keyValue.Key.ShouldBe("key1"); - keyValue.Value.ShouldBe("value1"); - } } - public class IncludedBaseMappingShouldInheritBaseMappings : NonValidatingSpecBase + public class DestinationBase { - public class ModelObject - { - public string DifferentBaseString { get; set; } - } + public ICollection CodeList { get; set; } = new HashSet(); + } + public class Destination : DestinationBase + { + } + [Fact] + public void ShouldMapOk() => Mapper.Map(new Source { CodeList = { "DMItemCode1" } }).CodeList.ShouldNotBeOfType>(); +} +public class ReadonlyCollectionProperties : AutoMapperSpecBase +{ + protected override MapperConfiguration CreateConfiguration() => new(cfg=> + { + cfg.CreateMap() + .ForMember(d => d.CodeList, o => o.MapFrom(s => s.CodeList)) + .ForMember(d => d.KeyValuesOtherName, o => o.MapFrom(s => new[] { new KeyValueModel { Key = "key1", Value = "value1" } })) + .Include(); + cfg.CreateMap(); + }); + public class DomainModelBase + { + public ICollection CodeList { get; } = new List(); + } + public class DomainModel : DomainModelBase + { + } + public class ModelBase + { + public ICollection KeyValuesOtherName { get; } = new List(); + public ICollection CodeList { get; } = new List(); + } + public class Model : ModelBase + { + } + public class KeyValueModel + { + public string Key { get; set; } + public string Value { get; set; } + } + [Fact] + public void ShouldMapOk() + { + var domainModel = new DomainModel { CodeList = { "DMItemCode1" } }; + var result = Mapper.Map(domainModel); + result.CodeList.First().ShouldBe("DMItemCode1"); + var keyValue = result.KeyValuesOtherName.First(); + keyValue.Key.ShouldBe("key1"); + keyValue.Value.ShouldBe("value1"); + } +} +public class IncludedBaseMappingShouldInheritBaseMappings : NonValidatingSpecBase +{ + public class ModelObject + { + public string DifferentBaseString { get; set; } + } - public class ModelSubObject : ModelObject - { - public string SubString { get; set; } - } + public class ModelSubObject : ModelObject + { + public string SubString { get; set; } + } - public class DtoObject - { - public string BaseString { get; set; } - } + public class DtoObject + { + public string BaseString { get; set; } + } - public class DtoSubObject : DtoObject - { - public string SubString { get; set; } - } + public class DtoSubObject : DtoObject + { + public string SubString { get; set; } + } - public class OtherDto - { - public string SubString { get; set; } - } + public class OtherDto + { + public string SubString { get; set; } + } - [Fact] - public void included_mapping_should_inherit_base_mappings_should_not_throw() + [Fact] + public void included_mapping_should_inherit_base_mappings_should_not_throw() + { + var config = new MapperConfiguration(cfg => { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap() - .ForMember(d => d.BaseString, m => m.MapFrom(s => s.DifferentBaseString)) - ; - cfg.CreateMap() - .IncludeBase(); - }); + cfg.CreateMap() + .ForMember(d => d.BaseString, m => m.MapFrom(s => s.DifferentBaseString)) + ; + cfg.CreateMap() + .IncludeBase(); + }); - config.AssertConfigurationIsValid(); - } - [Fact] - public void included_mapping_should_not_care_about_order() + config.AssertConfigurationIsValid(); + } + [Fact] + public void included_mapping_should_not_care_about_order() + { + var config = new MapperConfiguration(cfg => { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap() - .IncludeBase(); - cfg.CreateMap() - .ForMember(d => d.BaseString, m => m.MapFrom(s => s.DifferentBaseString)) - ; - }); + cfg.CreateMap() + .IncludeBase(); + cfg.CreateMap() + .ForMember(d => d.BaseString, m => m.MapFrom(s => s.DifferentBaseString)) + ; + }); - config.AssertConfigurationIsValid(); - } + config.AssertConfigurationIsValid(); + } - [Fact] - public void included_mapping_should_inherit_base_ignore_mappings_should_not_throw() + [Fact] + public void included_mapping_should_inherit_base_ignore_mappings_should_not_throw() + { + var config = new MapperConfiguration(cfg => { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap() - .ForMember(d => d.BaseString, m => m.Ignore()) - ; - cfg.CreateMap() - .IncludeBase() - ; - }); - config.AssertConfigurationIsValid(); - } + cfg.CreateMap() + .ForMember(d => d.BaseString, m => m.Ignore()) + ; + cfg.CreateMap() + .IncludeBase() + ; + }); + config.AssertConfigurationIsValid(); + } - [Fact] - public void more_specific_map_should_override_base_ignore_passes_validation() + [Fact] + public void more_specific_map_should_override_base_ignore_passes_validation() + { + var config = new MapperConfiguration(cfg => { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap() - .ForMember(d => d.BaseString, m => m.Ignore()) - ; - cfg.CreateMap() - .IncludeBase() - .ForMember(d => d.BaseString, m => m.MapFrom(s => s.DifferentBaseString)) - ; - }); - config.AssertConfigurationIsValid(); - } + cfg.CreateMap() + .ForMember(d => d.BaseString, m => m.Ignore()) + ; + cfg.CreateMap() + .IncludeBase() + .ForMember(d => d.BaseString, m => m.MapFrom(s => s.DifferentBaseString)) + ; + }); + config.AssertConfigurationIsValid(); + } - [Fact] - public void more_specific_map_should_override_base_ignore_with_one_parameter() + [Fact] + public void more_specific_map_should_override_base_ignore_with_one_parameter() + { + var config = new MapperConfiguration(cfg => { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap() - .ForMember(d => d.BaseString, m => m.Ignore()) - ; - cfg.CreateMap() - .IncludeBase() - .ForMember(d => d.BaseString, m => m.MapFrom(s => s.DifferentBaseString)) - ; - }); + cfg.CreateMap() + .ForMember(d => d.BaseString, m => m.Ignore()) + ; + cfg.CreateMap() + .IncludeBase() + .ForMember(d => d.BaseString, m => m.MapFrom(s => s.DifferentBaseString)) + ; + }); - var mapper = config.CreateMapper(); - var dto = mapper.Map(new ModelSubObject - { - DifferentBaseString = "123", - SubString = "456" - }); + var mapper = config.CreateMapper(); + var dto = mapper.Map(new ModelSubObject + { + DifferentBaseString = "123", + SubString = "456" + }); - "123".ShouldBe(dto.BaseString); - "456".ShouldBe(dto.SubString); - } + "123".ShouldBe(dto.BaseString); + "456".ShouldBe(dto.SubString); + } - [Fact] - public void more_specific_map_should_override_base_ignore() + [Fact] + public void more_specific_map_should_override_base_ignore() + { + var config = new MapperConfiguration(cfg => { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap() - .ForMember(d => d.BaseString, m => m.Ignore()) - ; - cfg.CreateMap() - .IncludeBase() - .ForMember(d => d.BaseString, m => m.MapFrom(s => s.DifferentBaseString)) - ; - }); - var mapper = config.CreateMapper(); - var dto = mapper.Map(new ModelSubObject - { - DifferentBaseString = "123", - SubString = "456" - }); + cfg.CreateMap() + .ForMember(d => d.BaseString, m => m.Ignore()) + ; + cfg.CreateMap() + .IncludeBase() + .ForMember(d => d.BaseString, m => m.MapFrom(s => s.DifferentBaseString)) + ; + }); + var mapper = config.CreateMapper(); + var dto = mapper.Map(new ModelSubObject + { + DifferentBaseString = "123", + SubString = "456" + }); - "123".ShouldBe(dto.BaseString); - "456".ShouldBe(dto.SubString); - } + "123".ShouldBe(dto.BaseString); + "456".ShouldBe(dto.SubString); + } - [Fact] - public void more_specific_map_should_override_base_mapping_passes_validation() + [Fact] + public void more_specific_map_should_override_base_mapping_passes_validation() + { + var config = new MapperConfiguration(cfg => { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap() - .ForMember(d => d.BaseString, m => m.MapFrom(s => s.DifferentBaseString)) - ; - cfg.CreateMap() - .IncludeBase() - .ForMember(d => d.BaseString, m => m.MapFrom(src => "789")); - }); - config.AssertConfigurationIsValid(); - } - [Fact] - public void more_specific_map_should_override_base_mapping_with_one_parameter() + cfg.CreateMap() + .ForMember(d => d.BaseString, m => m.MapFrom(s => s.DifferentBaseString)) + ; + cfg.CreateMap() + .IncludeBase() + .ForMember(d => d.BaseString, m => m.MapFrom(src => "789")); + }); + config.AssertConfigurationIsValid(); + } + [Fact] + public void more_specific_map_should_override_base_mapping_with_one_parameter() + { + var config = new MapperConfiguration(cfg => { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap() - .ForMember(d => d.BaseString, m => m.MapFrom(s => s.DifferentBaseString)); - cfg.CreateMap() - .IncludeBase() - .ForMember(d => d.BaseString, m => m.MapFrom(src => "789")); - }); - var mapper = config.CreateMapper(); - var dto = mapper.Map(new ModelSubObject - { - DifferentBaseString = "123", - SubString = "456" - }); + cfg.CreateMap() + .ForMember(d => d.BaseString, m => m.MapFrom(s => s.DifferentBaseString)); + cfg.CreateMap() + .IncludeBase() + .ForMember(d => d.BaseString, m => m.MapFrom(src => "789")); + }); + var mapper = config.CreateMapper(); + var dto = mapper.Map(new ModelSubObject + { + DifferentBaseString = "123", + SubString = "456" + }); - "789".ShouldBe(dto.BaseString); - "456".ShouldBe(dto.SubString); - } - - [Fact] - public void more_specific_map_should_override_base_mapping() + "789".ShouldBe(dto.BaseString); + "456".ShouldBe(dto.SubString); + } + + [Fact] + public void more_specific_map_should_override_base_mapping() + { + var config = new MapperConfiguration(cfg => { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap() - .ForMember(d => d.BaseString, m => m.MapFrom(s => s.DifferentBaseString)) - ; - cfg.CreateMap() - .IncludeBase() - .ForMember(d => d.BaseString, m => m.MapFrom(src => "789")); - }); - var mapper = config.CreateMapper(); - var dto = mapper.Map(new ModelSubObject - { - DifferentBaseString = "123", - SubString = "456" - }); + cfg.CreateMap() + .ForMember(d => d.BaseString, m => m.MapFrom(s => s.DifferentBaseString)) + ; + cfg.CreateMap() + .IncludeBase() + .ForMember(d => d.BaseString, m => m.MapFrom(src => "789")); + }); + var mapper = config.CreateMapper(); + var dto = mapper.Map(new ModelSubObject + { + DifferentBaseString = "123", + SubString = "456" + }); - "789".ShouldBe(dto.BaseString); - "456".ShouldBe(dto.SubString); - } + "789".ShouldBe(dto.BaseString); + "456".ShouldBe(dto.SubString); + } - [Fact] - public void include_should_allow_automapper_to_select_more_specific_included_type_with_one_parameter() + [Fact] + public void include_should_allow_automapper_to_select_more_specific_included_type_with_one_parameter() + { + var config = new MapperConfiguration(cfg => { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap() - .ForMember(d => d.BaseString, m => m.MapFrom(s => s.DifferentBaseString)); + cfg.CreateMap() + .ForMember(d => d.BaseString, m => m.MapFrom(s => s.DifferentBaseString)); - cfg.CreateMap() - .IncludeBase() - ; - }); - var mapper = config.CreateMapper(); - var dto = mapper.Map(new ModelSubObject - { - DifferentBaseString = "123", - SubString = "456" - }); + cfg.CreateMap() + .IncludeBase() + ; + }); + var mapper = config.CreateMapper(); + var dto = mapper.Map(new ModelSubObject + { + DifferentBaseString = "123", + SubString = "456" + }); - dto.ShouldBeOfType(); - } - - [Fact] - public void include_should_allow_automapper_to_select_more_specific_included_type() + dto.ShouldBeOfType(); + } + + [Fact] + public void include_should_allow_automapper_to_select_more_specific_included_type() + { + var config = new MapperConfiguration(cfg => { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap() - .ForMember(d => d.BaseString, m => m.MapFrom(s => s.DifferentBaseString)); + cfg.CreateMap() + .ForMember(d => d.BaseString, m => m.MapFrom(s => s.DifferentBaseString)); - cfg.CreateMap() - .IncludeBase(); - }); - var mapper = config.CreateMapper(); - var dto = mapper.Map(new ModelSubObject - { - DifferentBaseString = "123", - SubString = "456" - }); + cfg.CreateMap() + .IncludeBase(); + }); + var mapper = config.CreateMapper(); + var dto = mapper.Map(new ModelSubObject + { + DifferentBaseString = "123", + SubString = "456" + }); - dto.ShouldBeOfType(); - } + dto.ShouldBeOfType(); + } - [Fact] - public void include_should_apply_condition() + [Fact] + public void include_should_apply_condition() + { + var config = new MapperConfiguration(cfg => { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap() - .ForMember(d => d.BaseString, m => - { - m.Condition(src => !string.IsNullOrWhiteSpace(src.DifferentBaseString)); - m.MapFrom(s => s.DifferentBaseString); - }) - ; + cfg.CreateMap() + .ForMember(d => d.BaseString, m => + { + m.Condition(src => !string.IsNullOrWhiteSpace(src.DifferentBaseString)); + m.MapFrom(s => s.DifferentBaseString); + }) + ; - cfg.CreateMap() - .IncludeBase() - ; - }); - var dest = new DtoSubObject - { - BaseString = "12345" - }; - var mapper = config.CreateMapper(); - mapper.Map(new ModelSubObject - { - DifferentBaseString = "", - }, dest); + cfg.CreateMap() + .IncludeBase() + ; + }); + var dest = new DtoSubObject + { + BaseString = "12345" + }; + var mapper = config.CreateMapper(); + mapper.Map(new ModelSubObject + { + DifferentBaseString = "", + }, dest); - dest.BaseString.ShouldBe("12345"); - } + dest.BaseString.ShouldBe("12345"); + } - [Fact] - public void include_should_apply_null_substitute() + [Fact] + public void include_should_apply_null_substitute() + { + var config = new MapperConfiguration(cfg => { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap() - .ForMember(d => d.BaseString, m => - { - m.MapFrom(s => s.DifferentBaseString); - m.NullSubstitute("12345"); - }) - ; + cfg.CreateMap() + .ForMember(d => d.BaseString, m => + { + m.MapFrom(s => s.DifferentBaseString); + m.NullSubstitute("12345"); + }) + ; - cfg.CreateMap() - .IncludeBase() - ; - }); - var mapper = config.CreateMapper(); - var dest = mapper.Map(new ModelSubObject()); + cfg.CreateMap() + .IncludeBase() + ; + }); + var mapper = config.CreateMapper(); + var dest = mapper.Map(new ModelSubObject()); - dest.BaseString.ShouldBe("12345"); - } + dest.BaseString.ShouldBe("12345"); } } diff --git a/src/UnitTests/MappingInheritance/InheritanceWithoutIncludeShouldWork.cs b/src/UnitTests/MappingInheritance/InheritanceWithoutIncludeShouldWork.cs index 2fe14c8e3d..ca9e281c44 100644 --- a/src/UnitTests/MappingInheritance/InheritanceWithoutIncludeShouldWork.cs +++ b/src/UnitTests/MappingInheritance/InheritanceWithoutIncludeShouldWork.cs @@ -1,35 +1,34 @@ -namespace AutoMapper.UnitTests.MappingInheritance +namespace AutoMapper.UnitTests.MappingInheritance; + +using Shouldly; +using Xunit; + +public class InheritanceWithoutIncludeShouldWork : AutoMapperSpecBase { - using Shouldly; - using Xunit; + public class FooBase { } + public class Foo : FooBase { } + public class FooDto { public int Value { get; set; } } - public class InheritanceWithoutIncludeShouldWork : AutoMapperSpecBase + protected override MapperConfiguration CreateConfiguration() => new(cfg => { - public class FooBase { } - public class Foo : FooBase { } - public class FooDto { public int Value { get; set; } } + cfg.CreateMap().ForMember(d => d.Value, opt => opt.MapFrom(src => 10)); + cfg.CreateMap().ForMember(d => d.Value, opt => opt.MapFrom(src => 5)); + }); - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().ForMember(d => d.Value, opt => opt.MapFrom(src => 10)); - cfg.CreateMap().ForMember(d => d.Value, opt => opt.MapFrom(src => 5)); - }); - - [Fact] - public void Should_map_derived() - { - Map(new Foo()).Value.ShouldBe(5); - } + [Fact] + public void Should_map_derived() + { + Map(new Foo()).Value.ShouldBe(5); + } - [Fact] - public void Should_map_base() - { - Map(new FooBase()).Value.ShouldBe(10); - } + [Fact] + public void Should_map_base() + { + Map(new FooBase()).Value.ShouldBe(10); + } - private FooDto Map(FooBase foo) - { - return Mapper.Map(foo); - } + private FooDto Map(FooBase foo) + { + return Mapper.Map(foo); } } \ No newline at end of file diff --git a/src/UnitTests/MappingInheritance/MapToBaseClass.cs b/src/UnitTests/MappingInheritance/MapToBaseClass.cs index 3c9e947ffb..cf74825073 100644 --- a/src/UnitTests/MappingInheritance/MapToBaseClass.cs +++ b/src/UnitTests/MappingInheritance/MapToBaseClass.cs @@ -1,79 +1,78 @@ -namespace AutoMapper.UnitTests.MappingInheritance +namespace AutoMapper.UnitTests.MappingInheritance; + +using System; +using Shouldly; +using Xunit; +public class MapToBaseClass : AutoMapperSpecBase { - using System; - using Shouldly; - using Xunit; - public class MapToBaseClass : AutoMapperSpecBase - { - A _destination; + A _destination; - public class Input { } - public class A { } - public class B : A { } + public class Input { } + public class A { } + public class B : A { } - protected override MapperConfiguration CreateConfiguration() => new(c => - { - c.CreateMap().Include(); - c.CreateMap(); - }); + protected override MapperConfiguration CreateConfiguration() => new(c => + { + c.CreateMap().Include(); + c.CreateMap(); + }); - protected override void Because_of() - { - _destination = Mapper.Map(new Input()); - } + protected override void Because_of() + { + _destination = Mapper.Map(new Input()); + } - [Fact] - public void ShouldReturnBaseClass() - { - _destination.ShouldBeOfType(); - } + [Fact] + public void ShouldReturnBaseClass() + { + _destination.ShouldBeOfType(); + } +} +public class OverrideInclude : AutoMapperSpecBase +{ + class Source + { + } + class Destination + { } - public class OverrideInclude : AutoMapperSpecBase + class SourceDerived : Source { - class Source - { - } - class Destination - { - } - class SourceDerived : Source - { - } - class DestinationDerived : Destination - { - } - protected override MapperConfiguration CreateConfiguration() => new(c => - { - c.CreateMap().Include(); - c.CreateMap(); - c.CreateMap(); - }); - [Fact] - public void ExplicitMapShouldApply() => Map(new SourceDerived()).ShouldBeOfType(); } - public class IncludeAs : AutoMapperSpecBase + class DestinationDerived : Destination { - class Source - { - } - abstract class Destination - { - } - class SourceDerived : Source - { - } - class DestinationDerived : Destination - { - } - class DestinationConcrete : Destination { } - protected override MapperConfiguration CreateConfiguration() => new(c => - { - c.CreateMap().Include(); - c.CreateMap().As(); - c.CreateMap(); - c.CreateMap(); - }); - [Fact] - public void RedirectedMapShouldApply() => Map(new SourceDerived()).ShouldBeOfType(); } + protected override MapperConfiguration CreateConfiguration() => new(c => + { + c.CreateMap().Include(); + c.CreateMap(); + c.CreateMap(); + }); + [Fact] + public void ExplicitMapShouldApply() => Map(new SourceDerived()).ShouldBeOfType(); +} +public class IncludeAs : AutoMapperSpecBase +{ + class Source + { + } + abstract class Destination + { + } + class SourceDerived : Source + { + } + class DestinationDerived : Destination + { + } + class DestinationConcrete : Destination { } + protected override MapperConfiguration CreateConfiguration() => new(c => + { + c.CreateMap().Include(); + c.CreateMap().As(); + c.CreateMap(); + c.CreateMap(); + }); + [Fact] + public void RedirectedMapShouldApply() => Map(new SourceDerived()).ShouldBeOfType(); } \ No newline at end of file diff --git a/src/UnitTests/MappingInheritance/MultipleInheritedBaseMappingsOfSameTypeFails.cs b/src/UnitTests/MappingInheritance/MultipleInheritedBaseMappingsOfSameTypeFails.cs index f082d349e2..863b3e37dc 100644 --- a/src/UnitTests/MappingInheritance/MultipleInheritedBaseMappingsOfSameTypeFails.cs +++ b/src/UnitTests/MappingInheritance/MultipleInheritedBaseMappingsOfSameTypeFails.cs @@ -1,43 +1,42 @@ using Xunit; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class MultipleMappingsOfSameTypeFails { - public class MultipleMappingsOfSameTypeFails + public class MyClass { - public class MyClass - { - public ActivityBase Information { get; set; } - public InformationClass CurrentInformation { get; set; } - } + public ActivityBase Information { get; set; } + public InformationClass CurrentInformation { get; set; } + } - public class MySpecificClass :MyClass{} + public class MySpecificClass :MyClass{} - public class MyDto - { - public InformationDto Information { get; set; } - } + public class MyDto + { + public InformationDto Information { get; set; } + } - public class MySpecificDto : MyDto{} - public class InformationDto{} - public class ActivityBase{} - public class InformationBase{} - public class InformationClass{} + public class MySpecificDto : MyDto{} + public class InformationDto{} + public class ActivityBase{} + public class InformationBase{} + public class InformationClass{} - [Fact] - public void multiple_inherited_base_mappings_of_same_type_fails() + [Fact] + public void multiple_inherited_base_mappings_of_same_type_fails() + { + var config = new MapperConfiguration(cfg => { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap() - .ForMember(d => d.Information, m => m.MapFrom(s => s.CurrentInformation)) - .Include(); - cfg.CreateMap(); + cfg.CreateMap() + .ForMember(d => d.Information, m => m.MapFrom(s => s.CurrentInformation)) + .Include(); + cfg.CreateMap(); - cfg.CreateMap(); - }); + cfg.CreateMap(); + }); - config.AssertConfigurationIsValid(); - } + config.AssertConfigurationIsValid(); } } diff --git a/src/UnitTests/MappingInheritance/OpenGenericsWithInheritance.cs b/src/UnitTests/MappingInheritance/OpenGenericsWithInheritance.cs index 42fb89f420..bf3f12a7e5 100644 --- a/src/UnitTests/MappingInheritance/OpenGenericsWithInheritance.cs +++ b/src/UnitTests/MappingInheritance/OpenGenericsWithInheritance.cs @@ -6,225 +6,224 @@ using System.Threading.Tasks; using Xunit; -namespace AutoMapper.UnitTests +namespace AutoMapper.UnitTests; + +public class OpenGenericsWithAs : AutoMapperSpecBase +{ + public class Source + { + public object Value { get; set; } + } + + public interface ITarget + { + T Value { get; } + } + + public class Target : ITarget + { + public T Value { get; set; } + } + + protected override MapperConfiguration CreateConfiguration() => new(cfg=> + { + cfg.CreateMap(typeof(Source), typeof(Target<>)); + cfg.CreateMap(typeof(Source), typeof(ITarget<>)).As(typeof(Target<>)); + }); + + [Fact] + public void Should_use_the_redirected_map() + { + var source = new Source { Value = "value" }; + Mapper.Map>(source).Value.ShouldBe(source.Value); + } +} + +public class OpenGenericsWithInclude : AutoMapperSpecBase +{ + public class Person + { + public string Name { get; set; } + public List BarList { get; set; } = new List(); + } + + public class PersonModel + { + public string Name { get; set; } + public List BarList { get; set; } + } + + abstract public class BarBase + { + public int Id { get; set; } + } + + public class Bar : BarBase + { + public T Value { get; set; } + } + + abstract public class BarModelBase + { + public int Id { get; set; } + public string Ignored { get; set; } + public string MappedFrom { get; set; } + } + + public class BarModel : BarModelBase + { + public T Value { get; set; } + public string DerivedMember { get; set; } + } + + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .ForMember(d=>d.Ignored, o=>o.Ignore()) + .ForMember(d=>d.MappedFrom, o=>o.MapFrom(_=>"mappedFrom")) + .Include(typeof(Bar<>), typeof(BarModel<>)); + cfg.CreateMap(); + cfg.CreateMap(typeof(Bar<>), typeof(BarModel<>)).ForMember("DerivedMember", o=>o.MapFrom("Id")); + }); + + [Fact] + public void Should_work() + { + var person = new Person { Name = "Jack", BarList = { new Bar{ Id = 1, Value = "One" }, new Bar{ Id = 2, Value = "Two" } } }; + + var personMapped = Mapper.Map(person); + + var barModel = (BarModel)personMapped.BarList[0]; + barModel.Value.ShouldBe("One"); + barModel.DerivedMember.ShouldBe("1"); + barModel.MappedFrom.ShouldBe("mappedFrom"); + barModel = (BarModel)personMapped.BarList[1]; + barModel.Value.ShouldBe("Two"); + barModel.DerivedMember.ShouldBe("2"); + barModel.MappedFrom.ShouldBe("mappedFrom"); + } +} + +public class OpenGenericsWithIncludeBase : AutoMapperSpecBase +{ + public class Person + { + public string Name { get; set; } + public List BarList { get; set; } = new List(); + } + + public class PersonModel + { + public string Name { get; set; } + public List BarList { get; set; } + } + + abstract public class BarBase + { + public int Id { get; set; } + } + + public class Bar : BarBase + { + public T Value { get; set; } + } + + abstract public class BarModelBase + { + public int Id { get; set; } + public string Ignored { get; set; } + public string MappedFrom { get; set; } + } + + public class BarModel : BarModelBase + { + public T Value { get; set; } + public string DerivedMember { get; set; } + } + + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(typeof(BarBase), typeof(BarModelBase)) + .ForMember("Ignored", o => o.Ignore()) + .ForMember("MappedFrom", o => o.MapFrom(_=>"mappedFrom")); + cfg.CreateMap(); + cfg.CreateMap(typeof(Bar<>), typeof(BarModel<>)) + .ForMember("DerivedMember", o => o.MapFrom("Id")) + .IncludeBase(typeof(BarBase), typeof(BarModelBase)); + }); + + [Fact] + public void Should_work() + { + var person = new Person { Name = "Jack", BarList = { new Bar { Id = 1, Value = "One" }, new Bar { Id = 2, Value = "Two" } } }; + + var personMapped = Mapper.Map(person); + + var barModel = (BarModel)personMapped.BarList[0]; + barModel.Value.ShouldBe("One"); + barModel.DerivedMember.ShouldBe("1"); + barModel.MappedFrom.ShouldBe("mappedFrom"); + barModel = (BarModel)personMapped.BarList[1]; + barModel.Value.ShouldBe("Two"); + barModel.DerivedMember.ShouldBe("2"); + barModel.MappedFrom.ShouldBe("mappedFrom"); + } +} + +public class OpenGenericsAndNonGenericsWithIncludeBase : AutoMapperSpecBase { - public class OpenGenericsWithAs : AutoMapperSpecBase - { - public class Source - { - public object Value { get; set; } - } - - public interface ITarget - { - T Value { get; } - } - - public class Target : ITarget - { - public T Value { get; set; } - } - - protected override MapperConfiguration CreateConfiguration() => new(cfg=> - { - cfg.CreateMap(typeof(Source), typeof(Target<>)); - cfg.CreateMap(typeof(Source), typeof(ITarget<>)).As(typeof(Target<>)); - }); - - [Fact] - public void Should_use_the_redirected_map() - { - var source = new Source { Value = "value" }; - Mapper.Map>(source).Value.ShouldBe(source.Value); - } - } - - public class OpenGenericsWithInclude : AutoMapperSpecBase - { - public class Person - { - public string Name { get; set; } - public List BarList { get; set; } = new List(); - } - - public class PersonModel - { - public string Name { get; set; } - public List BarList { get; set; } - } - - abstract public class BarBase - { - public int Id { get; set; } - } - - public class Bar : BarBase - { - public T Value { get; set; } - } - - abstract public class BarModelBase - { - public int Id { get; set; } - public string Ignored { get; set; } - public string MappedFrom { get; set; } - } - - public class BarModel : BarModelBase - { - public T Value { get; set; } - public string DerivedMember { get; set; } - } - - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ForMember(d=>d.Ignored, o=>o.Ignore()) - .ForMember(d=>d.MappedFrom, o=>o.MapFrom(_=>"mappedFrom")) - .Include(typeof(Bar<>), typeof(BarModel<>)); - cfg.CreateMap(); - cfg.CreateMap(typeof(Bar<>), typeof(BarModel<>)).ForMember("DerivedMember", o=>o.MapFrom("Id")); - }); - - [Fact] - public void Should_work() - { - var person = new Person { Name = "Jack", BarList = { new Bar{ Id = 1, Value = "One" }, new Bar{ Id = 2, Value = "Two" } } }; - - var personMapped = Mapper.Map(person); - - var barModel = (BarModel)personMapped.BarList[0]; - barModel.Value.ShouldBe("One"); - barModel.DerivedMember.ShouldBe("1"); - barModel.MappedFrom.ShouldBe("mappedFrom"); - barModel = (BarModel)personMapped.BarList[1]; - barModel.Value.ShouldBe("Two"); - barModel.DerivedMember.ShouldBe("2"); - barModel.MappedFrom.ShouldBe("mappedFrom"); - } - } - - public class OpenGenericsWithIncludeBase : AutoMapperSpecBase - { - public class Person - { - public string Name { get; set; } - public List BarList { get; set; } = new List(); - } - - public class PersonModel - { - public string Name { get; set; } - public List BarList { get; set; } - } - - abstract public class BarBase - { - public int Id { get; set; } - } - - public class Bar : BarBase - { - public T Value { get; set; } - } - - abstract public class BarModelBase - { - public int Id { get; set; } - public string Ignored { get; set; } - public string MappedFrom { get; set; } - } - - public class BarModel : BarModelBase - { - public T Value { get; set; } - public string DerivedMember { get; set; } - } - - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(typeof(BarBase), typeof(BarModelBase)) - .ForMember("Ignored", o => o.Ignore()) - .ForMember("MappedFrom", o => o.MapFrom(_=>"mappedFrom")); - cfg.CreateMap(); - cfg.CreateMap(typeof(Bar<>), typeof(BarModel<>)) - .ForMember("DerivedMember", o => o.MapFrom("Id")) - .IncludeBase(typeof(BarBase), typeof(BarModelBase)); - }); - - [Fact] - public void Should_work() - { - var person = new Person { Name = "Jack", BarList = { new Bar { Id = 1, Value = "One" }, new Bar { Id = 2, Value = "Two" } } }; - - var personMapped = Mapper.Map(person); - - var barModel = (BarModel)personMapped.BarList[0]; - barModel.Value.ShouldBe("One"); - barModel.DerivedMember.ShouldBe("1"); - barModel.MappedFrom.ShouldBe("mappedFrom"); - barModel = (BarModel)personMapped.BarList[1]; - barModel.Value.ShouldBe("Two"); - barModel.DerivedMember.ShouldBe("2"); - barModel.MappedFrom.ShouldBe("mappedFrom"); - } - } - - public class OpenGenericsAndNonGenericsWithIncludeBase : AutoMapperSpecBase - { - public abstract class Entity - { - public string BaseMember { get; set; } - } - - public abstract class Model - { - public string BaseMember { get; set; } - } - - public abstract class Entity : Entity - { - public TId Id { get; set; } - } - - public abstract class Model : Model - { - public TId Id { get; set; } - } - - public class SubEntity : Entity - { - public string SubMember { get; set; } - } - - public class SubModel : Model - { - public string SubMember { get; set; } - } - - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - - cfg.CreateMap(typeof(Entity<>), typeof(Model<>)) - .IncludeBase(typeof(Entity), typeof(Model)); - - - cfg.CreateMap() - .IncludeBase, Model>() - .IncludeBase(); - }); - - [Fact] - public void Should_work() - { - var entity = new SubEntity { BaseMember = "foo", Id = 695, SubMember = "bar" }; - - var model = this.Mapper.Map(entity); - - model.BaseMember.ShouldBe("foo"); - model.Id.ShouldBe(695); - model.SubMember.ShouldBe("bar"); - } + public abstract class Entity + { + public string BaseMember { get; set; } + } + + public abstract class Model + { + public string BaseMember { get; set; } + } + + public abstract class Entity : Entity + { + public TId Id { get; set; } + } + + public abstract class Model : Model + { + public TId Id { get; set; } + } + + public class SubEntity : Entity + { + public string SubMember { get; set; } + } + + public class SubModel : Model + { + public string SubMember { get; set; } + } + + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + + cfg.CreateMap(typeof(Entity<>), typeof(Model<>)) + .IncludeBase(typeof(Entity), typeof(Model)); + + + cfg.CreateMap() + .IncludeBase, Model>() + .IncludeBase(); + }); + + [Fact] + public void Should_work() + { + var entity = new SubEntity { BaseMember = "foo", Id = 695, SubMember = "bar" }; + + var model = this.Mapper.Map(entity); + + model.BaseMember.ShouldBe("foo"); + model.Id.ShouldBe(695); + model.SubMember.ShouldBe("bar"); } } \ No newline at end of file diff --git a/src/UnitTests/MappingInheritance/OverrideIgnore.cs b/src/UnitTests/MappingInheritance/OverrideIgnore.cs index 5ce3fa5604..3c49af8d54 100644 --- a/src/UnitTests/MappingInheritance/OverrideIgnore.cs +++ b/src/UnitTests/MappingInheritance/OverrideIgnore.cs @@ -1,42 +1,41 @@ using Shouldly; using Xunit; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class OverrideIgnore { - public class OverrideIgnore + public class DomainBase + { + public string SomeProperty { get; set; } + } + + public class DtoBase + { + public string SomeDifferentProperty { get; set; } + } + + [Fact] + public void specifying_map_should_override_ignore() { - public class DomainBase - { - public string SomeProperty { get; set; } - } - - public class DtoBase - { - public string SomeDifferentProperty { get; set; } - } - - [Fact] - public void specifying_map_should_override_ignore() - { - var config = new MapperConfiguration(cfg => cfg.CreateMap() - .ForMember(m=>m.SomeDifferentProperty, m=>m.Ignore()) - .ForMember(m=>m.SomeDifferentProperty, m=>m.MapFrom(s=>s.SomeProperty))); - - var dto = config.CreateMapper().Map(new DomainBase {SomeProperty = "Test"}); - - "Test".ShouldBe(dto.SomeDifferentProperty); - } - - [Fact] - public void specifying_map_should_override_ignore_with_one_parameter() - { - var config = new MapperConfiguration(cfg => cfg.CreateMap() - .ForMember(m => m.SomeDifferentProperty, m => m.Ignore()) - .ForMember(m => m.SomeDifferentProperty, m => m.MapFrom(s => s.SomeProperty))); - - var dto = config.CreateMapper().Map(new DomainBase { SomeProperty = "Test" }); - - "Test".ShouldBe(dto.SomeDifferentProperty); - } + var config = new MapperConfiguration(cfg => cfg.CreateMap() + .ForMember(m=>m.SomeDifferentProperty, m=>m.Ignore()) + .ForMember(m=>m.SomeDifferentProperty, m=>m.MapFrom(s=>s.SomeProperty))); + + var dto = config.CreateMapper().Map(new DomainBase {SomeProperty = "Test"}); + + "Test".ShouldBe(dto.SomeDifferentProperty); + } + + [Fact] + public void specifying_map_should_override_ignore_with_one_parameter() + { + var config = new MapperConfiguration(cfg => cfg.CreateMap() + .ForMember(m => m.SomeDifferentProperty, m => m.Ignore()) + .ForMember(m => m.SomeDifferentProperty, m => m.MapFrom(s => s.SomeProperty))); + + var dto = config.CreateMapper().Map(new DomainBase { SomeProperty = "Test" }); + + "Test".ShouldBe(dto.SomeDifferentProperty); } } diff --git a/src/UnitTests/MappingInheritance/PropertyOnMappingShouldResolveMostSpecificType.cs b/src/UnitTests/MappingInheritance/PropertyOnMappingShouldResolveMostSpecificType.cs index 3716e383d6..d24823f0c0 100644 --- a/src/UnitTests/MappingInheritance/PropertyOnMappingShouldResolveMostSpecificType.cs +++ b/src/UnitTests/MappingInheritance/PropertyOnMappingShouldResolveMostSpecificType.cs @@ -2,199 +2,198 @@ using Shouldly; using Xunit; -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug; + +public class PropertyOnMappingShouldResolveMostSpecificType { - public class PropertyOnMappingShouldResolveMostSpecificType + public class ItemBase { - public class ItemBase - { - public string SomeBaseProperty { get; set; } - } + public string SomeBaseProperty { get; set; } + } - public class GenericItem : ItemBase{} + public class GenericItem : ItemBase{} - public class SpecificItem :ItemBase{} + public class SpecificItem :ItemBase{} - public class DifferentItem : GenericItem { } - public class DifferentItem2 : GenericItem { } + public class DifferentItem : GenericItem { } + public class DifferentItem2 : GenericItem { } - public class ItemDto - { - public DescriptionBaseDto Description { get; set; } - public string SomeProperty { get; set; } - } + public class ItemDto + { + public DescriptionBaseDto Description { get; set; } + public string SomeProperty { get; set; } + } - public class SpecificItemDto : ItemDto{} + public class SpecificItemDto : ItemDto{} - public class DescriptionBaseDto{} + public class DescriptionBaseDto{} - public class GenericDescriptionDto : DescriptionBaseDto{} + public class GenericDescriptionDto : DescriptionBaseDto{} - public class SpecificDescriptionDto : DescriptionBaseDto{} - public class DifferentDescriptionDto : GenericDescriptionDto { } - public class DifferentDescriptionDto2 : GenericDescriptionDto { } + public class SpecificDescriptionDto : DescriptionBaseDto{} + public class DifferentDescriptionDto : GenericDescriptionDto { } + public class DifferentDescriptionDto2 : GenericDescriptionDto { } - public class Container + public class Container + { + public Container() { - public Container() - { - Items = new List(); - } - public List Items { get; private set; } + Items = new List(); } + public List Items { get; private set; } + } - public class ContainerDto + public class ContainerDto + { + public ContainerDto() { - public ContainerDto() - { - Items = new List(); - } - public List Items { get; private set; } + Items = new List(); } + public List Items { get; private set; } + } - [Fact] - public void container_class_is_caching_too_specific_mapper_for_collection() + [Fact] + public void container_class_is_caching_too_specific_mapper_for_collection() + { + var config = new MapperConfiguration(cfg => { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap() - .ForMember(d => d.Description, m => m.MapFrom(s => s)) - .ForMember(d => d.SomeProperty, m => m.MapFrom(s => s.SomeBaseProperty)) - .Include(); - cfg.CreateMap() - .ForMember(d => d.SomeProperty, m => m.MapFrom(s => s.SomeBaseProperty)); - - cfg.CreateMap() - .Include() - .Include(); - - cfg.CreateMap(); - cfg.CreateMap() - .Include() - .Include(); - cfg.CreateMap(); - cfg.CreateMap(); - - cfg.CreateMap(); - }); - - var dto = config.CreateMapper().Map(new Container - { - Items = - { - new DifferentItem(), - new SpecificItem() - } - }); - - dto.Items[0].Description.ShouldBeOfType(); - dto.Items[1].ShouldBeOfType(); - dto.Items[1].Description.ShouldBeOfType(); - } + cfg.CreateMap() + .ForMember(d => d.Description, m => m.MapFrom(s => s)) + .ForMember(d => d.SomeProperty, m => m.MapFrom(s => s.SomeBaseProperty)) + .Include(); + cfg.CreateMap() + .ForMember(d => d.SomeProperty, m => m.MapFrom(s => s.SomeBaseProperty)); + + cfg.CreateMap() + .Include() + .Include(); + + cfg.CreateMap(); + cfg.CreateMap() + .Include() + .Include(); + cfg.CreateMap(); + cfg.CreateMap(); + + cfg.CreateMap(); + }); + + var dto = config.CreateMapper().Map(new Container + { + Items = + { + new DifferentItem(), + new SpecificItem() + } + }); + + dto.Items[0].Description.ShouldBeOfType(); + dto.Items[1].ShouldBeOfType(); + dto.Items[1].Description.ShouldBeOfType(); + } - [Fact] - public void container_class_is_caching_too_specific_mapper_for_collection_with_one_parameter() + [Fact] + public void container_class_is_caching_too_specific_mapper_for_collection_with_one_parameter() + { + var config = new MapperConfiguration(cfg => { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap() - .ForMember(d => d.Description, m => m.MapFrom(s => s)) - .ForMember(d => d.SomeProperty, m => m.MapFrom(s => s.SomeBaseProperty)) - .Include(); - cfg.CreateMap() - .ForMember(d => d.SomeProperty, m => m.MapFrom(s => s.SomeBaseProperty)); - - cfg.CreateMap() - .Include() - .Include(); - - cfg.CreateMap(); - cfg.CreateMap() - .Include() - .Include(); - cfg.CreateMap(); - cfg.CreateMap(); - - cfg.CreateMap(); - }); - - var dto = config.CreateMapper().Map(new Container - { - Items = - { - new DifferentItem(), - new SpecificItem() - } - }); - - dto.Items[0].Description.ShouldBeOfType(); - dto.Items[1].ShouldBeOfType(); - dto.Items[1].Description.ShouldBeOfType(); - } + cfg.CreateMap() + .ForMember(d => d.Description, m => m.MapFrom(s => s)) + .ForMember(d => d.SomeProperty, m => m.MapFrom(s => s.SomeBaseProperty)) + .Include(); + cfg.CreateMap() + .ForMember(d => d.SomeProperty, m => m.MapFrom(s => s.SomeBaseProperty)); + + cfg.CreateMap() + .Include() + .Include(); + + cfg.CreateMap(); + cfg.CreateMap() + .Include() + .Include(); + cfg.CreateMap(); + cfg.CreateMap(); + + cfg.CreateMap(); + }); + + var dto = config.CreateMapper().Map(new Container + { + Items = + { + new DifferentItem(), + new SpecificItem() + } + }); + + dto.Items[0].Description.ShouldBeOfType(); + dto.Items[1].ShouldBeOfType(); + dto.Items[1].Description.ShouldBeOfType(); + } - [Fact] - public void property_on_dto_mapped_from_self_should_be_specific_match() + [Fact] + public void property_on_dto_mapped_from_self_should_be_specific_match() + { + var config = new MapperConfiguration(cfg => { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap() - .ForMember(d => d.Description, m => m.MapFrom(s => s)) - .ForMember(d => d.SomeProperty, m => m.MapFrom(s => s.SomeBaseProperty)) - .Include(); - cfg.CreateMap() - .ForMember(d => d.SomeProperty, m => m.MapFrom(s => s.SomeBaseProperty)); - - cfg.CreateMap() - .Include() - .Include(); - - cfg.CreateMap(); - cfg.CreateMap() - .Include() - .Include(); - cfg.CreateMap(); - cfg.CreateMap(); - }); - - config.AssertConfigurationIsValid(); - - var dto = config.CreateMapper().Map(new DifferentItem()); - - dto.ShouldBeOfType(); - dto.Description.ShouldBeOfType(); - } + cfg.CreateMap() + .ForMember(d => d.Description, m => m.MapFrom(s => s)) + .ForMember(d => d.SomeProperty, m => m.MapFrom(s => s.SomeBaseProperty)) + .Include(); + cfg.CreateMap() + .ForMember(d => d.SomeProperty, m => m.MapFrom(s => s.SomeBaseProperty)); + + cfg.CreateMap() + .Include() + .Include(); + + cfg.CreateMap(); + cfg.CreateMap() + .Include() + .Include(); + cfg.CreateMap(); + cfg.CreateMap(); + }); + + config.AssertConfigurationIsValid(); + + var dto = config.CreateMapper().Map(new DifferentItem()); + + dto.ShouldBeOfType(); + dto.Description.ShouldBeOfType(); + } - [Fact] - public void property_on_dto_mapped_from_self_should_be_specific_match_with_one_parameter() + [Fact] + public void property_on_dto_mapped_from_self_should_be_specific_match_with_one_parameter() + { + var config = new MapperConfiguration(cfg => { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap() - .ForMember(d => d.Description, m => m.MapFrom(s => s)) - .ForMember(d => d.SomeProperty, m => m.MapFrom(s => s.SomeBaseProperty)) - .Include(); - cfg.CreateMap() - .ForMember(d => d.SomeProperty, m => m.MapFrom(s => s.SomeBaseProperty)); - - cfg.CreateMap() - .Include() - .Include(); - - cfg.CreateMap(); - cfg.CreateMap() - .Include() - .Include(); - cfg.CreateMap(); - cfg.CreateMap(); - }); - - config.AssertConfigurationIsValid(); - - var dto = config.CreateMapper().Map(new DifferentItem()); - - dto.ShouldBeOfType(); - dto.Description.ShouldBeOfType(); - } + cfg.CreateMap() + .ForMember(d => d.Description, m => m.MapFrom(s => s)) + .ForMember(d => d.SomeProperty, m => m.MapFrom(s => s.SomeBaseProperty)) + .Include(); + cfg.CreateMap() + .ForMember(d => d.SomeProperty, m => m.MapFrom(s => s.SomeBaseProperty)); + + cfg.CreateMap() + .Include() + .Include(); + + cfg.CreateMap(); + cfg.CreateMap() + .Include() + .Include(); + cfg.CreateMap(); + cfg.CreateMap(); + }); + + config.AssertConfigurationIsValid(); + + var dto = config.CreateMapper().Map(new DifferentItem()); + + dto.ShouldBeOfType(); + dto.Description.ShouldBeOfType(); } } diff --git a/src/UnitTests/MappingInheritance/ReverseMapWithInclude.cs b/src/UnitTests/MappingInheritance/ReverseMapWithInclude.cs index 867a6a438f..5d427cb003 100644 --- a/src/UnitTests/MappingInheritance/ReverseMapWithInclude.cs +++ b/src/UnitTests/MappingInheritance/ReverseMapWithInclude.cs @@ -1,75 +1,74 @@ -namespace AutoMapper.UnitTests.MappingInheritance +namespace AutoMapper.UnitTests.MappingInheritance; + +using System; +using Shouldly; +using Xunit; + +public class ReverseMapWithInclude : NonValidatingSpecBase { - using System; - using Shouldly; - using Xunit; + public class Duck : Animal { } + public class DuckDto : AnimalDto { } + public abstract class Animal { } + public abstract class AnimalDto { } + public class DuckProxyClassFoo : Duck { } - public class ReverseMapWithInclude : NonValidatingSpecBase + [Fact] + public void Should_map_correctly() { - public class Duck : Animal { } - public class DuckDto : AnimalDto { } - public abstract class Animal { } - public abstract class AnimalDto { } - public class DuckProxyClassFoo : Duck { } - - [Fact] - public void Should_map_correctly() + var config = new MapperConfiguration(cfg => { - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap() - .Include(); + cfg.CreateMap() + .Include(); - cfg.CreateMap().ReverseMap(); - }); + cfg.CreateMap().ReverseMap(); + }); - var aDuck = new DuckProxyClassFoo(); + var aDuck = new DuckProxyClassFoo(); - var mapper = config.CreateMapper(); - var dto = mapper.Map(aDuck); + var mapper = config.CreateMapper(); + var dto = mapper.Map(aDuck); - dto.ShouldBeOfType(); - } + dto.ShouldBeOfType(); } +} - public class ReverseMapWithIncludeBase : AutoMapperSpecBase - { - ConcreteSource _destination; +public class ReverseMapWithIncludeBase : AutoMapperSpecBase +{ + ConcreteSource _destination; - public class Destination - { - public string Name { get; set; } - } + public class Destination + { + public string Name { get; set; } + } - public class ConcreteDestination : Destination { } + public class ConcreteDestination : Destination { } - public class Source - { - public string Title { get; set; } - } + public class Source + { + public string Title { get; set; } + } - public class ConcreteSource : Source { } + public class ConcreteSource : Source { } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ForMember(dest => dest.Name, conf => conf.MapFrom(source => source.Title)) - .ReverseMap() - .ForMember(dest => dest.Title, conf => conf.MapFrom(source => source.Name)); - cfg.CreateMap() - .IncludeBase() - .ReverseMap(); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .ForMember(dest => dest.Name, conf => conf.MapFrom(source => source.Title)) + .ReverseMap() + .ForMember(dest => dest.Title, conf => conf.MapFrom(source => source.Name)); + cfg.CreateMap() + .IncludeBase() + .ReverseMap(); + }); - protected override void Because_of() - { - _destination = Mapper.Map(new ConcreteDestination { Name = "Name" }); - } + protected override void Because_of() + { + _destination = Mapper.Map(new ConcreteDestination { Name = "Name" }); + } - [Fact] - public void Should_work_together() - { - _destination.Title.ShouldBe("Name"); - } + [Fact] + public void Should_work_together() + { + _destination.Title.ShouldBe("Name"); } } \ No newline at end of file diff --git a/src/UnitTests/MappingInheritance/ShouldInheritBeforeAndAfterMap.cs b/src/UnitTests/MappingInheritance/ShouldInheritBeforeAndAfterMap.cs index 7bfc7a390d..976d4b0978 100644 --- a/src/UnitTests/MappingInheritance/ShouldInheritBeforeAndAfterMap.cs +++ b/src/UnitTests/MappingInheritance/ShouldInheritBeforeAndAfterMap.cs @@ -3,142 +3,141 @@ using Shouldly; using Xunit; -namespace AutoMapper.UnitTests.MappingInheritance +namespace AutoMapper.UnitTests.MappingInheritance; + +public class ShouldInheritBeforeAndAfterMapOnlyOnce : AutoMapperSpecBase { - public class ShouldInheritBeforeAndAfterMapOnlyOnce : AutoMapperSpecBase + int afterMapCount; + int beforeMapCount; + + public abstract class BaseBaseSource { } + public class BaseSource : BaseBaseSource { - int afterMapCount; - int beforeMapCount; + public string Foo { get; set; } + } + public class Source : BaseSource { } - public abstract class BaseBaseSource { } - public class BaseSource : BaseBaseSource - { - public string Foo { get; set; } - } - public class Source : BaseSource { } + public abstract class BaseBaseDest + { + } + public class BaseDest : BaseBaseDest { } + public class Dest : BaseDest { } - public abstract class BaseBaseDest - { - } - public class BaseDest : BaseBaseDest { } - public class Dest : BaseDest { } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().AfterMap((s, d) => afterMapCount++).BeforeMap((s, d)=>beforeMapCount++).Include().Include(); + cfg.CreateMap().Include(); + cfg.CreateMap(); + }); - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().AfterMap((s, d) => afterMapCount++).BeforeMap((s, d)=>beforeMapCount++).Include().Include(); - cfg.CreateMap().Include(); - cfg.CreateMap(); - }); + protected override void Because_of() + { + Mapper.Map(new Source()); + } - protected override void Because_of() - { - Mapper.Map(new Source()); - } + [Fact] + public void Should_call_AfterMap_just_once() + { + afterMapCount.ShouldBe(1); + beforeMapCount.ShouldBe(1); + } +} - [Fact] - public void Should_call_AfterMap_just_once() - { - afterMapCount.ShouldBe(1); - beforeMapCount.ShouldBe(1); - } +public class ShouldInheritBeforeAndAfterMapOnlyOnceIncludeBase : AutoMapperSpecBase +{ + int afterMapCount; + int beforeMapCount; + + public abstract class BaseBaseSource { } + public class BaseSource : BaseBaseSource + { + public string Foo { get; set; } } + public class Source : BaseSource { } - public class ShouldInheritBeforeAndAfterMapOnlyOnceIncludeBase : AutoMapperSpecBase + public abstract class BaseBaseDest { - int afterMapCount; - int beforeMapCount; + } + public class BaseDest : BaseBaseDest { } + public class Dest : BaseDest { } - public abstract class BaseBaseSource { } - public class BaseSource : BaseBaseSource - { - public string Foo { get; set; } - } - public class Source : BaseSource { } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().AfterMap((s, d) => afterMapCount++).BeforeMap((s, d) => beforeMapCount++); + cfg.CreateMap().IncludeBase(); + cfg.CreateMap().IncludeBase(); + }); - public abstract class BaseBaseDest - { - } - public class BaseDest : BaseBaseDest { } - public class Dest : BaseDest { } + protected override void Because_of() + { + Mapper.Map(new Source()); + } + + [Fact] + public void Should_call_AfterMap_just_once() + { + afterMapCount.ShouldBe(1); + beforeMapCount.ShouldBe(1); + } +} - protected override MapperConfiguration CreateConfiguration() => new(cfg => +public class ShouldInheritBeforeAndAfterMap +{ + public class BaseClass + { + public string Prop { get; set; } + } + public class Class : BaseClass {} + + public class BaseDto + { + public string DifferentProp { get; set; } + } + public class Dto : BaseDto {} + + [Fact] + public void should_inherit_base_beforemap() + { + // arrange + var source = new Class{ Prop = "test" }; + var configurationProvider = new MapperConfiguration(cfg => { - cfg.CreateMap().AfterMap((s, d) => afterMapCount++).BeforeMap((s, d) => beforeMapCount++); - cfg.CreateMap().IncludeBase(); - cfg.CreateMap().IncludeBase(); + cfg + .CreateMap() + .BeforeMap((s, d) => d.DifferentProp = s.Prop) + .Include(); + + cfg.CreateMap(); }); + var mappingEngine = configurationProvider.CreateMapper(); - protected override void Because_of() - { - Mapper.Map(new Source()); - } + // act + var dest = mappingEngine.Map(source); - [Fact] - public void Should_call_AfterMap_just_once() - { - afterMapCount.ShouldBe(1); - beforeMapCount.ShouldBe(1); - } + // assert + "test".ShouldBe(dest.DifferentProp); } - public class ShouldInheritBeforeAndAfterMap + [Fact] + public void should_inherit_base_aftermap() { - public class BaseClass + // arrange + var source = new Class { Prop = "test" }; + var configurationProvider = new MapperConfiguration(cfg => { - public string Prop { get; set; } - } - public class Class : BaseClass {} + cfg + .CreateMap() + .AfterMap((s, d) => d.DifferentProp = s.Prop) + .Include(); - public class BaseDto - { - public string DifferentProp { get; set; } - } - public class Dto : BaseDto {} + cfg.CreateMap(); + }); + var mappingEngine = configurationProvider.CreateMapper(); - [Fact] - public void should_inherit_base_beforemap() - { - // arrange - var source = new Class{ Prop = "test" }; - var configurationProvider = new MapperConfiguration(cfg => - { - cfg - .CreateMap() - .BeforeMap((s, d) => d.DifferentProp = s.Prop) - .Include(); - - cfg.CreateMap(); - }); - var mappingEngine = configurationProvider.CreateMapper(); - - // act - var dest = mappingEngine.Map(source); - - // assert - "test".ShouldBe(dest.DifferentProp); - } - - [Fact] - public void should_inherit_base_aftermap() - { - // arrange - var source = new Class { Prop = "test" }; - var configurationProvider = new MapperConfiguration(cfg => - { - cfg - .CreateMap() - .AfterMap((s, d) => d.DifferentProp = s.Prop) - .Include(); - - cfg.CreateMap(); - }); - var mappingEngine = configurationProvider.CreateMapper(); - - // act - var dest = mappingEngine.Map(source); - - // assert - "test".ShouldBe(dest.DifferentProp); - } + // act + var dest = mappingEngine.Map(source); + + // assert + "test".ShouldBe(dest.DifferentProp); } } \ No newline at end of file diff --git a/src/UnitTests/MappingInheritance/ShouldSupportOnlyDestinationTypeBeingDerived.cs b/src/UnitTests/MappingInheritance/ShouldSupportOnlyDestinationTypeBeingDerived.cs index 8986d1471f..9608ce9ce5 100644 --- a/src/UnitTests/MappingInheritance/ShouldSupportOnlyDestinationTypeBeingDerived.cs +++ b/src/UnitTests/MappingInheritance/ShouldSupportOnlyDestinationTypeBeingDerived.cs @@ -2,227 +2,226 @@ using Shouldly; using Xunit; -namespace AutoMapper.UnitTests.MappingInheritance +namespace AutoMapper.UnitTests.MappingInheritance; + +public class AsWithMissingMap : NonValidatingSpecBase { - public class AsWithMissingMap : NonValidatingSpecBase + interface TInterface { - interface TInterface - { - string Value { get; set; } - } - class TConcrete : TInterface - { - public string Value { get; set; } - } - class TModel - { - public string Value { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.CreateMap().As()); - [Fact] - public void Should_report_missing_map() => new Action(AssertConfigurationIsValid).ShouldThrow().Message.ShouldBe( - "Missing map from AutoMapper.UnitTests.MappingInheritance.AsWithMissingMap+TModel to AutoMapper.UnitTests.MappingInheritance.AsWithMissingMap+TConcrete. Create using CreateMap."); + string Value { get; set; } } - public class AsShouldWorkOnlyWithDerivedTypesWithGenerics : AutoMapperSpecBase + class TConcrete : TInterface { - class Source - { - } + public string Value { get; set; } + } + class TModel + { + public string Value { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.CreateMap().As()); + [Fact] + public void Should_report_missing_map() => new Action(AssertConfigurationIsValid).ShouldThrow().Message.ShouldBe( + "Missing map from AutoMapper.UnitTests.MappingInheritance.AsWithMissingMap+TModel to AutoMapper.UnitTests.MappingInheritance.AsWithMissingMap+TConcrete. Create using CreateMap."); +} +public class AsShouldWorkOnlyWithDerivedTypesWithGenerics : AutoMapperSpecBase +{ + class Source + { + } - class Destination - { - } + class Destination + { + } - class Override : Destination - { - } + class Override : Destination + { + } - protected override MapperConfiguration CreateConfiguration() => new(c => - { - c.CreateMap(typeof(Source<>), typeof(Override<>)); - c.CreateMap(typeof(Source<>), typeof(Destination<>)).As(typeof(Override<>)); - }); - [Fact] - public void Validate() => AssertConfigurationIsValid(); + protected override MapperConfiguration CreateConfiguration() => new(c => + { + c.CreateMap(typeof(Source<>), typeof(Override<>)); + c.CreateMap(typeof(Source<>), typeof(Destination<>)).As(typeof(Override<>)); + }); + [Fact] + public void Validate() => AssertConfigurationIsValid(); +} + +public class AsShouldWorkOnlyWithDerivedTypes +{ + class Source + { } - public class AsShouldWorkOnlyWithDerivedTypes + class Destination { - class Source - { - } + } - class Destination + [Fact] + public void Should_detect_unrelated_override() + { + new Action(() => new MapperConfiguration(c => c.CreateMap(typeof(Source), typeof(Destination)).As(typeof(Source)))).ShouldThrowException(ex => { - } + ex.Message.ShouldStartWith($"{typeof(Source)} is not derived from {typeof(Destination)}."); + }); + } +} - [Fact] - public void Should_detect_unrelated_override() - { - new Action(() => new MapperConfiguration(c => c.CreateMap(typeof(Source), typeof(Destination)).As(typeof(Source)))).ShouldThrowException(ex => - { - ex.Message.ShouldStartWith($"{typeof(Source)} is not derived from {typeof(Destination)}."); - }); - } +public class DestinationTypePolymorphismTest +{ + public class Customer + { + public int Id { get; set; } + public string Name { get; set; } } - public class DestinationTypePolymorphismTest + public class CustomerStubDTO { - public class Customer - { - public int Id { get; set; } - public string Name { get; set; } - } + public int Id { get; set; } + } - public class CustomerStubDTO - { - public int Id { get; set; } - } + public class CustomerDTO : CustomerStubDTO + { + public string Name { get; set; } + } - public class CustomerDTO : CustomerStubDTO - { - public string Name { get; set; } - } + public class Order + { + public Customer Customer { get; set; } + } - public class Order - { - public Customer Customer { get; set; } - } + public class OrderDTO + { + public CustomerStubDTO Customer { get; set; } + } - public class OrderDTO - { - public CustomerStubDTO Customer { get; set; } - } + [Fact] + public void Mapper_Should_Allow_Overriding_Of_Destination_Type() + { + var order = new Order() { Customer = new Customer() { Id = 1, Name = "A" } }; - [Fact] - public void Mapper_Should_Allow_Overriding_Of_Destination_Type() + var config = new MapperConfiguration(cfg => { - var order = new Order() { Customer = new Customer() { Id = 1, Name = "A" } }; + cfg.CreateMap(); + cfg.CreateMap(); + cfg.CreateMap().As(); + }); + var orderDto = config.CreateMapper().Map(order); - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap(); - cfg.CreateMap(); - cfg.CreateMap().As(); - }); - var orderDto = config.CreateMapper().Map(order); + var customerDto = (CustomerDTO)orderDto.Customer; + "A".ShouldBe(customerDto.Name); + 1.ShouldBe(customerDto.Id); - var customerDto = (CustomerDTO)orderDto.Customer; - "A".ShouldBe(customerDto.Name); - 1.ShouldBe(customerDto.Id); + } - } +} +public class DestinationTypePolymorphismTestNonGeneric +{ + public class Customer + { + public int Id { get; set; } + public string Name { get; set; } + } + public class CustomerStubDTO + { + public int Id { get; set; } } - public class DestinationTypePolymorphismTestNonGeneric + + public class CustomerDTO : CustomerStubDTO { - public class Customer - { - public int Id { get; set; } - public string Name { get; set; } - } + public string Name { get; set; } + } - public class CustomerStubDTO - { - public int Id { get; set; } - } + public class Order + { + public Customer Customer { get; set; } + } - public class CustomerDTO : CustomerStubDTO - { - public string Name { get; set; } - } + public class OrderDTO + { + public CustomerStubDTO Customer { get; set; } + } - public class Order - { - public Customer Customer { get; set; } - } - public class OrderDTO + [Fact] + public void Mapper_Should_Allow_Overriding_Of_Destination_Type() + { + var order = new Order() { Customer = new Customer() { Id = 1, Name = "A" } }; + var config = new MapperConfiguration(cfg => { - public CustomerStubDTO Customer { get; set; } - } + cfg.CreateMap(typeof(Order), typeof(OrderDTO)); + cfg.CreateMap(typeof(Customer), typeof(CustomerDTO)); + cfg.CreateMap(typeof(Customer), typeof(CustomerStubDTO)).As(typeof(CustomerDTO)); + }); + var orderDto = config.CreateMapper().Map(order); + var customerDto = (CustomerDTO)orderDto.Customer; + "A".ShouldBe(customerDto.Name); + 1.ShouldBe(customerDto.Id); - [Fact] - public void Mapper_Should_Allow_Overriding_Of_Destination_Type() - { - var order = new Order() { Customer = new Customer() { Id = 1, Name = "A" } }; - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap(typeof(Order), typeof(OrderDTO)); - cfg.CreateMap(typeof(Customer), typeof(CustomerDTO)); - cfg.CreateMap(typeof(Customer), typeof(CustomerStubDTO)).As(typeof(CustomerDTO)); - }); - var orderDto = config.CreateMapper().Map(order); + } - var customerDto = (CustomerDTO)orderDto.Customer; - "A".ShouldBe(customerDto.Name); - 1.ShouldBe(customerDto.Id); +} - } +public class AsWithGenerics : AutoMapperSpecBase +{ + INodeModel _destination; + public interface INodeModel : INodeModel where T : struct + { + new T? ID { get; set; } } - public class AsWithGenerics : AutoMapperSpecBase + public interface INodeModel { - INodeModel _destination; - - public interface INodeModel : INodeModel where T : struct - { - new T? ID { get; set; } - } + object ID { get; set; } + string Name { get; set; } + } - public interface INodeModel - { - object ID { get; set; } - string Name { get; set; } - } + public class NodeModel : INodeModel where T : struct + { + public T? ID { get; set; } + public string Name { get; set; } - public class NodeModel : INodeModel where T : struct + object INodeModel.ID { - public T? ID { get; set; } - public string Name { get; set; } + get + { + return ID; + } - object INodeModel.ID + set { - get - { - return ID; - } - - set - { - ID = value as T?; - } + ID = value as T?; } } + } - public class NodeDto where T : struct - { - public T? ID { get; set; } - public string Name { get; set; } - } + public class NodeDto where T : struct + { + public T? ID { get; set; } + public string Name { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(typeof(NodeDto<>), typeof(NodeModel<>)); - cfg.CreateMap(typeof(NodeDto<>), typeof(INodeModel<>)).As(typeof(NodeModel<>)); - cfg.CreateMap(typeof(INodeModel<>), typeof(NodeModel<>)); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(typeof(NodeDto<>), typeof(NodeModel<>)); + cfg.CreateMap(typeof(NodeDto<>), typeof(INodeModel<>)).As(typeof(NodeModel<>)); + cfg.CreateMap(typeof(INodeModel<>), typeof(NodeModel<>)); + }); - protected override void Because_of() - { - var dto = new NodeDto { ID = 1, Name = "Hi" }; - _destination = Mapper.Map>(dto); - } + protected override void Because_of() + { + var dto = new NodeDto { ID = 1, Name = "Hi" }; + _destination = Mapper.Map>(dto); + } - [Fact] - public void Should_override_the_map() - { - _destination.ShouldBeOfType>(); - _destination.ID.ShouldBe(1); - _destination.Name.ShouldBe("Hi"); - } + [Fact] + public void Should_override_the_map() + { + _destination.ShouldBeOfType>(); + _destination.ID.ShouldBe(1); + _destination.Name.ShouldBe("Hi"); } } diff --git a/src/UnitTests/MappingInheritance/SourceValidationWithInheritance.cs b/src/UnitTests/MappingInheritance/SourceValidationWithInheritance.cs index 8c574968ba..311ee4ac59 100644 --- a/src/UnitTests/MappingInheritance/SourceValidationWithInheritance.cs +++ b/src/UnitTests/MappingInheritance/SourceValidationWithInheritance.cs @@ -1,127 +1,126 @@ using System; using Xunit; -namespace AutoMapper.UnitTests +namespace AutoMapper.UnitTests; + +public class SourceValidationWithInheritance : AutoMapperSpecBase +{ + public abstract class FormElement2 + { + public Guid Id { get; set; } + public int Order { get; set; } + } + + public abstract class FieldControl2 : FormElement2 + { + public string Label { get; set; } + public string Trailer { get; set; } + public bool Misspelled { get; set; } + } + + public abstract class TextFieldControl2 : FieldControl2 + { + public string DefaultValue { get; set; } + public int Size { get; set; } + } + + public class TextBoxControl2 : TextFieldControl2 + { + public int Rows { get; set; } + } + + public abstract class FormControlBaseDTO2 + { + public Guid Id { get; set; } + public int Order { get; set; } + } + + public class FormElementDTO2 : FormControlBaseDTO2 + { + public int ElementType { get; set; } + public string Label { get; set; } + public string Trailer { get; set; } + + public string DefaultValue { get; set; } + public int Size { get; set; } + public int Rows { get; set; } + + public bool Prepopulate { get; set; } + } + + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(MemberList.Source) + .Include(); + + cfg.CreateMap(MemberList.Source) + .ForMember(dto => dto.Prepopulate, opt => opt.MapFrom(src => src.Misspelled)) + .Include(); + + cfg.CreateMap(MemberList.Source) + .ForMember(dto => dto.ElementType, opt => opt.MapFrom(src => 0)); + }); + [Fact] + public void Validate() => AssertConfigurationIsValid(); +} + +public class SourceValidationWithIgnore: AutoMapperSpecBase { - public class SourceValidationWithInheritance : AutoMapperSpecBase + public abstract class FormElement2 + { + public Guid Id { get; set; } + public int Order { get; set; } + } + + public abstract class FieldControl2 : FormElement2 + { + public string Label { get; set; } + public string Trailer { get; set; } + public bool Misspelled { get; set; } + } + + public abstract class TextFieldControl2 : FieldControl2 { - public abstract class FormElement2 - { - public Guid Id { get; set; } - public int Order { get; set; } - } - - public abstract class FieldControl2 : FormElement2 - { - public string Label { get; set; } - public string Trailer { get; set; } - public bool Misspelled { get; set; } - } - - public abstract class TextFieldControl2 : FieldControl2 - { - public string DefaultValue { get; set; } - public int Size { get; set; } - } - - public class TextBoxControl2 : TextFieldControl2 - { - public int Rows { get; set; } - } - - public abstract class FormControlBaseDTO2 - { - public Guid Id { get; set; } - public int Order { get; set; } - } - - public class FormElementDTO2 : FormControlBaseDTO2 - { - public int ElementType { get; set; } - public string Label { get; set; } - public string Trailer { get; set; } - - public string DefaultValue { get; set; } - public int Size { get; set; } - public int Rows { get; set; } - - public bool Prepopulate { get; set; } - } - - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(MemberList.Source) - .Include(); - - cfg.CreateMap(MemberList.Source) - .ForMember(dto => dto.Prepopulate, opt => opt.MapFrom(src => src.Misspelled)) - .Include(); - - cfg.CreateMap(MemberList.Source) - .ForMember(dto => dto.ElementType, opt => opt.MapFrom(src => 0)); - }); - [Fact] - public void Validate() => AssertConfigurationIsValid(); + public string DefaultValue { get; set; } + public int Size { get; set; } } - public class SourceValidationWithIgnore: AutoMapperSpecBase + public class TextBoxControl2 : TextFieldControl2 { - public abstract class FormElement2 - { - public Guid Id { get; set; } - public int Order { get; set; } - } - - public abstract class FieldControl2 : FormElement2 - { - public string Label { get; set; } - public string Trailer { get; set; } - public bool Misspelled { get; set; } - } - - public abstract class TextFieldControl2 : FieldControl2 - { - public string DefaultValue { get; set; } - public int Size { get; set; } - } - - public class TextBoxControl2 : TextFieldControl2 - { - public int Rows { get; set; } - } - - public abstract class FormControlBaseDTO2 - { - public Guid Id { get; set; } - public int Order { get; set; } - } - - public class FormElementDTO2 : FormControlBaseDTO2 - { - public int ElementType { get; set; } - public string Label { get; set; } - public string Trailer { get; set; } - - public string DefaultValue { get; set; } - public int Size { get; set; } - public int Rows { get; set; } - - public bool Prepopulate { get; set; } - } - - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(MemberList.Source) - .Include(); - - cfg.CreateMap(MemberList.Source) - .ForSourceMember(src => src.Misspelled, o=>o.DoNotValidate()) - .Include(); - - cfg.CreateMap(MemberList.Source) - .ForMember(dto => dto.ElementType, opt => opt.MapFrom(src => 0)); - }); - [Fact] - public void Validate() => AssertConfigurationIsValid(); + public int Rows { get; set; } } + + public abstract class FormControlBaseDTO2 + { + public Guid Id { get; set; } + public int Order { get; set; } + } + + public class FormElementDTO2 : FormControlBaseDTO2 + { + public int ElementType { get; set; } + public string Label { get; set; } + public string Trailer { get; set; } + + public string DefaultValue { get; set; } + public int Size { get; set; } + public int Rows { get; set; } + + public bool Prepopulate { get; set; } + } + + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(MemberList.Source) + .Include(); + + cfg.CreateMap(MemberList.Source) + .ForSourceMember(src => src.Misspelled, o=>o.DoNotValidate()) + .Include(); + + cfg.CreateMap(MemberList.Source) + .ForMember(dto => dto.ElementType, opt => opt.MapFrom(src => 0)); + }); + [Fact] + public void Validate() => AssertConfigurationIsValid(); } \ No newline at end of file diff --git a/src/UnitTests/MaxDepthTests.cs b/src/UnitTests/MaxDepthTests.cs index a4b2f775c4..1c1259eed9 100644 --- a/src/UnitTests/MaxDepthTests.cs +++ b/src/UnitTests/MaxDepthTests.cs @@ -4,104 +4,103 @@ using Shouldly; using Xunit; -namespace AutoMapper.UnitTests +namespace AutoMapper.UnitTests; + +public class MaxDepthTests { - public class MaxDepthTests + public class Source { - public class Source - { - public int Level { get; set; } - public IList Children { get; set; } - public Source Parent { get; set; } - - public Source(int level) - { - Children = new List(); - Level = level; - } + public int Level { get; set; } + public IList Children { get; set; } + public Source Parent { get; set; } - public void AddChild(Source child) - { - Children.Add(child); - child.Parent = this; - } + public Source(int level) + { + Children = new List(); + Level = level; } - public class Destination + public void AddChild(Source child) { - public int Level { get; set; } - public IList Children { get; set; } - public Destination Parent { get; set; } + Children.Add(child); + child.Parent = this; } + } - private readonly Source _source; + public class Destination + { + public int Level { get; set; } + public IList Children { get; set; } + public Destination Parent { get; set; } + } - public MaxDepthTests() - { - var nest = new Source(1); + private readonly Source _source; - nest.AddChild(new Source(2)); - nest.Children[0].AddChild(new Source(3)); - nest.Children[0].AddChild(new Source(3)); - nest.Children[0].Children[1].AddChild(new Source(4)); - nest.Children[0].Children[1].AddChild(new Source(4)); - nest.Children[0].Children[1].AddChild(new Source(4)); + public MaxDepthTests() + { + var nest = new Source(1); - nest.AddChild(new Source(2)); - nest.Children[1].AddChild(new Source(3)); + nest.AddChild(new Source(2)); + nest.Children[0].AddChild(new Source(3)); + nest.Children[0].AddChild(new Source(3)); + nest.Children[0].Children[1].AddChild(new Source(4)); + nest.Children[0].Children[1].AddChild(new Source(4)); + nest.Children[0].Children[1].AddChild(new Source(4)); - nest.AddChild(new Source(2)); - nest.Children[2].AddChild(new Source(3)); + nest.AddChild(new Source(2)); + nest.Children[1].AddChild(new Source(3)); - _source = nest; - } + nest.AddChild(new Source(2)); + nest.Children[2].AddChild(new Source(3)); - [Fact] - public void Second_level_children_is_empty_with_max_depth_1() - { - var config = new MapperConfiguration(cfg => cfg.CreateMap().MaxDepth(1)); - var destination = config.CreateMapper().Map(_source); - destination.Children.ShouldBeEmpty(); - } + _source = nest; + } - [Fact] - public void Second_level_children_are_not_null_with_max_depth_2() + [Fact] + public void Second_level_children_is_empty_with_max_depth_1() + { + var config = new MapperConfiguration(cfg => cfg.CreateMap().MaxDepth(1)); + var destination = config.CreateMapper().Map(_source); + destination.Children.ShouldBeEmpty(); + } + + [Fact] + public void Second_level_children_are_not_null_with_max_depth_2() + { + var config = new MapperConfiguration(cfg => cfg.CreateMap().MaxDepth(2)); + var destination = config.CreateMapper().Map(_source); + foreach (var child in destination.Children) { - var config = new MapperConfiguration(cfg => cfg.CreateMap().MaxDepth(2)); - var destination = config.CreateMapper().Map(_source); - foreach (var child in destination.Children) - { - 2.ShouldBe(child.Level); - child.ShouldNotBeNull(); - destination.ShouldBe(child.Parent); - } + 2.ShouldBe(child.Level); + child.ShouldNotBeNull(); + destination.ShouldBe(child.Parent); } + } - [Fact] - public void Third_level_children_is_empty_with_max_depth_2() + [Fact] + public void Third_level_children_is_empty_with_max_depth_2() + { + var config = new MapperConfiguration(cfg => cfg.CreateMap().MaxDepth(2)); + var destination = config.CreateMapper().Map(_source); + foreach (var child in destination.Children) { - var config = new MapperConfiguration(cfg => cfg.CreateMap().MaxDepth(2)); - var destination = config.CreateMapper().Map(_source); - foreach (var child in destination.Children) - { - child.Children.ShouldBeEmpty(); - } + child.Children.ShouldBeEmpty(); } + } - [Fact] - public void Third_level_children_are_not_null_max_depth_3() + [Fact] + public void Third_level_children_are_not_null_max_depth_3() + { + var config = new MapperConfiguration(cfg => cfg.CreateMap().MaxDepth(3)); + var destination = config.CreateMapper().Map(_source); + foreach (var child in destination.Children) { - var config = new MapperConfiguration(cfg => cfg.CreateMap().MaxDepth(3)); - var destination = config.CreateMapper().Map(_source); - foreach (var child in destination.Children) + child.Children.ShouldNotBeNull(); + foreach (var subChild in child.Children) { - child.Children.ShouldNotBeNull(); - foreach (var subChild in child.Children) - { - 3.ShouldBe(subChild.Level); - subChild.Children.ShouldNotBeNull(); - child.ShouldBe(subChild.Parent); - } + 3.ShouldBe(subChild.Level); + subChild.Children.ShouldNotBeNull(); + child.ShouldBe(subChild.Parent); } } } diff --git a/src/UnitTests/MaxExecutionPlanDepth.cs b/src/UnitTests/MaxExecutionPlanDepth.cs index fdc6ee477d..71182b1853 100644 --- a/src/UnitTests/MaxExecutionPlanDepth.cs +++ b/src/UnitTests/MaxExecutionPlanDepth.cs @@ -5,327 +5,326 @@ using Shouldly; using AutoMapper.Internal; -namespace AutoMapper.UnitTests +namespace AutoMapper.UnitTests; + +public class MaxExecutionPlanDepth : AutoMapperSpecBase +{ + class Source + { + public Source1 Inner { get; set; } + } + + class Source1 + { + public Source2 Inner { get; set; } + } + + class Source2 + { + public Source3 Inner { get; set; } + } + + class Source3 + { + public Source4 Inner { get; set; } + } + + class Source4 + { + public Source5 Inner { get; set; } + } + + class Source5 + { + public Source6 Inner { get; set; } + } + + class Source6 + { + public int Value { get; set; } + } + + class Destination + { + public Destination1 Inner { get; set; } + } + + class Destination1 + { + public Destination2 Inner { get; set; } + } + + class Destination2 + { + public Destination3 Inner { get; set; } + } + + class Destination3 + { + public Destination4 Inner { get; set; } + } + + class Destination4 + { + public Destination5 Inner { get; set; } + } + + class Destination5 + { + public Destination6 Inner { get; set; } + } + + class Destination6 + { + public int Value { get; set; } + } + + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.Internal().MaxExecutionPlanDepth = 2; + cfg.CreateMap(); + cfg.CreateMap(); + cfg.CreateMap(); + cfg.CreateMap(); + cfg.CreateMap(); + cfg.CreateMap(); + cfg.CreateMap(); + }); + [Fact] + public void Should_set_inline_accordingly() + { + TypeMap map; + map = FindTypeMapFor(); + map.PropertyMaps.First().Inline.ShouldBeTrue(); + map = FindTypeMapFor(); + map.PropertyMaps.First().Inline.ShouldBeTrue(); + map = FindTypeMapFor(); + map.PropertyMaps.First().Inline.ShouldBeFalse(); + map = FindTypeMapFor(); + map.PropertyMaps.First().Inline.ShouldBeFalse(); + map = FindTypeMapFor(); + map.PropertyMaps.First().Inline.ShouldBeFalse(); + map = FindTypeMapFor(); + map.PropertyMaps.First().Inline.ShouldBeFalse(); + map = FindTypeMapFor(); + map.PropertyMaps.First().Inline.ShouldBeTrue(); + } +} +public class MaxExecutionPlanDepthDefault : AutoMapperSpecBase +{ + class Source + { + public Source1 Inner { get; set; } + } + + class Source1 + { + public Source2 Inner { get; set; } + } + + class Source2 + { + public Source3 Inner { get; set; } + } + + class Source3 + { + public Source4 Inner { get; set; } + } + + class Source4 + { + public Source5 Inner { get; set; } + } + + class Source5 + { + public Source6 Inner { get; set; } + } + + class Source6 + { + public int Value { get; set; } + } + + class Destination + { + public Destination1 Inner { get; set; } + } + + class Destination1 + { + public Destination2 Inner { get; set; } + } + + class Destination2 + { + public Destination3 Inner { get; set; } + } + + class Destination3 + { + public Destination4 Inner { get; set; } + } + + class Destination4 + { + public Destination5 Inner { get; set; } + } + + class Destination5 + { + public Destination6 Inner { get; set; } + } + + class Destination6 + { + public int Value { get; set; } + } + + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + cfg.CreateMap(); + cfg.CreateMap(); + cfg.CreateMap(); + cfg.CreateMap(); + cfg.CreateMap(); + cfg.CreateMap(); + }); + [Fact] + public void Should_set_inline_accordingly() + { + TypeMap map; + map = FindTypeMapFor(); + map.PropertyMaps.First().Inline.ShouldBeTrue(); + map = FindTypeMapFor(); + map.PropertyMaps.First().Inline.ShouldBeFalse(); + map = FindTypeMapFor(); + map.PropertyMaps.First().Inline.ShouldBeFalse(); + map = FindTypeMapFor(); + map.PropertyMaps.First().Inline.ShouldBeFalse(); + map = FindTypeMapFor(); + map.PropertyMaps.First().Inline.ShouldBeFalse(); + map = FindTypeMapFor(); + map.PropertyMaps.First().Inline.ShouldBeFalse(); + map = FindTypeMapFor(); + map.PropertyMaps.First().Inline.ShouldBeTrue(); + } +} +public class MaxExecutionPlanDepthWithPreserveReferences : AutoMapperSpecBase { - public class MaxExecutionPlanDepth : AutoMapperSpecBase - { - class Source - { - public Source1 Inner { get; set; } - } - - class Source1 - { - public Source2 Inner { get; set; } - } - - class Source2 - { - public Source3 Inner { get; set; } - } - - class Source3 - { - public Source4 Inner { get; set; } - } - - class Source4 - { - public Source5 Inner { get; set; } - } - - class Source5 - { - public Source6 Inner { get; set; } - } - - class Source6 - { - public int Value { get; set; } - } - - class Destination - { - public Destination1 Inner { get; set; } - } - - class Destination1 - { - public Destination2 Inner { get; set; } - } - - class Destination2 - { - public Destination3 Inner { get; set; } - } - - class Destination3 - { - public Destination4 Inner { get; set; } - } - - class Destination4 - { - public Destination5 Inner { get; set; } - } - - class Destination5 - { - public Destination6 Inner { get; set; } - } - - class Destination6 - { - public int Value { get; set; } - } - - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.Internal().MaxExecutionPlanDepth = 2; - cfg.CreateMap(); - cfg.CreateMap(); - cfg.CreateMap(); - cfg.CreateMap(); - cfg.CreateMap(); - cfg.CreateMap(); - cfg.CreateMap(); - }); - [Fact] - public void Should_set_inline_accordingly() - { - TypeMap map; - map = FindTypeMapFor(); - map.PropertyMaps.First().Inline.ShouldBeTrue(); - map = FindTypeMapFor(); - map.PropertyMaps.First().Inline.ShouldBeTrue(); - map = FindTypeMapFor(); - map.PropertyMaps.First().Inline.ShouldBeFalse(); - map = FindTypeMapFor(); - map.PropertyMaps.First().Inline.ShouldBeFalse(); - map = FindTypeMapFor(); - map.PropertyMaps.First().Inline.ShouldBeFalse(); - map = FindTypeMapFor(); - map.PropertyMaps.First().Inline.ShouldBeFalse(); - map = FindTypeMapFor(); - map.PropertyMaps.First().Inline.ShouldBeTrue(); - } - } - public class MaxExecutionPlanDepthDefault : AutoMapperSpecBase - { - class Source - { - public Source1 Inner { get; set; } - } - - class Source1 - { - public Source2 Inner { get; set; } - } - - class Source2 - { - public Source3 Inner { get; set; } - } - - class Source3 - { - public Source4 Inner { get; set; } - } - - class Source4 - { - public Source5 Inner { get; set; } - } - - class Source5 - { - public Source6 Inner { get; set; } - } - - class Source6 - { - public int Value { get; set; } - } - - class Destination - { - public Destination1 Inner { get; set; } - } - - class Destination1 - { - public Destination2 Inner { get; set; } - } - - class Destination2 - { - public Destination3 Inner { get; set; } - } - - class Destination3 - { - public Destination4 Inner { get; set; } - } - - class Destination4 - { - public Destination5 Inner { get; set; } - } - - class Destination5 - { - public Destination6 Inner { get; set; } - } - - class Destination6 - { - public int Value { get; set; } - } - - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - cfg.CreateMap(); - cfg.CreateMap(); - cfg.CreateMap(); - cfg.CreateMap(); - cfg.CreateMap(); - cfg.CreateMap(); - }); - [Fact] - public void Should_set_inline_accordingly() - { - TypeMap map; - map = FindTypeMapFor(); - map.PropertyMaps.First().Inline.ShouldBeTrue(); - map = FindTypeMapFor(); - map.PropertyMaps.First().Inline.ShouldBeFalse(); - map = FindTypeMapFor(); - map.PropertyMaps.First().Inline.ShouldBeFalse(); - map = FindTypeMapFor(); - map.PropertyMaps.First().Inline.ShouldBeFalse(); - map = FindTypeMapFor(); - map.PropertyMaps.First().Inline.ShouldBeFalse(); - map = FindTypeMapFor(); - map.PropertyMaps.First().Inline.ShouldBeFalse(); - map = FindTypeMapFor(); - map.PropertyMaps.First().Inline.ShouldBeTrue(); - } - } - public class MaxExecutionPlanDepthWithPreserveReferences : AutoMapperSpecBase - { - class Source - { - public Source1 Inner { get; set; } - } - - class Source1 - { - public Source2 Inner { get; set; } - } - - class Source2 - { - public Source3 Inner { get; set; } - } - - class Source3 - { - public Source4 Inner { get; set; } - } - - class Source4 - { - public Source5 Inner { get; set; } - } - - class Source5 - { - public Source6 Inner { get; set; } - } - - class Source6 - { - public int Value { get; set; } - } - - class Destination - { - public Destination1 Inner { get; set; } - } - - class Destination1 - { - public Destination2 Inner { get; set; } - } - - class Destination2 - { - public Destination3 Inner { get; set; } - } - - class Destination3 - { - public Destination4 Inner { get; set; } - } - - class Destination4 - { - public Destination5 Inner { get; set; } - } - - class Destination5 - { - public Destination6 Inner { get; set; } - } - - class Destination6 - { - public int Value { get; set; } - } - - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.Internal().MaxExecutionPlanDepth = 0; - cfg.CreateMap().PreserveReferences(); - cfg.CreateMap().PreserveReferences(); - cfg.CreateMap().PreserveReferences(); - cfg.CreateMap().PreserveReferences(); - cfg.CreateMap().PreserveReferences(); - cfg.CreateMap().PreserveReferences(); - cfg.CreateMap().PreserveReferences(); - }); - - [Fact] - public void Should_set_inline_accordingly() - { - TypeMap map; - map = FindTypeMapFor(); - map.PropertyMaps.First().Inline.ShouldBeFalse(); - map = FindTypeMapFor(); - map.PropertyMaps.First().Inline.ShouldBeFalse(); - map = FindTypeMapFor(); - map.PropertyMaps.First().Inline.ShouldBeFalse(); - map = FindTypeMapFor(); - map.PropertyMaps.First().Inline.ShouldBeFalse(); - map = FindTypeMapFor(); - map.PropertyMaps.First().Inline.ShouldBeFalse(); - map = FindTypeMapFor(); - map.PropertyMaps.First().Inline.ShouldBeFalse(); - } - } - public class InlineWithoutPreserveReferences : AutoMapperSpecBase - { - class Source - { - public Source Inner { get; set; } - } - class Destination - { - public Destination Inner { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.CreateMap()); - [Fact] - public void Should_set_inline_accordingly() => FindTypeMapFor().PropertyMaps.First().Inline.ShouldBeFalse(); + class Source + { + public Source1 Inner { get; set; } + } + + class Source1 + { + public Source2 Inner { get; set; } + } + + class Source2 + { + public Source3 Inner { get; set; } + } + + class Source3 + { + public Source4 Inner { get; set; } + } + + class Source4 + { + public Source5 Inner { get; set; } + } + + class Source5 + { + public Source6 Inner { get; set; } + } + + class Source6 + { + public int Value { get; set; } + } + + class Destination + { + public Destination1 Inner { get; set; } + } + + class Destination1 + { + public Destination2 Inner { get; set; } + } + + class Destination2 + { + public Destination3 Inner { get; set; } + } + + class Destination3 + { + public Destination4 Inner { get; set; } + } + + class Destination4 + { + public Destination5 Inner { get; set; } + } + + class Destination5 + { + public Destination6 Inner { get; set; } + } + + class Destination6 + { + public int Value { get; set; } + } + + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.Internal().MaxExecutionPlanDepth = 0; + cfg.CreateMap().PreserveReferences(); + cfg.CreateMap().PreserveReferences(); + cfg.CreateMap().PreserveReferences(); + cfg.CreateMap().PreserveReferences(); + cfg.CreateMap().PreserveReferences(); + cfg.CreateMap().PreserveReferences(); + cfg.CreateMap().PreserveReferences(); + }); + + [Fact] + public void Should_set_inline_accordingly() + { + TypeMap map; + map = FindTypeMapFor(); + map.PropertyMaps.First().Inline.ShouldBeFalse(); + map = FindTypeMapFor(); + map.PropertyMaps.First().Inline.ShouldBeFalse(); + map = FindTypeMapFor(); + map.PropertyMaps.First().Inline.ShouldBeFalse(); + map = FindTypeMapFor(); + map.PropertyMaps.First().Inline.ShouldBeFalse(); + map = FindTypeMapFor(); + map.PropertyMaps.First().Inline.ShouldBeFalse(); + map = FindTypeMapFor(); + map.PropertyMaps.First().Inline.ShouldBeFalse(); + } +} +public class InlineWithoutPreserveReferences : AutoMapperSpecBase +{ + class Source + { + public Source Inner { get; set; } + } + class Destination + { + public Destination Inner { get; set; } } + protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.CreateMap()); + [Fact] + public void Should_set_inline_accordingly() => FindTypeMapFor().PropertyMaps.First().Inline.ShouldBeFalse(); } \ No newline at end of file diff --git a/src/UnitTests/MemberNameReplacers.cs b/src/UnitTests/MemberNameReplacers.cs index 869d4b360c..3a394899ce 100644 --- a/src/UnitTests/MemberNameReplacers.cs +++ b/src/UnitTests/MemberNameReplacers.cs @@ -4,50 +4,49 @@ using System.Text; using Xunit; -namespace AutoMapper.UnitTests +namespace AutoMapper.UnitTests; + +public class When_using_a_member_name_replacer : NonValidatingSpecBase { - public class When_using_a_member_name_replacer : NonValidatingSpecBase + public class Source { - public class Source - { - public int Value { get; set; } - public int Ävíator { get; set; } - public int SubAirlinaFlight { get; set; } - } + public int Value { get; set; } + public int Ävíator { get; set; } + public int SubAirlinaFlight { get; set; } + } + + public class Destination + { + public int Value { get; set; } + public int Aviator { get; set; } + public int SubAirlineFlight { get; set; } + } - public class Destination + [Fact] + public void Should_map_properties_with_different_names() + { + var config = new MapperConfiguration(c => { - public int Value { get; set; } - public int Aviator { get; set; } - public int SubAirlineFlight { get; set; } - } + c.ReplaceMemberName("Ä", "A"); + c.ReplaceMemberName("í", "i"); + c.ReplaceMemberName("Airlina", "Airline"); + c.CreateMap(); + }); - [Fact] - public void Should_map_properties_with_different_names() + var source = new Source() { - var config = new MapperConfiguration(c => - { - c.ReplaceMemberName("Ä", "A"); - c.ReplaceMemberName("í", "i"); - c.ReplaceMemberName("Airlina", "Airline"); - c.CreateMap(); - }); - - var source = new Source() - { - Value = 5, - Ävíator = 3, - SubAirlinaFlight = 4 - }; - - //Mapper.AddMemberConvention().AddName(_ => _.AddReplace("A", "Ä").AddReplace("i", "í").AddReplace("Airline", "Airlina")).SetMemberInfo(); - var mapper = config.CreateMapper(); - var destination = mapper.Map(source); - - Assert.Equal(source.Value, destination.Value); - Assert.Equal(source.Ävíator, destination.Aviator); - Assert.Equal(source.SubAirlinaFlight, destination.SubAirlineFlight); - } - } + Value = 5, + Ävíator = 3, + SubAirlinaFlight = 4 + }; + + //Mapper.AddMemberConvention().AddName(_ => _.AddReplace("A", "Ä").AddReplace("i", "í").AddReplace("Airline", "Airlina")).SetMemberInfo(); + var mapper = config.CreateMapper(); + var destination = mapper.Map(source); + Assert.Equal(source.Value, destination.Value); + Assert.Equal(source.Ävíator, destination.Aviator); + Assert.Equal(source.SubAirlinaFlight, destination.SubAirlineFlight); + } } + diff --git a/src/UnitTests/NullBehavior.cs b/src/UnitTests/NullBehavior.cs index dcf4879285..59e8ee79ed 100644 --- a/src/UnitTests/NullBehavior.cs +++ b/src/UnitTests/NullBehavior.cs @@ -6,1115 +6,1114 @@ using System.Collections; using System; -namespace AutoMapper.UnitTests.NullBehavior +namespace AutoMapper.UnitTests.NullBehavior; + +public class NullCheckDefault : AutoMapperSpecBase { - public class NullCheckDefault : AutoMapperSpecBase + class Source { - class Source - { - public string Value { get; } - } - class Destination - { - public int Length { get; set; } = 42; - } - protected override MapperConfiguration CreateConfiguration() => new(c => - c.CreateMap().ForMember(d => d.Length, o => o.MapFrom(s => s.Value.Length))); - [Fact] - public void Should_be_default() => Map(new Source()).Length.ShouldBe(0); + public string Value { get; } } - public class When_mappping_null_with_DoNotAllowNull : AutoMapperSpecBase + class Destination { - class Source - { - public InnerSource Inner { get; set; } - public int[] Collection { get; set; } - } - public class InnerSource - { - public int Integer { get; set; } - } - class Destination - { - public InnerDestination Inner { get; set; } - public int[] Collection { get; set; } - } - public class InnerDestination - { - public int Integer { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().ForAllMembers(o => o.DoNotAllowNull()); - cfg.CreateMap(); - cfg.AllowNullDestinationValues = true; - cfg.AllowNullCollections = true; - }); - [Fact] - public void Should_map_to_non_null() - { - var destination = Mapper.Map(new Source()); - destination.Collection.ShouldNotBeNull(); - destination.Inner.ShouldNotBeNull(); - } + public int Length { get; set; } = 42; } - public class When_mappping_null_with_AllowNull : AutoMapperSpecBase + protected override MapperConfiguration CreateConfiguration() => new(c => + c.CreateMap().ForMember(d => d.Length, o => o.MapFrom(s => s.Value.Length))); + [Fact] + public void Should_be_default() => Map(new Source()).Length.ShouldBe(0); +} +public class When_mappping_null_with_DoNotAllowNull : AutoMapperSpecBase +{ + class Source { - class Source - { - public InnerSource Inner { get; set; } - public int[] Collection { get; set; } - } - public class InnerSource - { - public int Integer { get; set; } - } - class Destination - { - public InnerDestination Inner { get; set; } - public int[] Collection { get; set; } - } - public class InnerDestination - { - public int Integer { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().ForAllMembers(o=>o.AllowNull()); - cfg.CreateMap(); - cfg.AllowNullDestinationValues = false; - cfg.AllowNullCollections = false; - }); - [Fact] - public void Should_map_to_null() - { - var destination = Mapper.Map(new Source()); - destination.Collection.ShouldBeNull(); - destination.Inner.ShouldBeNull(); - } + public InnerSource Inner { get; set; } + public int[] Collection { get; set; } } - public class When_mappping_null_with_AllowNull_and_inheritance : AutoMapperSpecBase + public class InnerSource { - class Source - { - public InnerSource Inner { get; set; } - public int[] Collection { get; set; } - } - class SourceDerived : Source - { - } - public class InnerSource - { - public int Integer { get; set; } - } - class Destination - { - public InnerDestination Inner { get; set; } - public int[] Collection { get; set; } - } - class DestinationDerived : Destination - { - } - public class InnerDestination - { - public int Integer { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().ForAllMembers(o => o.AllowNull()); - cfg.CreateMap().IncludeBase(); - cfg.CreateMap(); - cfg.AllowNullDestinationValues = false; - cfg.AllowNullCollections = false; - }); - [Fact] - public void Should_map_to_null() - { - var destination = Mapper.Map(new SourceDerived()); - destination.Collection.ShouldBeNull(); - destination.Inner.ShouldBeNull(); - } + public int Integer { get; set; } } - public class When_mappping_null_with_DoNotAllowNull_and_inheritance : AutoMapperSpecBase + class Destination { - class Source - { - public InnerSource Inner { get; set; } - public int[] Collection { get; set; } - } - class SourceDerived : Source - { - } - public class InnerSource - { - public int Integer { get; set; } - } - class Destination - { - public InnerDestination Inner { get; set; } - public int[] Collection { get; set; } - } - class DestinationDerived : Destination - { - } - public class InnerDestination - { - public int Integer { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().ForAllMembers(o => o.AllowNull()); - cfg.CreateMap().IncludeBase().ForAllMembers(o => o.DoNotAllowNull()); - cfg.CreateMap(); - cfg.AllowNullDestinationValues = true; - cfg.AllowNullCollections = true; - }); - [Fact] - public void Should_map_to_non_null() - { - var destination = Mapper.Map(new SourceDerived()); - destination.Collection.ShouldNotBeNull(); - destination.Inner.ShouldNotBeNull(); - } + public InnerDestination Inner { get; set; } + public int[] Collection { get; set; } + } + public class InnerDestination + { + public int Integer { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().ForAllMembers(o => o.DoNotAllowNull()); + cfg.CreateMap(); + cfg.AllowNullDestinationValues = true; + cfg.AllowNullCollections = true; + }); + [Fact] + public void Should_map_to_non_null() + { + var destination = Mapper.Map(new Source()); + destination.Collection.ShouldNotBeNull(); + destination.Inner.ShouldNotBeNull(); + } +} +public class When_mappping_null_with_AllowNull : AutoMapperSpecBase +{ + class Source + { + public InnerSource Inner { get; set; } + public int[] Collection { get; set; } + } + public class InnerSource + { + public int Integer { get; set; } + } + class Destination + { + public InnerDestination Inner { get; set; } + public int[] Collection { get; set; } + } + public class InnerDestination + { + public int Integer { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().ForAllMembers(o=>o.AllowNull()); + cfg.CreateMap(); + cfg.AllowNullDestinationValues = false; + cfg.AllowNullCollections = false; + }); + [Fact] + public void Should_map_to_null() + { + var destination = Mapper.Map(new Source()); + destination.Collection.ShouldBeNull(); + destination.Inner.ShouldBeNull(); + } +} +public class When_mappping_null_with_AllowNull_and_inheritance : AutoMapperSpecBase +{ + class Source + { + public InnerSource Inner { get; set; } + public int[] Collection { get; set; } + } + class SourceDerived : Source + { + } + public class InnerSource + { + public int Integer { get; set; } } - public class When_mappping_null_collection_with_AllowNullCollections_false : AutoMapperSpecBase + class Destination { - protected override MapperConfiguration CreateConfiguration() => new(cfg => {}); + public InnerDestination Inner { get; set; } + public int[] Collection { get; set; } + } + class DestinationDerived : Destination + { + } + public class InnerDestination + { + public int Integer { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().ForAllMembers(o => o.AllowNull()); + cfg.CreateMap().IncludeBase(); + cfg.CreateMap(); + cfg.AllowNullDestinationValues = false; + cfg.AllowNullCollections = false; + }); + [Fact] + public void Should_map_to_null() + { + var destination = Mapper.Map(new SourceDerived()); + destination.Collection.ShouldBeNull(); + destination.Inner.ShouldBeNull(); + } +} +public class When_mappping_null_with_DoNotAllowNull_and_inheritance : AutoMapperSpecBase +{ + class Source + { + public InnerSource Inner { get; set; } + public int[] Collection { get; set; } + } + class SourceDerived : Source + { + } + public class InnerSource + { + public int Integer { get; set; } + } + class Destination + { + public InnerDestination Inner { get; set; } + public int[] Collection { get; set; } + } + class DestinationDerived : Destination + { + } + public class InnerDestination + { + public int Integer { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().ForAllMembers(o => o.AllowNull()); + cfg.CreateMap().IncludeBase().ForAllMembers(o => o.DoNotAllowNull()); + cfg.CreateMap(); + cfg.AllowNullDestinationValues = true; + cfg.AllowNullCollections = true; + }); + [Fact] + public void Should_map_to_non_null() + { + var destination = Mapper.Map(new SourceDerived()); + destination.Collection.ShouldNotBeNull(); + destination.Inner.ShouldNotBeNull(); + } +} +public class When_mappping_null_collection_with_AllowNullCollections_false : AutoMapperSpecBase +{ + protected override MapperConfiguration CreateConfiguration() => new(cfg => {}); - [Fact] - public void Should_map_to_non_null() - { - Mapper.Map(null).ShouldNotBeNull(); - Mapper.Map(null, _=> { }).ShouldNotBeNull(); - } + [Fact] + public void Should_map_to_non_null() + { + Mapper.Map(null).ShouldNotBeNull(); + Mapper.Map(null, _=> { }).ShouldNotBeNull(); } +} - public class When_mappping_null_collection_with_AllowNullCollections_true : AutoMapperSpecBase +public class When_mappping_null_collection_with_AllowNullCollections_true : AutoMapperSpecBase +{ + protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.AllowNullCollections = true); + + [Fact] + public void Should_map_to_null() { - protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.AllowNullCollections = true); + Mapper.Map(null).ShouldBeNull(); + Mapper.Map(null, _ => { }).ShouldBeNull(); + } +} - [Fact] - public void Should_map_to_null() - { - Mapper.Map(null).ShouldBeNull(); - Mapper.Map(null, _ => { }).ShouldBeNull(); - } +public class When_mappping_null_array_with_AllowNullDestinationValues_false : AutoMapperSpecBase +{ + class Source + { + public int[] Collection { get; set; } } - public class When_mappping_null_array_with_AllowNullDestinationValues_false : AutoMapperSpecBase + class Destination { - class Source - { - public int[] Collection { get; set; } - } + public int[] Collection { get; set; } + } - class Destination - { - public int[] Collection { get; set; } - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + cfg.AllowNullDestinationValues = false; + }); - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - cfg.AllowNullDestinationValues = false; - }); + [Fact] + public void Should_map_to_non_null() => Mapper.Map(new Source()).Collection.ShouldNotBeNull(); +} - [Fact] - public void Should_map_to_non_null() => Mapper.Map(new Source()).Collection.ShouldNotBeNull(); +public class When_mappping_null_array_to_IEnumerable_with_MapAtRuntime : AutoMapperSpecBase +{ + class Source + { + public int[] Collection { get; set; } } - public class When_mappping_null_array_to_IEnumerable_with_MapAtRuntime : AutoMapperSpecBase + class Destination { - class Source - { - public int[] Collection { get; set; } - } + public IEnumerable Collection { get; set; } + } - class Destination - { - public IEnumerable Collection { get; set; } - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.CreateMap().ForMember(d=>d.Collection, o=>o.MapAtRuntime())); - protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.CreateMap().ForMember(d=>d.Collection, o=>o.MapAtRuntime())); + [Fact] + public void Should_map_to_non_null() + { + Mapper.Map(new Source()).Collection.ShouldNotBeNull(); + } +} - [Fact] - public void Should_map_to_non_null() - { - Mapper.Map(new Source()).Collection.ShouldNotBeNull(); - } +public class When_mappping_null_array_to_IEnumerable : AutoMapperSpecBase +{ + class Source + { + public int[] Collection { get; set; } } - public class When_mappping_null_array_to_IEnumerable : AutoMapperSpecBase + class Destination { - class Source - { - public int[] Collection { get; set; } - } + public IEnumerable Collection { get; set; } + } - class Destination - { - public IEnumerable Collection { get; set; } - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.CreateMap()); - protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.CreateMap()); + [Fact] + public void Should_map_to_non_null() + { + Mapper.Map(new Source()).Collection.ShouldNotBeNull(); + } +} - [Fact] - public void Should_map_to_non_null() - { - Mapper.Map(new Source()).Collection.ShouldNotBeNull(); - } +public class When_mappping_null_list_to_ICollection : AutoMapperSpecBase +{ + class Source + { + public List Collection { get; set; } } - public class When_mappping_null_list_to_ICollection : AutoMapperSpecBase + class Destination { - class Source - { - public List Collection { get; set; } - } + public ICollection Collection { get; set; } + } - class Destination - { - public ICollection Collection { get; set; } - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.CreateMap()); - protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.CreateMap()); + [Fact] + public void Should_map_to_non_null() + { + Mapper.Map(new Source()).Collection.ShouldNotBeNull(); + } +} - [Fact] - public void Should_map_to_non_null() - { - Mapper.Map(new Source()).Collection.ShouldNotBeNull(); - } +public class When_mapping_untyped_null_to_IEnumerable_and_AllowNullCollections_is_true : AutoMapperSpecBase +{ + class Source + { + public object Value { get; set; } } - public class When_mapping_untyped_null_to_IEnumerable_and_AllowNullCollections_is_true : AutoMapperSpecBase + class Destination { - class Source - { - public object Value { get; set; } - } + public IEnumerable Value { get; set; } + } - class Destination - { - public IEnumerable Value { get; set; } - } + protected override MapperConfiguration CreateConfiguration() => new(c => + { + c.AllowNullCollections = true; + c.CreateMap(); + }); - protected override MapperConfiguration CreateConfiguration() => new(c => - { - c.AllowNullCollections = true; - c.CreateMap(); - }); + [Fact] + public void Should_map_to_null() + { + Mapper.Map(new Source()).Value.ShouldBeNull(); + } +} - [Fact] - public void Should_map_to_null() - { - Mapper.Map(new Source()).Value.ShouldBeNull(); - } +public class When_mapping_from_null_interface_and_AllowNullDestinationValues_is_false : AutoMapperSpecBase +{ + ElementDestination _destination; + + interface ILink + { + int Id { get; set; } + string Type { get; set; } } - public class When_mapping_from_null_interface_and_AllowNullDestinationValues_is_false : AutoMapperSpecBase + class LinkImpl : ILink { - ElementDestination _destination; + public int Id { get; set; } + public string Type { get; set; } + } - interface ILink - { - int Id { get; set; } - string Type { get; set; } - } + class ElementSource + { + public int Id { get; set; } + public ILink Link { get; set; } + } - class LinkImpl : ILink - { - public int Id { get; set; } - public string Type { get; set; } - } + class ElementDestination + { + public int Id { get; set; } + public LinkImpl Link { get; set; } + } - class ElementSource - { - public int Id { get; set; } - public ILink Link { get; set; } - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.AllowNullDestinationValues = false; + cfg.CreateMap(); + cfg.CreateMap(); + }); - class ElementDestination - { - public int Id { get; set; } - public LinkImpl Link { get; set; } - } + protected override void Because_of() + { + _destination = Mapper.Map(new ElementSource()); + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.AllowNullDestinationValues = false; - cfg.CreateMap(); - cfg.CreateMap(); - }); + [Fact] + public void Should_not_get_null() + { + _destination.Link.ShouldNotBeNull(); + } +} - protected override void Because_of() - { - _destination = Mapper.Map(new ElementSource()); - } +public class When_mapping_from_null_interface : AutoMapperSpecBase +{ + ElementDestination _destination; - [Fact] - public void Should_not_get_null() - { - _destination.Link.ShouldNotBeNull(); - } + interface ILink + { + int Id { get; set; } + string Type { get; set; } } - public class When_mapping_from_null_interface : AutoMapperSpecBase + class LinkImpl : ILink { - ElementDestination _destination; + public int Id { get; set; } + public string Type { get; set; } + } - interface ILink - { - int Id { get; set; } - string Type { get; set; } - } + class ElementSource + { + public int Id { get; set; } + public ILink Link { get; set; } + } - class LinkImpl : ILink - { - public int Id { get; set; } - public string Type { get; set; } - } + class ElementDestination + { + public int Id { get; set; } + public LinkImpl Link { get; set; } + } - class ElementSource - { - public int Id { get; set; } - public ILink Link { get; set; } - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().ReverseMap(); + cfg.CreateMap(); + }); - class ElementDestination - { - public int Id { get; set; } - public LinkImpl Link { get; set; } - } + protected override void Because_of() + { + _destination = Mapper.Map(new ElementSource()); + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().ReverseMap(); - cfg.CreateMap(); - }); + [Fact] + public void Should_get_null() + { + _destination.Link.ShouldBeNull(); + } +} - protected override void Because_of() - { - _destination = Mapper.Map(new ElementSource()); - } +public class When_mapping_a_model_with_null_items : AutoMapperSpecBase +{ + private ModelDto _result; - [Fact] - public void Should_get_null() - { - _destination.Link.ShouldBeNull(); - } + public class ModelDto + { + public ModelSubDto Sub { get; set; } + public int SubSomething { get; set; } + public int? SubSomethingNullDest { get; set; } + public string NullString { get; set; } } - public class When_mapping_a_model_with_null_items : AutoMapperSpecBase + public class ModelSubDto { - private ModelDto _result; + public int[] Items { get; set; } + } - public class ModelDto - { - public ModelSubDto Sub { get; set; } - public int SubSomething { get; set; } - public int? SubSomethingNullDest { get; set; } - public string NullString { get; set; } - } + public class ModelObject + { + public ModelSubObject Sub { get; set; } + public string NullString { get; set; } + } - public class ModelSubDto + public class ModelSubObject + { + public int[] GetItems() { - public int[] Items { get; set; } + return new[] { 0, 1, 2, 3 }; } - public class ModelObject - { - public ModelSubObject Sub { get; set; } - public string NullString { get; set; } - } + public int Something { get; set; } + public int SomethingNullDest { get; set; } + } - public class ModelSubObject - { - public int[] GetItems() - { - return new[] { 0, 1, 2, 3 }; - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.AllowNullDestinationValues = false; + cfg.CreateMap(); + cfg.CreateMap(); + }); - public int Something { get; set; } - public int SomethingNullDest { get; set; } - } + protected override void Because_of() + { + var model = new ModelObject(); + model.Sub = null; - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.AllowNullDestinationValues = false; - cfg.CreateMap(); - cfg.CreateMap(); - }); + _result = Mapper.Map(model); + } - protected override void Because_of() - { - var model = new ModelObject(); - model.Sub = null; + [Fact] + public void Should_populate_dto_items_with_a_value() + { + _result.Sub.ShouldNotBeNull(); + } - _result = Mapper.Map(model); - } + [Fact] + public void Should_provide_empty_array_for_array_type_values() + { + _result.Sub.Items.ShouldNotBeNull(); + } - [Fact] - public void Should_populate_dto_items_with_a_value() - { - _result.Sub.ShouldNotBeNull(); - } + [Fact] + public void Should_return_default_value_of_property_in_the_chain() + { + _result.SubSomething.ShouldBe(0); + } - [Fact] - public void Should_provide_empty_array_for_array_type_values() - { - _result.Sub.Items.ShouldNotBeNull(); - } + [Fact] + public void Should_return_null_for_nullable_properties() + { + _result.SubSomethingNullDest.ShouldBeNull(); + } - [Fact] - public void Should_return_default_value_of_property_in_the_chain() - { - _result.SubSomething.ShouldBe(0); - } + [Fact] + public void Default_value_for_string_should_be_empty() + { + _result.NullString.ShouldBe(string.Empty); + } +} - [Fact] - public void Should_return_null_for_nullable_properties() - { - _result.SubSomethingNullDest.ShouldBeNull(); - } +public class When_overriding_null_behavior_with_null_source_items : AutoMapperSpecBase +{ + private ModelDto _result; - [Fact] - public void Default_value_for_string_should_be_empty() - { - _result.NullString.ShouldBe(string.Empty); - } + public class ModelDto + { + public ModelSubDto Sub { get; set; } + public int SubSomething { get; set; } + public int? NullableMapFrom { get; set; } + public string NullString { get; set; } + public int? SubExpressionName { get; set; } } - public class When_overriding_null_behavior_with_null_source_items : AutoMapperSpecBase + public class ModelSubDto { - private ModelDto _result; + public int[] Items { get; set; } + } - public class ModelDto - { - public ModelSubDto Sub { get; set; } - public int SubSomething { get; set; } - public int? NullableMapFrom { get; set; } - public string NullString { get; set; } - public int? SubExpressionName { get; set; } - } + public class ModelObject + { + public ModelSubObject Sub { get; set; } + public string NullString { get; set; } - public class ModelSubDto - { - public int[] Items { get; set; } - } + public ModelSubObject[] Subs { get; set; } - public class ModelObject + public int Id { get; set; } + } + + public class ModelSubObject + { + public int[] GetItems() { - public ModelSubObject Sub { get; set; } - public string NullString { get; set; } + return new[] { 0, 1, 2, 3 }; + } - public ModelSubObject[] Subs { get; set; } + public int Something { get; set; } - public int Id { get; set; } - } + public string Name { get; set; } + public ModelSubObject Sub { get; set; } + } - public class ModelSubObject - { - public int[] GetItems() - { - return new[] { 0, 1, 2, 3 }; - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { - public int Something { get; set; } + cfg.AllowNullDestinationValues = true; + cfg.CreateMap(); + cfg.CreateMap() + .ForMember(d => d.SubExpressionName, opt => opt.MapFrom(src => + src.Subs.FirstOrDefault(spt => spt.Sub.Something == src.Id).Something)) + .ForMember(d => d.NullableMapFrom, opt => opt.MapFrom(s => s.Sub.Something)); + }); - public string Name { get; set; } - public ModelSubObject Sub { get; set; } - } + protected override void Because_of() + { + var model = new ModelObject(); + model.Sub = null; + model.NullString = null; - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { + _result = Mapper.Map(model); + } - cfg.AllowNullDestinationValues = true; - cfg.CreateMap(); - cfg.CreateMap() - .ForMember(d => d.SubExpressionName, opt => opt.MapFrom(src => - src.Subs.FirstOrDefault(spt => spt.Sub.Something == src.Id).Something)) - .ForMember(d => d.NullableMapFrom, opt => opt.MapFrom(s => s.Sub.Something)); - }); + [Fact] + public void Should_return_null_for_nullable_properties_that_are_complex_map_froms() + { + _result.SubExpressionName.ShouldBe(null); + } - protected override void Because_of() - { - var model = new ModelObject(); - model.Sub = null; - model.NullString = null; + [Fact] + public void Should_return_null_for_nullable_properties_that_have_member_access_map_froms() + { + _result.NullableMapFrom.ShouldBe(null); + } - _result = Mapper.Map(model); - } + [Fact] + public void Should_map_first_level_items_as_null() + { + _result.NullString.ShouldBeNull(); + } - [Fact] - public void Should_return_null_for_nullable_properties_that_are_complex_map_froms() - { - _result.SubExpressionName.ShouldBe(null); - } + [Fact] + public void Should_map_primitive_items_as_default() + { + _result.SubSomething.ShouldBe(0); + } - [Fact] - public void Should_return_null_for_nullable_properties_that_have_member_access_map_froms() - { - _result.NullableMapFrom.ShouldBe(null); - } + [Fact] + public void Should_map_any_sub_mapped_items_as_null() + { + _result.Sub.ShouldBeNull(); + } +} - [Fact] - public void Should_map_first_level_items_as_null() - { - _result.NullString.ShouldBeNull(); - } +public class When_overriding_null_behavior_in_sub_profile : AutoMapperSpecBase +{ + private ModelDto _result; - [Fact] - public void Should_map_primitive_items_as_default() - { - _result.SubSomething.ShouldBe(0); - } + public class ModelDto + { + public ModelSubDto Sub { get; set; } + public int SubSomething { get; set; } + public int? NullableMapFrom { get; set; } + public string NullString { get; set; } + public int? SubExpressionName { get; set; } + } - [Fact] - public void Should_map_any_sub_mapped_items_as_null() - { - _result.Sub.ShouldBeNull(); - } + public class ModelSubDto + { + public int[] Items { get; set; } } - public class When_overriding_null_behavior_in_sub_profile : AutoMapperSpecBase + public class ModelObject { - private ModelDto _result; + public ModelSubObject Sub { get; set; } + public string NullString { get; set; } - public class ModelDto - { - public ModelSubDto Sub { get; set; } - public int SubSomething { get; set; } - public int? NullableMapFrom { get; set; } - public string NullString { get; set; } - public int? SubExpressionName { get; set; } - } + public ModelSubObject[] Subs { get; set; } - public class ModelSubDto - { - public int[] Items { get; set; } - } + public int Id { get; set; } + } - public class ModelObject + public class ModelSubObject + { + public int[] GetItems() { - public ModelSubObject Sub { get; set; } - public string NullString { get; set; } - - public ModelSubObject[] Subs { get; set; } - - public int Id { get; set; } + return new[] { 0, 1, 2, 3 }; } - public class ModelSubObject - { - public int[] GetItems() - { - return new[] { 0, 1, 2, 3 }; - } + public int Something { get; set; } - public int Something { get; set; } + public string Name { get; set; } + public ModelSubObject Sub { get; set; } + } - public string Name { get; set; } - public ModelSubObject Sub { get; set; } - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.AllowNullDestinationValues = false; - protected override MapperConfiguration CreateConfiguration() => new(cfg => + cfg.CreateProfile("Foo", p => { - cfg.AllowNullDestinationValues = false; - - cfg.CreateProfile("Foo", p => - { - p.AllowNullDestinationValues = true; - p.CreateMap(); - p.CreateMap() - .ForMember(d => d.SubExpressionName, opt => opt.MapFrom(src => - src.Subs.FirstOrDefault(spt => spt.Sub.Something == src.Id).Something)) - .ForMember(d => d.NullableMapFrom, opt => opt.MapFrom(s => s.Sub.Something)); - }); + p.AllowNullDestinationValues = true; + p.CreateMap(); + p.CreateMap() + .ForMember(d => d.SubExpressionName, opt => opt.MapFrom(src => + src.Subs.FirstOrDefault(spt => spt.Sub.Something == src.Id).Something)) + .ForMember(d => d.NullableMapFrom, opt => opt.MapFrom(s => s.Sub.Something)); }); + }); - protected override void Because_of() - { - var model = new ModelObject(); - model.Sub = null; - model.NullString = null; - - _result = Mapper.Map(model); - } + protected override void Because_of() + { + var model = new ModelObject(); + model.Sub = null; + model.NullString = null; - [Fact] - public void Should_return_null_for_nullable_properties_that_are_complex_map_froms() - { - _result.SubExpressionName.ShouldBe(null); - } + _result = Mapper.Map(model); + } - [Fact] - public void Should_return_null_for_nullable_properties_that_have_member_access_map_froms() - { - _result.NullableMapFrom.ShouldBe(null); - } + [Fact] + public void Should_return_null_for_nullable_properties_that_are_complex_map_froms() + { + _result.SubExpressionName.ShouldBe(null); + } - [Fact] - public void Should_map_first_level_items_as_null() - { - _result.NullString.ShouldBeNull(); - } + [Fact] + public void Should_return_null_for_nullable_properties_that_have_member_access_map_froms() + { + _result.NullableMapFrom.ShouldBe(null); + } - [Fact] - public void Should_map_primitive_items_as_default() - { - _result.SubSomething.ShouldBe(0); - } + [Fact] + public void Should_map_first_level_items_as_null() + { + _result.NullString.ShouldBeNull(); + } - [Fact] - public void Should_map_any_sub_mapped_items_as_null() - { - _result.Sub.ShouldBeNull(); - } + [Fact] + public void Should_map_primitive_items_as_default() + { + _result.SubSomething.ShouldBe(0); } - public class When_overriding_null_behavior_in_a_profile : AutoMapperSpecBase + [Fact] + public void Should_map_any_sub_mapped_items_as_null() { - private DefaultDestination _defaultResult; - private NullDestination _nullResult; + _result.Sub.ShouldBeNull(); + } +} - public class DefaultSource - { - public object Value { get; set; } - } +public class When_overriding_null_behavior_in_a_profile : AutoMapperSpecBase +{ + private DefaultDestination _defaultResult; + private NullDestination _nullResult; - public class DefaultDestination - { - public object Value { get; set; } - } + public class DefaultSource + { + public object Value { get; set; } + } - public class NullSource - { - public object Value { get; set; } - } + public class DefaultDestination + { + public object Value { get; set; } + } - public class NullDestination - { - public object Value { get; set; } - } + public class NullSource + { + public object Value { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => + public class NullDestination + { + public object Value { get; set; } + } + + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateProfile("MapsNulls", p => { - cfg.CreateProfile("MapsNulls", p => - { - p.AllowNullDestinationValues = false; - p.CreateMap(); - }); - cfg.CreateMap(); + p.AllowNullDestinationValues = false; + p.CreateMap(); }); + cfg.CreateMap(); + }); - protected override void Because_of() - { - _defaultResult = Mapper.Map(new DefaultSource()); - _nullResult = Mapper.Map(new NullSource()); - } + protected override void Because_of() + { + _defaultResult = Mapper.Map(new DefaultSource()); + _nullResult = Mapper.Map(new NullSource()); + } - [Fact] - public void Should_use_default_behavior_in_default_profile() - { - _defaultResult.Value.ShouldBeNull(); - } + [Fact] + public void Should_use_default_behavior_in_default_profile() + { + _defaultResult.Value.ShouldBeNull(); + } - [Fact] - public void Should_use_overridden_null_behavior_in_profile() - { - _nullResult.Value.ShouldNotBeNull(); - } + [Fact] + public void Should_use_overridden_null_behavior_in_profile() + { + _nullResult.Value.ShouldNotBeNull(); } +} - public class When_using_a_custom_resolver_and_the_source_value_is_null : NonValidatingSpecBase +public class When_using_a_custom_resolver_and_the_source_value_is_null : NonValidatingSpecBase +{ + public class NullResolver : IMemberValueResolver { - public class NullResolver : IMemberValueResolver + public string Resolve(Source s, Destination d, string source, string dest, ResolutionContext context) { - public string Resolve(Source s, Destination d, string source, string dest, ResolutionContext context) - { - if(source == null) - return "jon"; - return "fail"; - } + if(source == null) + return "jon"; + return "fail"; } + } - private static Source _source; - private Destination _dest; - - public class Source - { - public string MyName { get; set; } - } + private static Source _source; + private Destination _dest; - public class Destination - { - public string Name { get; set; } - } + public class Source + { + public string MyName { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.MyName)); - _source = new Source(); - }); + public class Destination + { + public string Name { get; set; } + } - protected override void Because_of() - { - _dest = Mapper.Map(_source); - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.MyName)); + _source = new Source(); + }); - [Fact] - public void Should_perform_the_translation() - { - _dest.Name.ShouldBe("jon"); - } + protected override void Because_of() + { + _dest = Mapper.Map(_source); } - public class When_mapping_using_a_custom_member_mapping_and_source_is_null : AutoMapperSpecBase + [Fact] + public void Should_perform_the_translation() { - private Dest _dest; + _dest.Name.ShouldBe("jon"); + } +} - public class Source - { - public SubSource Sub { get; set; } - } +public class When_mapping_using_a_custom_member_mapping_and_source_is_null : AutoMapperSpecBase +{ + private Dest _dest; - public class SubSource - { - public int Value { get; set; } - } + public class Source + { + public SubSource Sub { get; set; } + } - public class Dest - { - public int OtherValue { get; set; } - } + public class SubSource + { + public int Value { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.AllowNullDestinationValues = false; - cfg.CreateMap() - .ForMember(dest => dest.OtherValue, opt => opt.MapFrom(src => src.Sub.Value)); - }); + public class Dest + { + public int OtherValue { get; set; } + } - protected override void Because_of() - { - _dest = Mapper.Map(new Source()); - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.AllowNullDestinationValues = false; + cfg.CreateMap() + .ForMember(dest => dest.OtherValue, opt => opt.MapFrom(src => src.Sub.Value)); + }); - [Fact] - public void Should_map_to_null_on_destination_values() - { - _dest.OtherValue.ShouldBe(0); - } + protected override void Because_of() + { + _dest = Mapper.Map(new Source()); } - public class When_specifying_a_resolver_for_a_nullable_type : AutoMapperSpecBase + [Fact] + public void Should_map_to_null_on_destination_values() { - private FooViewModel _result; + _dest.OtherValue.ShouldBe(0); + } +} - public class NullableBoolToLabel : ITypeConverter +public class When_specifying_a_resolver_for_a_nullable_type : AutoMapperSpecBase +{ + private FooViewModel _result; + + public class NullableBoolToLabel : ITypeConverter + { + public string Convert(bool? source, string destination, ResolutionContext context) { - public string Convert(bool? source, string destination, ResolutionContext context) + if(source.HasValue) { - if(source.HasValue) - { - if(source.Value) - return "Yes"; - else - return "No"; - } + if(source.Value) + return "Yes"; else - return "(n/a)"; + return "No"; } + else + return "(n/a)"; } + } - public class Foo - { - public bool? IsFooBarred { get; set; } - } - - public class FooViewModel - { - public string IsFooBarred { get; set; } - } + public class Foo + { + public bool? IsFooBarred { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().ConvertUsing(); - cfg.CreateMap(); - }); + public class FooViewModel + { + public string IsFooBarred { get; set; } + } - protected override void Because_of() - { - var foo3 = new Foo { IsFooBarred = null }; - _result = Mapper.Map(foo3); - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().ConvertUsing(); + cfg.CreateMap(); + }); - [Fact] - public void Should_allow_the_resolver_to_handle_null_values() - { - _result.IsFooBarred.ShouldBe("(n/a)"); - } + protected override void Because_of() + { + var foo3 = new Foo { IsFooBarred = null }; + _result = Mapper.Map(foo3); } - public class When_overriding_collection_null_behavior : AutoMapperSpecBase + [Fact] + public void Should_allow_the_resolver_to_handle_null_values() { - private Dest _dest; + _result.IsFooBarred.ShouldBe("(n/a)"); + } +} - public class Source - { - public IEnumerable Values1 { get; set; } - public List Values2 { get; set; } - public Dictionary Values3 { get; set; } - public int[] Values4 { get; set; } - public ReadOnlyCollection Values5 { get; set; } - public Collection Values6 { get; set; } - } +public class When_overriding_collection_null_behavior : AutoMapperSpecBase +{ + private Dest _dest; - public class Dest - { - public IEnumerable Values1 { get; set; } - public List Values2 { get; set; } - public Dictionary Values3 { get; set; } - public int[] Values4 { get; set; } - public ReadOnlyCollection Values5 { get; set; } - public Collection Values6 { get; set; } - } + public class Source + { + public IEnumerable Values1 { get; set; } + public List Values2 { get; set; } + public Dictionary Values3 { get; set; } + public int[] Values4 { get; set; } + public ReadOnlyCollection Values5 { get; set; } + public Collection Values6 { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - cfg.AllowNullCollections = true; - }); + public class Dest + { + public IEnumerable Values1 { get; set; } + public List Values2 { get; set; } + public Dictionary Values3 { get; set; } + public int[] Values4 { get; set; } + public ReadOnlyCollection Values5 { get; set; } + public Collection Values6 { get; set; } + } - protected override void Because_of() - { - _dest = Mapper.Map(new Source()); - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + cfg.AllowNullCollections = true; + }); - [Fact] - public void Should_allow_null_ienumerables() - { - _dest.Values1.ShouldBeNull(); - } + protected override void Because_of() + { + _dest = Mapper.Map(new Source()); + } - [Fact] - public void Should_allow_null_lists() - { - _dest.Values2.ShouldBeNull(); - } + [Fact] + public void Should_allow_null_ienumerables() + { + _dest.Values1.ShouldBeNull(); + } - [Fact] - public void Should_allow_null_dictionaries() - { - _dest.Values3.ShouldBeNull(); - } + [Fact] + public void Should_allow_null_lists() + { + _dest.Values2.ShouldBeNull(); + } - [Fact] - public void Should_allow_null_arrays() - { - _dest.Values4.ShouldBeNull(); - } + [Fact] + public void Should_allow_null_dictionaries() + { + _dest.Values3.ShouldBeNull(); + } - [Fact] - public void Should_allow_null_read_only_collections() - { - _dest.Values5.ShouldBeNull(); - } + [Fact] + public void Should_allow_null_arrays() + { + _dest.Values4.ShouldBeNull(); + } - [Fact] - public void Should_allow_null_collections() - { - _dest.Values6.ShouldBeNull(); - } + [Fact] + public void Should_allow_null_read_only_collections() + { + _dest.Values5.ShouldBeNull(); } - public class When_overriding_collection_null_behavior_in_profile_with_MapAtRuntime : AutoMapperSpecBase + [Fact] + public void Should_allow_null_collections() { - private Dest _dest; + _dest.Values6.ShouldBeNull(); + } +} - public class Source - { - public IEnumerable Values1 { get; set; } - public List Values2 { get; set; } - public Dictionary Values3 { get; set; } - public int[] Values4 { get; set; } - public ReadOnlyCollection Values5 { get; set; } - public Collection Values6 { get; set; } - public int[,] Values7 { get; set; } - } +public class When_overriding_collection_null_behavior_in_profile_with_MapAtRuntime : AutoMapperSpecBase +{ + private Dest _dest; - public class Dest - { - public IEnumerable Values1 { get; set; } - public List Values2 { get; set; } - public Dictionary Values3 { get; set; } - public int[] Values4 { get; set; } - public ReadOnlyCollection Values5 { get; set; } - public Collection Values6 { get; set; } - public int[,] Values7 { get; set; } - } + public class Source + { + public IEnumerable Values1 { get; set; } + public List Values2 { get; set; } + public Dictionary Values3 { get; set; } + public int[] Values4 { get; set; } + public ReadOnlyCollection Values5 { get; set; } + public Collection Values6 { get; set; } + public int[,] Values7 { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateProfile("MyProfile", p => - { - p.CreateMap().ForAllMembers(o=>o.MapAtRuntime()); - p.AllowNullCollections = true; - }); - }); + public class Dest + { + public IEnumerable Values1 { get; set; } + public List Values2 { get; set; } + public Dictionary Values3 { get; set; } + public int[] Values4 { get; set; } + public ReadOnlyCollection Values5 { get; set; } + public Collection Values6 { get; set; } + public int[,] Values7 { get; set; } + } - protected override void Because_of() + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateProfile("MyProfile", p => { - _dest = Mapper.Map(new Source()); - } + p.CreateMap().ForAllMembers(o=>o.MapAtRuntime()); + p.AllowNullCollections = true; + }); + }); - [Fact] - public void Should_allow_null_ienumerables() - { - _dest.Values1.ShouldBeNull(); - } + protected override void Because_of() + { + _dest = Mapper.Map(new Source()); + } - [Fact] - public void Should_allow_null_lists() - { - _dest.Values2.ShouldBeNull(); - } + [Fact] + public void Should_allow_null_ienumerables() + { + _dest.Values1.ShouldBeNull(); + } - [Fact] - public void Should_allow_null_dictionaries() - { - _dest.Values3.ShouldBeNull(); - } + [Fact] + public void Should_allow_null_lists() + { + _dest.Values2.ShouldBeNull(); + } - [Fact] - public void Should_allow_null_arrays() - { - _dest.Values4.ShouldBeNull(); - } + [Fact] + public void Should_allow_null_dictionaries() + { + _dest.Values3.ShouldBeNull(); + } - [Fact] - public void Should_allow_null_read_only_collections() - { - _dest.Values5.ShouldBeNull(); - } + [Fact] + public void Should_allow_null_arrays() + { + _dest.Values4.ShouldBeNull(); + } - [Fact] - public void Should_allow_null_collections() - { - _dest.Values6.ShouldBeNull(); - } + [Fact] + public void Should_allow_null_read_only_collections() + { + _dest.Values5.ShouldBeNull(); + } - [Fact] - public void Should_allow_null_multidimensional_arrays() - { - _dest.Values7.ShouldBeNull(); - } + [Fact] + public void Should_allow_null_collections() + { + _dest.Values6.ShouldBeNull(); } - public class When_overriding_collection_null_behavior_in_profile : AutoMapperSpecBase + [Fact] + public void Should_allow_null_multidimensional_arrays() { - private Dest _dest; + _dest.Values7.ShouldBeNull(); + } +} - public class Source - { - public IEnumerable Values1 { get; set; } - public List Values2 { get; set; } - public Dictionary Values3 { get; set; } - public int[] Values4 { get; set; } - public ReadOnlyCollection Values5 { get; set; } - public Collection Values6 { get; set; } - public int[,] Values7 { get; set; } - } +public class When_overriding_collection_null_behavior_in_profile : AutoMapperSpecBase +{ + private Dest _dest; - public class Dest - { - public IEnumerable Values1 { get; set; } - public List Values2 { get; set; } - public Dictionary Values3 { get; set; } - public int[] Values4 { get; set; } - public ReadOnlyCollection Values5 { get; set; } - public Collection Values6 { get; set; } - public int[,] Values7 { get; set; } - } + public class Source + { + public IEnumerable Values1 { get; set; } + public List Values2 { get; set; } + public Dictionary Values3 { get; set; } + public int[] Values4 { get; set; } + public ReadOnlyCollection Values5 { get; set; } + public Collection Values6 { get; set; } + public int[,] Values7 { get; set; } + } + + public class Dest + { + public IEnumerable Values1 { get; set; } + public List Values2 { get; set; } + public Dictionary Values3 { get; set; } + public int[] Values4 { get; set; } + public ReadOnlyCollection Values5 { get; set; } + public Collection Values6 { get; set; } + public int[,] Values7 { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateProfile("MyProfile", p => { - cfg.CreateProfile("MyProfile", p => - { - p.CreateMap(); - p.AllowNullCollections = true; - }); + p.CreateMap(); + p.AllowNullCollections = true; }); + }); - protected override void Because_of() - { - _dest = Mapper.Map(new Source()); - } + protected override void Because_of() + { + _dest = Mapper.Map(new Source()); + } - [Fact] - public void Should_allow_null_ienumerables() - { - _dest.Values1.ShouldBeNull(); - } + [Fact] + public void Should_allow_null_ienumerables() + { + _dest.Values1.ShouldBeNull(); + } - [Fact] - public void Should_allow_null_lists() - { - _dest.Values2.ShouldBeNull(); - } + [Fact] + public void Should_allow_null_lists() + { + _dest.Values2.ShouldBeNull(); + } - [Fact] - public void Should_allow_null_dictionaries() - { - _dest.Values3.ShouldBeNull(); - } + [Fact] + public void Should_allow_null_dictionaries() + { + _dest.Values3.ShouldBeNull(); + } - [Fact] - public void Should_allow_null_arrays() - { - _dest.Values4.ShouldBeNull(); - } + [Fact] + public void Should_allow_null_arrays() + { + _dest.Values4.ShouldBeNull(); + } - [Fact] - public void Should_allow_null_read_only_collections() - { - _dest.Values5.ShouldBeNull(); - } + [Fact] + public void Should_allow_null_read_only_collections() + { + _dest.Values5.ShouldBeNull(); + } - [Fact] - public void Should_allow_null_collections() - { - _dest.Values6.ShouldBeNull(); - } + [Fact] + public void Should_allow_null_collections() + { + _dest.Values6.ShouldBeNull(); + } - [Fact] - public void Should_allow_null_multidimensional_arrays() - { - _dest.Values7.ShouldBeNull(); - } + [Fact] + public void Should_allow_null_multidimensional_arrays() + { + _dest.Values7.ShouldBeNull(); } +} - public class When_mapping_a_null_model : AutoMapperSpecBase +public class When_mapping_a_null_model : AutoMapperSpecBase +{ + public class ModelDto { - public class ModelDto - { - } + } - public class ModelObject - { - } + public class ModelObject + { + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + }); - [Fact] - public void Should_populate_dto_items_with_a_value() - { - Mapper.Map(null).ShouldBeNull(); - } + [Fact] + public void Should_populate_dto_items_with_a_value() + { + Mapper.Map(null).ShouldBeNull(); } } \ No newline at end of file diff --git a/src/UnitTests/OpenGenerics.cs b/src/UnitTests/OpenGenerics.cs index 403e96fa4e..d91ba4554b 100644 --- a/src/UnitTests/OpenGenerics.cs +++ b/src/UnitTests/OpenGenerics.cs @@ -4,569 +4,568 @@ using System.Linq; using Xunit; -namespace AutoMapper.UnitTests +namespace AutoMapper.UnitTests; + +public class SealGenerics : AutoMapperSpecBase { - public class SealGenerics : AutoMapperSpecBase + public record SourceProperty(T Value, SourceProperty Recursive = null); + public record DestProperty(T Value, DestProperty Recursive = null); + public record User(SourceProperty UserStoreId); + public class UserPropertiesContainer { - public record SourceProperty(T Value, SourceProperty Recursive = null); - public record DestProperty(T Value, DestProperty Recursive = null); - public record User(SourceProperty UserStoreId); - public class UserPropertiesContainer - { - public UserProperties User { get; set; } - } - public class UserProperties - { - public DestProperty UserStoreId { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(typeof(SourceProperty<>), typeof(DestProperty<>)); - cfg.CreateMap().ForMember(dest => dest.User, opt => opt.MapFrom(src => src)); - cfg.CreateMap(); - }); - [Fact] - public void Should_work() - { - var guid = Guid.NewGuid(); - Map(new User(new(guid))).UserStoreId.Value.ShouldBe(guid); - } + public UserProperties User { get; set; } } - public class OpenGenerics_With_Struct : AutoMapperSpecBase + public class UserProperties { - public struct Id - { - } - protected override MapperConfiguration CreateConfiguration() => new(mapper => mapper.CreateMap(typeof(Id<>), typeof(long)).ConvertUsing((_,__)=>(long)42)); - [Fact] - public void Should_work() => Map(new Id()).ShouldBe(42); + public DestProperty UserStoreId { get; set; } } - public class OpenGenerics_With_Base_Generic : AutoMapperSpecBase + protected override MapperConfiguration CreateConfiguration() => new(cfg => { - public class Foo - { - public T Value1 { get; set; } - } - public class BarBase - { - public T Value2 { get; set; } - } - public class Bar : BarBase - { - } - protected override MapperConfiguration CreateConfiguration() => new(mapper => mapper.CreateMap(typeof(Foo<>), typeof(Bar<>)).ForMember("Value2", to => to.MapFrom("Value1"))); - [Fact] - public void Can_map_base_members() => Map>(new Foo { Value1 = 5 }).Value2.ShouldBe(5); + cfg.CreateMap(typeof(SourceProperty<>), typeof(DestProperty<>)); + cfg.CreateMap().ForMember(dest => dest.User, opt => opt.MapFrom(src => src)); + cfg.CreateMap(); + }); + [Fact] + public void Should_work() + { + var guid = Guid.NewGuid(); + Map(new User(new(guid))).UserStoreId.Value.ShouldBe(guid); } - public class GenericMapsAsNonGeneric : AutoMapperSpecBase +} +public class OpenGenerics_With_Struct : AutoMapperSpecBase +{ + public struct Id { - class Source - { - public int Value; - } - class Destination - { - public T Value; - } - class NonGenericDestination : Destination - { - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(typeof(Source), typeof(Destination<>)).As(typeof(NonGenericDestination)); - cfg.CreateMap(typeof(Source), typeof(NonGenericDestination)); - }); - [Fact] - public void Should_work() => Mapper.Map>(new Source { Value = 42 }).Value.ShouldBe("42"); } - public class GenericMapsPriority : AutoMapperSpecBase + protected override MapperConfiguration CreateConfiguration() => new(mapper => mapper.CreateMap(typeof(Id<>), typeof(long)).ConvertUsing((_,__)=>(long)42)); + [Fact] + public void Should_work() => Map(new Id()).ShouldBe(42); +} +public class OpenGenerics_With_Base_Generic : AutoMapperSpecBase +{ + public class Foo { - class Source - { - public T Value; - } - class Destination - { - public T Value; - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(typeof(Source<>), typeof(Destination)); - cfg.CreateMap(typeof(Source<>), typeof(Destination<>)).ForAllMembers(o=>o.Ignore()); - cfg.CreateMap(typeof(Source), typeof(Destination<>)).ForAllMembers(o => o.Ignore()); - cfg.CreateMap(typeof(Source), typeof(Destination<>)); - }); - [Fact] - public void Should_work() - { - Mapper.Map>(new Source { Value = 42 }).Value.ShouldBe(42); - Mapper.Map>(new Source { Value = "42" }).Value.ShouldBe("42"); - } + public T Value1 { get; set; } } - public class GenericMapWithUntypedMap : AutoMapperSpecBase + public class BarBase { - class Source - { - public T Value; - } - class Destination - { - public T Value; - } - protected override MapperConfiguration CreateConfiguration() => new(cfg=>cfg.CreateMap(typeof(Source<>), typeof(Destination<>))); - [Fact] - public void Should_work() => new Action(() => Mapper.Map(new Source(), null, typeof(Destination<>))) - .ShouldThrow().Message.ShouldStartWith($"Type {typeof(Destination<>).FullName}[T] is a generic type definition"); + public T Value2 { get; set; } } - public class GenericValueResolverTypeMismatch : AutoMapperSpecBase + public class Bar : BarBase { - class Source - { - public T Value; - } - class Destination - { - public string Value; - } - protected override MapperConfiguration CreateConfiguration() => new(cfg=> - cfg.CreateMap(typeof(Source<>), typeof(Destination)).ForMember("Value", o => o.MapFrom(typeof(ValueResolver<>)))); - class ValueResolver : IValueResolver, Destination, object> - { - public object Resolve(Source source, Destination destination, object destMember, ResolutionContext context) => int.MaxValue; - } - [Fact] - public void Should_map_ok() => Map(new Source()).Value.ShouldBe(int.MaxValue.ToString()); } - public class GenericValueResolver : AutoMapperSpecBase + protected override MapperConfiguration CreateConfiguration() => new(mapper => mapper.CreateMap(typeof(Foo<>), typeof(Bar<>)).ForMember("Value2", to => to.MapFrom("Value1"))); + [Fact] + public void Can_map_base_members() => Map>(new Foo { Value1 = 5 }).Value2.ShouldBe(5); +} +public class GenericMapsAsNonGeneric : AutoMapperSpecBase +{ + class Source { - class Destination - { - public string MyKey; - public string MyValue; - } - class Destination - { - public TKey MyKey; - public TValue MyValue; - } + public int Value; + } + class Destination + { + public T Value; + } + class NonGenericDestination : Destination + { + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(typeof(Source), typeof(Destination<>)).As(typeof(NonGenericDestination)); + cfg.CreateMap(typeof(Source), typeof(NonGenericDestination)); + }); + [Fact] + public void Should_work() => Mapper.Map>(new Source { Value = 42 }).Value.ShouldBe("42"); +} +public class GenericMapsPriority : AutoMapperSpecBase +{ + class Source + { + public T Value; + } + class Destination + { + public T Value; + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(typeof(Source<>), typeof(Destination)); + cfg.CreateMap(typeof(Source<>), typeof(Destination<>)).ForAllMembers(o=>o.Ignore()); + cfg.CreateMap(typeof(Source), typeof(Destination<>)).ForAllMembers(o => o.Ignore()); + cfg.CreateMap(typeof(Source), typeof(Destination<>)); + }); + [Fact] + public void Should_work() + { + Mapper.Map>(new Source { Value = 42 }).Value.ShouldBe(42); + Mapper.Map>(new Source { Value = "42" }).Value.ShouldBe("42"); + } +} +public class GenericMapWithUntypedMap : AutoMapperSpecBase +{ + class Source + { + public T Value; + } + class Destination + { + public T Value; + } + protected override MapperConfiguration CreateConfiguration() => new(cfg=>cfg.CreateMap(typeof(Source<>), typeof(Destination<>))); + [Fact] + public void Should_work() => new Action(() => Mapper.Map(new Source(), null, typeof(Destination<>))) + .ShouldThrow().Message.ShouldStartWith($"Type {typeof(Destination<>).FullName}[T] is a generic type definition"); +} +public class GenericValueResolverTypeMismatch : AutoMapperSpecBase +{ + class Source + { + public T Value; + } + class Destination + { + public string Value; + } + protected override MapperConfiguration CreateConfiguration() => new(cfg=> + cfg.CreateMap(typeof(Source<>), typeof(Destination)).ForMember("Value", o => o.MapFrom(typeof(ValueResolver<>)))); + class ValueResolver : IValueResolver, Destination, object> + { + public object Resolve(Source source, Destination destination, object destMember, ResolutionContext context) => int.MaxValue; + } + [Fact] + public void Should_map_ok() => Map(new Source()).Value.ShouldBe(int.MaxValue.ToString()); +} +public class GenericValueResolver : AutoMapperSpecBase +{ + class Destination + { + public string MyKey; + public string MyValue; + } + class Destination + { + public TKey MyKey; + public TValue MyValue; + } - class Source - { - public IEnumerable MyValues; - } + class Source + { + public IEnumerable MyValues; + } - class Source - { - public IEnumerable MyValues; - } + class Source + { + public IEnumerable MyValues; + } - class Destination - { - public IEnumerable MyValues; - } + class Destination + { + public IEnumerable MyValues; + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(typeof(KeyValuePair<,>), typeof(Destination)) - .ForMember("MyKey", o => o.MapFrom(typeof(KeyResolver<>))) - .ForMember("MyValue", o => o.MapFrom(typeof(ValueResolver<,>))); - cfg.CreateMap(typeof(KeyValuePair<,>), typeof(Destination<,>)) - .ForMember("MyKey", o => o.MapFrom(typeof(KeyResolver<,,>))) - .ForMember("MyValue", o => o.MapFrom(typeof(ValueResolver<,,,>))); - cfg.CreateMap(typeof(Source), typeof(Destination<>)) - .ForMember("MyValues", o => o.MapFrom(typeof(ValuesResolver<>))); - cfg.CreateMap(typeof(Source<>), typeof(Destination<>)) - .ForMember("MyValues", o => o.MapFrom(typeof(ValuesResolver<,>))); - }); - private class KeyResolver : IValueResolver, Destination, string> - { - public string Resolve(KeyValuePair source, Destination destination, string destMember, ResolutionContext context) => source.Key.ToString(); - } - private class ValueResolver : IValueResolver, Destination, string> - { - public string Resolve(KeyValuePair source, Destination destination, string destMember, ResolutionContext context) => source.Value.ToString(); - } - private class KeyResolver - : IValueResolver, Destination, string> - { - public string Resolve(KeyValuePair source, Destination destination, string destMember, ResolutionContext context) - => source.Key.ToString(); - } - private class ValueResolver - : IValueResolver, Destination, string> - { - public string Resolve(KeyValuePair source, Destination destination, string destMember, ResolutionContext context) - => source.Value.ToString(); - } - private class ValuesResolver - : IValueResolver, IEnumerable> + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(typeof(KeyValuePair<,>), typeof(Destination)) + .ForMember("MyKey", o => o.MapFrom(typeof(KeyResolver<>))) + .ForMember("MyValue", o => o.MapFrom(typeof(ValueResolver<,>))); + cfg.CreateMap(typeof(KeyValuePair<,>), typeof(Destination<,>)) + .ForMember("MyKey", o => o.MapFrom(typeof(KeyResolver<,,>))) + .ForMember("MyValue", o => o.MapFrom(typeof(ValueResolver<,,,>))); + cfg.CreateMap(typeof(Source), typeof(Destination<>)) + .ForMember("MyValues", o => o.MapFrom(typeof(ValuesResolver<>))); + cfg.CreateMap(typeof(Source<>), typeof(Destination<>)) + .ForMember("MyValues", o => o.MapFrom(typeof(ValuesResolver<,>))); + }); + private class KeyResolver : IValueResolver, Destination, string> + { + public string Resolve(KeyValuePair source, Destination destination, string destMember, ResolutionContext context) => source.Key.ToString(); + } + private class ValueResolver : IValueResolver, Destination, string> + { + public string Resolve(KeyValuePair source, Destination destination, string destMember, ResolutionContext context) => source.Value.ToString(); + } + private class KeyResolver + : IValueResolver, Destination, string> + { + public string Resolve(KeyValuePair source, Destination destination, string destMember, ResolutionContext context) + => source.Key.ToString(); + } + private class ValueResolver + : IValueResolver, Destination, string> + { + public string Resolve(KeyValuePair source, Destination destination, string destMember, ResolutionContext context) + => source.Value.ToString(); + } + private class ValuesResolver + : IValueResolver, IEnumerable> + { + public IEnumerable Resolve(Source source, Destination destination, IEnumerable destMember, ResolutionContext context) { - public IEnumerable Resolve(Source source, Destination destination, IEnumerable destMember, ResolutionContext context) + foreach (var item in source.MyValues) { - foreach (var item in source.MyValues) - { - yield return (TDestination)((object)item); - } + yield return (TDestination)((object)item); } } - private class ValuesResolver - : IValueResolver, Destination, IEnumerable> + } + private class ValuesResolver + : IValueResolver, Destination, IEnumerable> + { + public IEnumerable Resolve(Source source, Destination destination, IEnumerable destMember, ResolutionContext context) { - public IEnumerable Resolve(Source source, Destination destination, IEnumerable destMember, ResolutionContext context) + foreach (var item in source.MyValues) { - foreach (var item in source.MyValues) - { - yield return (TDestination)((object)item); - } + yield return (TDestination)((object)item); } } - [Fact] - public void Should_map_non_generic_destination() - { - var destination = Map(new KeyValuePair(1,2)); - destination.MyKey.ShouldBe("1"); - destination.MyValue.ShouldBe("2"); - } - [Fact] - public void Should_map_generic_destination() - { - var destination = Map>(new KeyValuePair(1, 2)); - destination.MyKey.ShouldBe("1"); - destination.MyValue.ShouldBe("2"); - var destinationString = Map>(new KeyValuePair("1", "2")); - destinationString.MyKey.ShouldBe("1"); - destinationString.MyValue.ShouldBe("2"); - } - [Fact] - public void Should_map_closed_to_ienumerable_generic_destination() - { - var source = new Source { MyValues = new int[] { 1, 2 } }; - var destination = Map>(source); - destination.MyValues.ShouldBe(source.MyValues); - } - [Fact] - public void Should_map_ienumerable_generic_destination() - { - var source = new Source { MyValues = new int[] { 1, 2 } }; - var destination = Map>(source); - destination.MyValues.ShouldBe(source.MyValues); - } } + [Fact] + public void Should_map_non_generic_destination() + { + var destination = Map(new KeyValuePair(1,2)); + destination.MyKey.ShouldBe("1"); + destination.MyValue.ShouldBe("2"); + } + [Fact] + public void Should_map_generic_destination() + { + var destination = Map>(new KeyValuePair(1, 2)); + destination.MyKey.ShouldBe("1"); + destination.MyValue.ShouldBe("2"); + var destinationString = Map>(new KeyValuePair("1", "2")); + destinationString.MyKey.ShouldBe("1"); + destinationString.MyValue.ShouldBe("2"); + } + [Fact] + public void Should_map_closed_to_ienumerable_generic_destination() + { + var source = new Source { MyValues = new int[] { 1, 2 } }; + var destination = Map>(source); + destination.MyValues.ShouldBe(source.MyValues); + } + [Fact] + public void Should_map_ienumerable_generic_destination() + { + var source = new Source { MyValues = new int[] { 1, 2 } }; + var destination = Map>(source); + destination.MyValues.ShouldBe(source.MyValues); + } +} - public class GenericMemberValueResolver : AutoMapperSpecBase +public class GenericMemberValueResolver : AutoMapperSpecBase +{ + class Destination { - class Destination - { - public string MyKey; - public string MyValue; - } - class Destination - { - public TKey MyKey; - public TValue MyValue; - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(typeof(KeyValuePair<,>), typeof(Destination)) - .ForMember("MyKey", o => o.MapFrom(typeof(Resolver<>), "Key")) - .ForMember("MyValue", o => o.MapFrom(typeof(Resolver<,>), "Value")); - cfg.CreateMap(typeof(KeyValuePair<,>), typeof(Destination<,>)) - .ForMember("MyKey", o => o.MapFrom(typeof(Resolver<,,>), "Key")) - .ForMember("MyValue", o => o.MapFrom(typeof(Resolver<,,,>), "Value")); - }); - private class Resolver : IMemberValueResolver, Destination, int, string> - { - public string Resolve(KeyValuePair source, Destination destination, int sourceMember, string destMember, ResolutionContext context) => sourceMember.ToString(); - } - private class Resolver : IMemberValueResolver, Destination, int, string> - { - public string Resolve(KeyValuePair source, Destination destination, int sourceMember, string destMember, ResolutionContext context) => sourceMember.ToString(); - } - private class Resolver : IMemberValueResolver, Destination, int, string> - { - public string Resolve(KeyValuePair source, Destination destination, int sourceMember, string destMember, ResolutionContext context) => sourceMember.ToString(); - } - private class Resolver : IMemberValueResolver, Destination, int, string> - { - public string Resolve(KeyValuePair source, Destination destination, int sourceMember, string destMember, ResolutionContext context) => sourceMember.ToString(); - } - [Fact] - public void Should_map_non_generic_destination() - { - var destination = Map(new KeyValuePair(1, 2)); - destination.MyKey.ShouldBe("1"); - destination.MyValue.ShouldBe("2"); - } - [Fact] - public void Should_map_generic_destination() - { - var destination = Map>(new KeyValuePair(1, 2)); - destination.MyKey.ShouldBe("1"); - destination.MyValue.ShouldBe("2"); - } + public string MyKey; + public string MyValue; + } + class Destination + { + public TKey MyKey; + public TValue MyValue; } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(typeof(KeyValuePair<,>), typeof(Destination)) + .ForMember("MyKey", o => o.MapFrom(typeof(Resolver<>), "Key")) + .ForMember("MyValue", o => o.MapFrom(typeof(Resolver<,>), "Value")); + cfg.CreateMap(typeof(KeyValuePair<,>), typeof(Destination<,>)) + .ForMember("MyKey", o => o.MapFrom(typeof(Resolver<,,>), "Key")) + .ForMember("MyValue", o => o.MapFrom(typeof(Resolver<,,,>), "Value")); + }); + private class Resolver : IMemberValueResolver, Destination, int, string> + { + public string Resolve(KeyValuePair source, Destination destination, int sourceMember, string destMember, ResolutionContext context) => sourceMember.ToString(); + } + private class Resolver : IMemberValueResolver, Destination, int, string> + { + public string Resolve(KeyValuePair source, Destination destination, int sourceMember, string destMember, ResolutionContext context) => sourceMember.ToString(); + } + private class Resolver : IMemberValueResolver, Destination, int, string> + { + public string Resolve(KeyValuePair source, Destination destination, int sourceMember, string destMember, ResolutionContext context) => sourceMember.ToString(); + } + private class Resolver : IMemberValueResolver, Destination, int, string> + { + public string Resolve(KeyValuePair source, Destination destination, int sourceMember, string destMember, ResolutionContext context) => sourceMember.ToString(); + } + [Fact] + public void Should_map_non_generic_destination() + { + var destination = Map(new KeyValuePair(1, 2)); + destination.MyKey.ShouldBe("1"); + destination.MyValue.ShouldBe("2"); + } + [Fact] + public void Should_map_generic_destination() + { + var destination = Map>(new KeyValuePair(1, 2)); + destination.MyKey.ShouldBe("1"); + destination.MyValue.ShouldBe("2"); + } +} - public class RecursiveOpenGenerics : AutoMapperSpecBase +public class RecursiveOpenGenerics : AutoMapperSpecBase +{ + public class SourceTree { - public class SourceTree + public SourceTree(T value, SourceTree[] children) { - public SourceTree(T value, SourceTree[] children) - { - Value = value; - Children = children; - } + Value = value; + Children = children; + } - public T Value { get; } + public T Value { get; } - public SourceTree[] Children { get; } - } + public SourceTree[] Children { get; } + } - public class DestinationTree + public class DestinationTree + { + public DestinationTree(T value, DestinationTree[] children) { - public DestinationTree(T value, DestinationTree[] children) - { - Value = value; - Children = children; - } + Value = value; + Children = children; + } - public T Value { get; } + public T Value { get; } - public DestinationTree[] Children { get; } - } + public DestinationTree[] Children { get; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.CreateMap(typeof(SourceTree<>), typeof(DestinationTree<>))); + protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.CreateMap(typeof(SourceTree<>), typeof(DestinationTree<>))); - [Fact] - public void Should_work() - { - var source = new SourceTree("value", new SourceTree[0]); - Mapper.Map>(source).Value.ShouldBe("value"); - } + [Fact] + public void Should_work() + { + var source = new SourceTree("value", new SourceTree[0]); + Mapper.Map>(source).Value.ShouldBe("value"); } +} - public class OpenGenericsValidation : NonValidatingSpecBase +public class OpenGenericsValidation : NonValidatingSpecBase +{ + public class Source { - public class Source - { - public T Value { get; set; } - } + public T Value { get; set; } + } - public class Dest - { - public int A { get; set; } - public T Value { get; set; } - } + public class Dest + { + public int A { get; set; } + public T Value { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.CreateMap(typeof(Source<>), typeof(Dest<>))); + protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.CreateMap(typeof(Source<>), typeof(Dest<>))); - [Fact] - public void Should_report_unmapped_property() - { - new Action(Configuration.AssertConfigurationIsValid) - .ShouldThrow() - .Errors.Single().UnmappedPropertyNames.Single().ShouldBe("A"); - } + [Fact] + public void Should_report_unmapped_property() + { + new Action(Configuration.AssertConfigurationIsValid) + .ShouldThrow() + .Errors.Single().UnmappedPropertyNames.Single().ShouldBe("A"); } +} - public class OpenGenericsProfileValidationNonGenericMembers : NonValidatingSpecBase +public class OpenGenericsProfileValidationNonGenericMembers : NonValidatingSpecBase +{ + public class Source { - public class Source - { - public T[] Value { get; set; } - } + public T[] Value { get; set; } + } - public class Dest - { - public int A { get; set; } - public T[] Value { get; set; } - } + public class Dest + { + public int A { get; set; } + public T[] Value { get; set; } + } - class MyProfile : Profile + class MyProfile : Profile + { + public MyProfile() { - public MyProfile() - { - CreateMap(typeof(Source<>), typeof(Dest<>)); - } + CreateMap(typeof(Source<>), typeof(Dest<>)); } + } + + protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.AddProfile()); - protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.AddProfile()); + [Fact] + public void Should_report_unmapped_property() => + new Action(()=> AssertConfigurationIsValid()) + .ShouldThrow() + .Errors.Single().UnmappedPropertyNames.Single().ShouldBe("A"); +} - [Fact] - public void Should_report_unmapped_property() => - new Action(()=> AssertConfigurationIsValid()) - .ShouldThrow() - .Errors.Single().UnmappedPropertyNames.Single().ShouldBe("A"); +public class OpenGenericsProfileValidation : AutoMapperSpecBase +{ + public class Source + { + public T[] Value { get; set; } } - public class OpenGenericsProfileValidation : AutoMapperSpecBase + public class Dest { - public class Source - { - public T[] Value { get; set; } - } + public T[] Value { get; set; } + } - public class Dest + class MyProfile : Profile + { + public MyProfile() { - public T[] Value { get; set; } + CreateMap(typeof(Source<>), typeof(Dest<>)); } + } - class MyProfile : Profile - { - public MyProfile() - { - CreateMap(typeof(Source<>), typeof(Dest<>)); - } - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.AddProfile()); + [Fact] + public void Validate() => AssertConfigurationIsValid(); +} - protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.AddProfile()); - [Fact] - public void Validate() => AssertConfigurationIsValid(); +public class OpenGenerics +{ + public class Source + { + public int A { get; set; } + public T Value { get; set; } } - public class OpenGenerics + public class Dest { - public class Source - { - public int A { get; set; } - public T Value { get; set; } - } + public int A { get; set; } + public T Value { get; set; } + } - public class Dest - { - public int A { get; set; } - public T Value { get; set; } - } + [Fact] + public void Can_map_simple_generic_types() + { + var config = new MapperConfiguration(cfg => cfg.CreateMap(typeof(Source<>), typeof(Dest<>))); - [Fact] - public void Can_map_simple_generic_types() + var source = new Source { - var config = new MapperConfiguration(cfg => cfg.CreateMap(typeof(Source<>), typeof(Dest<>))); + Value = 5 + }; - var source = new Source - { - Value = 5 - }; + var dest = config.CreateMapper().Map, Dest>(source); - var dest = config.CreateMapper().Map, Dest>(source); + dest.Value.ShouldBe(5); + } - dest.Value.ShouldBe(5); - } + [Fact] + public void Can_map_non_generic_members() + { + var config = new MapperConfiguration(cfg => cfg.CreateMap(typeof(Source<>), typeof(Dest<>))); - [Fact] - public void Can_map_non_generic_members() + var source = new Source { - var config = new MapperConfiguration(cfg => cfg.CreateMap(typeof(Source<>), typeof(Dest<>))); + A = 5 + }; - var source = new Source - { - A = 5 - }; + var dest = config.CreateMapper().Map, Dest>(source); - var dest = config.CreateMapper().Map, Dest>(source); + dest.A.ShouldBe(5); + } - dest.A.ShouldBe(5); - } + [Fact] + public void Can_map_recursive_generic_types() + { + var config = new MapperConfiguration(cfg => cfg.CreateMap(typeof(Source<>), typeof(Dest<>))); - [Fact] - public void Can_map_recursive_generic_types() + var source = new Source> { - var config = new MapperConfiguration(cfg => cfg.CreateMap(typeof(Source<>), typeof(Dest<>))); - - var source = new Source> + Value = new Source { - Value = new Source - { - Value = 5, - } - }; + Value = 5, + } + }; - var dest = config.CreateMapper().Map>, Dest>>(source); + var dest = config.CreateMapper().Map>, Dest>>(source); - dest.Value.Value.ShouldBe(5); - } + dest.Value.Value.ShouldBe(5); } +} - public class OpenGenerics_With_MemberConfiguration : AutoMapperSpecBase +public class OpenGenerics_With_MemberConfiguration : AutoMapperSpecBase +{ + public class Foo { - public class Foo - { - public int A { get; set; } - public int B { get; set; } - } + public int A { get; set; } + public int B { get; set; } + } - public class Bar - { - public int C { get; set; } - public int D { get; set; } - } + public class Bar + { + public int C { get; set; } + public int D { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(mapper => { - mapper.CreateMap(typeof(Foo<>), typeof(Bar<>)) - .ForMember("C", to => to.MapFrom("A")) - .ForMember("D", to => to.MapFrom("B")); - }); + protected override MapperConfiguration CreateConfiguration() => new(mapper => { + mapper.CreateMap(typeof(Foo<>), typeof(Bar<>)) + .ForMember("C", to => to.MapFrom("A")) + .ForMember("D", to => to.MapFrom("B")); + }); - [Fact] - public void Can_remap_explicit_members() + [Fact] + public void Can_remap_explicit_members() + { + var source = new Foo { - var source = new Foo - { - A = 5, - B = 10 - }; + A = 5, + B = 10 + }; - var dest = Mapper.Map, Bar>(source); + var dest = Mapper.Map, Bar>(source); - dest.C.ShouldBe(5); - dest.D.ShouldBe(10); - } + dest.C.ShouldBe(5); + dest.D.ShouldBe(10); } +} - public class OpenGenerics_With_UntypedMapFrom : AutoMapperSpecBase +public class OpenGenerics_With_UntypedMapFrom : AutoMapperSpecBase +{ + public class Foo { - public class Foo - { - public T Value1 { get; set; } - } + public T Value1 { get; set; } + } - public class Bar - { - public T Value2 { get; set; } - } + public class Bar + { + public T Value2 { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(mapper => { - mapper.CreateMap(typeof(Foo<>), typeof(Bar<>)).ForMember("Value2", to => to.MapFrom("Value1")); - }); + protected override MapperConfiguration CreateConfiguration() => new(mapper => { + mapper.CreateMap(typeof(Foo<>), typeof(Bar<>)).ForMember("Value2", to => to.MapFrom("Value1")); + }); - [Fact] - public void Can_remap_explicit_members() - { - var dest = Mapper.Map>(new Foo { Value1 = 5 }); - dest.Value2.ShouldBe(5); - } + [Fact] + public void Can_remap_explicit_members() + { + var dest = Mapper.Map>(new Foo { Value1 = 5 }); + dest.Value2.ShouldBe(5); } +} - public class OpenGenerics_With_UntypedMapFromStructs : AutoMapperSpecBase +public class OpenGenerics_With_UntypedMapFromStructs : AutoMapperSpecBase +{ + public class Foo where T : struct { - public class Foo where T : struct - { - public T Value1 { get; set; } - } + public T Value1 { get; set; } + } - public class Bar where T : struct - { - public T Value2 { get; set; } - } + public class Bar where T : struct + { + public T Value2 { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(mapper => { - mapper.CreateMap(typeof(Foo<>), typeof(Bar<>)).ForMember("Value2", to => to.MapFrom("Value1")); - }); + protected override MapperConfiguration CreateConfiguration() => new(mapper => { + mapper.CreateMap(typeof(Foo<>), typeof(Bar<>)).ForMember("Value2", to => to.MapFrom("Value1")); + }); - [Fact] - public void Can_remap_explicit_members() - { - var dest = Mapper.Map>(new Foo { Value1 = 5 }); - dest.Value2.ShouldBe(5); - } + [Fact] + public void Can_remap_explicit_members() + { + var dest = Mapper.Map>(new Foo { Value1 = 5 }); + dest.Value2.ShouldBe(5); } } \ No newline at end of file diff --git a/src/UnitTests/Projection/ConstructorTests.cs b/src/UnitTests/Projection/ConstructorTests.cs index aebfc9affe..60e973ce34 100644 --- a/src/UnitTests/Projection/ConstructorTests.cs +++ b/src/UnitTests/Projection/ConstructorTests.cs @@ -4,234 +4,233 @@ using Shouldly; using Xunit; -namespace AutoMapper.UnitTests.Projection +namespace AutoMapper.UnitTests.Projection; + +public class ConstructorLetClause : AutoMapperSpecBase { - public class ConstructorLetClause : AutoMapperSpecBase + class Source { - class Source - { - public IList Items { get; set; } - } - class SourceItem - { - public IList Values { get; set; } - } - class SourceValue - { - public int Value1 { get; set; } - public int Value2 { get; set; } - } - class Destination - { - public Destination(DestinationItem item) => Item = item; - public DestinationItem Item { get; } - } - class DestinationValue - { - public DestinationValue(int value1, int value2) - { - Value1 = value1; - Value2 = value2; - } - public int Value1 { get; } - public int Value2 { get; } - } - class DestinationItem - { - public DestinationItem(DestinationValue destinationValue) - { - Value1 = destinationValue.Value1; - Value2 = destinationValue.Value2; - } - public int Value1 { get; } - public int Value2 { get; } - public IList Values { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateProjection().ForCtorParam("item", o => o.MapFrom(s => s.Items.FirstOrDefault())); - cfg.CreateProjection().ForCtorParam("destinationValue", o=>o.MapFrom(s=>s.Values.FirstOrDefault())); - cfg.CreateProjection(); - }); - [Fact] - public void Should_construct_correctly() - { - var query = new[] { new Source { Items = new[] { new SourceItem { Values = new[] { new SourceValue { Value1 = 1, Value2 = 2 } } } } } }.AsQueryable().ProjectTo(Configuration); - var first = query.First(); - first.Item.Value1.ShouldBe(1); - first.Item.Value2.ShouldBe(2); - var firstValue = first.Item.Values.Single(); - firstValue.Value1.ShouldBe(1); - firstValue.Value2.ShouldBe(2); - } + public IList Items { get; set; } } - public class ConstructorToString : AutoMapperSpecBase + class SourceItem { - class Source - { - public int Value { get; set; } - } - class Destination - { - public Destination(string value) => Value = value; - public string Value { get; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.CreateProjection()); - [Fact] - public void Should_construct_correctly() => new[] { new Source { Value = 5 } }.AsQueryable().ProjectTo(Configuration).First().Value.ShouldBe("5"); + public IList Values { get; set; } } - public class ConstructorMapFrom : AutoMapperSpecBase + class SourceValue { - class Source - { - public int Value { get; set; } - } - record Destination(bool Value) - { - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - cfg.CreateProjection().ForCtorParam(nameof(Destination.Value), o=>o.MapFrom(s=>s.Value==5))); - [Fact] - public void Should_construct_correctly() => new[] { new Source { Value = 5 } }.AsQueryable().ProjectTo(Configuration).First().Value.ShouldBeTrue(); + public int Value1 { get; set; } + public int Value2 { get; set; } } - public class ConstructorIncludeMembers : AutoMapperSpecBase + class Destination { - class SourceWrapper - { - public Source Source { get; set; } - } - class Source - { - public int Value { get; set; } - } - class Destination - { - public Destination(string value) => Value = value; - public string Value { get; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateProjection().IncludeMembers(s => s.Source); - cfg.CreateProjection(); - }); - [Fact] - public void Should_construct_correctly() => new[] { new SourceWrapper { Source = new Source { Value = 5 } } }.AsQueryable().ProjectTo(Configuration).First().Value.ShouldBe("5"); + public Destination(DestinationItem item) => Item = item; + public DestinationItem Item { get; } } - public class ConstructorsWithCollections : AutoMapperSpecBase + class DestinationValue { - class Addresses + public DestinationValue(int value1, int value2) { - public int Id { get; set; } - public string Address { get; set; } - public ICollection Users { get; set; } + Value1 = value1; + Value2 = value2; } - class Users + public int Value1 { get; } + public int Value2 { get; } + } + class DestinationItem + { + public DestinationItem(DestinationValue destinationValue) { - public int Id { get; set; } - public Addresses FkAddress { get; set; } + Value1 = destinationValue.Value1; + Value2 = destinationValue.Value2; } - class AddressDto - { - public int Id { get; } - public string Address { get; } - public AddressDto(int id, string address) - { - Id = id; - Address = address; - } - } - class UserDto + public int Value1 { get; } + public int Value2 { get; } + public IList Values { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateProjection().ForCtorParam("item", o => o.MapFrom(s => s.Items.FirstOrDefault())); + cfg.CreateProjection().ForCtorParam("destinationValue", o=>o.MapFrom(s=>s.Values.FirstOrDefault())); + cfg.CreateProjection(); + }); + [Fact] + public void Should_construct_correctly() + { + var query = new[] { new Source { Items = new[] { new SourceItem { Values = new[] { new SourceValue { Value1 = 1, Value2 = 2 } } } } } }.AsQueryable().ProjectTo(Configuration); + var first = query.First(); + first.Item.Value1.ShouldBe(1); + first.Item.Value2.ShouldBe(2); + var firstValue = first.Item.Values.Single(); + firstValue.Value1.ShouldBe(1); + firstValue.Value2.ShouldBe(2); + } +} +public class ConstructorToString : AutoMapperSpecBase +{ + class Source + { + public int Value { get; set; } + } + class Destination + { + public Destination(string value) => Value = value; + public string Value { get; } + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.CreateProjection()); + [Fact] + public void Should_construct_correctly() => new[] { new Source { Value = 5 } }.AsQueryable().ProjectTo(Configuration).First().Value.ShouldBe("5"); +} +public class ConstructorMapFrom : AutoMapperSpecBase +{ + class Source + { + public int Value { get; set; } + } + record Destination(bool Value) + { + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + cfg.CreateProjection().ForCtorParam(nameof(Destination.Value), o=>o.MapFrom(s=>s.Value==5))); + [Fact] + public void Should_construct_correctly() => new[] { new Source { Value = 5 } }.AsQueryable().ProjectTo(Configuration).First().Value.ShouldBeTrue(); +} +public class ConstructorIncludeMembers : AutoMapperSpecBase +{ + class SourceWrapper + { + public Source Source { get; set; } + } + class Source + { + public int Value { get; set; } + } + class Destination + { + public Destination(string value) => Value = value; + public string Value { get; } + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateProjection().IncludeMembers(s => s.Source); + cfg.CreateProjection(); + }); + [Fact] + public void Should_construct_correctly() => new[] { new SourceWrapper { Source = new Source { Value = 5 } } }.AsQueryable().ProjectTo(Configuration).First().Value.ShouldBe("5"); +} +public class ConstructorsWithCollections : AutoMapperSpecBase +{ + class Addresses + { + public int Id { get; set; } + public string Address { get; set; } + public ICollection Users { get; set; } + } + class Users + { + public int Id { get; set; } + public Addresses FkAddress { get; set; } + } + class AddressDto + { + public int Id { get; } + public string Address { get; } + public AddressDto(int id, string address) { - public int Id { get; set; } - public AddressDto AddressDto { get; set; } + Id = id; + Address = address; } - protected override MapperConfiguration CreateConfiguration() => new(cfg=> - { - cfg.CreateProjection().ForMember(d => d.AddressDto, e => e.MapFrom(s => s.FkAddress)); - cfg.CreateProjection().ConstructUsing(a => new AddressDto(a.Id, a.Address)); - }); - [Fact] - public void Should_work() => ProjectTo(new[] { new Users { FkAddress = new Addresses { Address = "address" } } }.AsQueryable()).First().AddressDto.Address.ShouldBe("address"); } - public class ConstructorTests : AutoMapperSpecBase + class UserDto { - private Dest[] _dest; + public int Id { get; set; } + public AddressDto AddressDto { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(cfg=> + { + cfg.CreateProjection().ForMember(d => d.AddressDto, e => e.MapFrom(s => s.FkAddress)); + cfg.CreateProjection().ConstructUsing(a => new AddressDto(a.Id, a.Address)); + }); + [Fact] + public void Should_work() => ProjectTo(new[] { new Users { FkAddress = new Addresses { Address = "address" } } }.AsQueryable()).First().AddressDto.Address.ShouldBe("address"); +} +public class ConstructorTests : AutoMapperSpecBase +{ + private Dest[] _dest; - public class Source + public class Source + { + public int Value { get; set; } + } + + public class Dest + { + public Dest() { - public int Value { get; set; } + } - - public class Dest + public Dest(int other) { - public Dest() - { - - } - public Dest(int other) - { - Other = other; - } - - public int Value { get; set; } - [IgnoreMap] - public int Other { get; set; } + Other = other; } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.AddIgnoreMapAttribute(); - cfg.CreateProjection() - .ConstructUsing(src => new Dest(src.Value + 10)); - }); + public int Value { get; set; } + [IgnoreMap] + public int Other { get; set; } + } + + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.AddIgnoreMapAttribute(); + cfg.CreateProjection() + .ConstructUsing(src => new Dest(src.Value + 10)); + }); - protected override void Because_of() + protected override void Because_of() + { + var values = new[] { - var values = new[] + new Source() { - new Source() - { - Value = 5 - } - }.AsQueryable(); + Value = 5 + } + }.AsQueryable(); - _dest = values.ProjectTo(Configuration).ToArray(); - } + _dest = values.ProjectTo(Configuration).ToArray(); + } - [Fact] - public void Should_construct_correctly() - { - _dest[0].Other.ShouldBe(15); - } + [Fact] + public void Should_construct_correctly() + { + _dest[0].Other.ShouldBe(15); } - public class NestedConstructors : AutoMapperSpecBase +} +public class NestedConstructors : AutoMapperSpecBase +{ + public class A { - public class A - { - public int Id { get; set; } - public B B { get; set; } - } - public class B - { - public int Id { get; set; } - } - public class DtoA - { - public DtoB B { get; } - public DtoA(DtoB b) => B = b; - } - public class DtoB - { - public int Id { get; } - public DtoB(int id) => Id = id; - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateProjection(); - cfg.CreateProjection(); - }); - [Fact] - public void Should_project_ok() => - ProjectTo(new[] { new A { B = new B { Id = 3 } } }.AsQueryable()).FirstOrDefault().B.Id.ShouldBe(3); + public int Id { get; set; } + public B B { get; set; } } + public class B + { + public int Id { get; set; } + } + public class DtoA + { + public DtoB B { get; } + public DtoA(DtoB b) => B = b; + } + public class DtoB + { + public int Id { get; } + public DtoB(int id) => Id = id; + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateProjection(); + cfg.CreateProjection(); + }); + [Fact] + public void Should_project_ok() => + ProjectTo(new[] { new A { B = new B { Id = 3 } } }.AsQueryable()).FirstOrDefault().B.Id.ShouldBe(3); } \ No newline at end of file diff --git a/src/UnitTests/Projection/ExplicitExpansion.cs b/src/UnitTests/Projection/ExplicitExpansion.cs index 217ccc1caf..e8d9457a21 100644 --- a/src/UnitTests/Projection/ExplicitExpansion.cs +++ b/src/UnitTests/Projection/ExplicitExpansion.cs @@ -1,78 +1,77 @@ -namespace AutoMapper.UnitTests.Projection +namespace AutoMapper.UnitTests.Projection; + +using System.Linq; +using QueryableExtensions; +using Shouldly; +using Xunit; + +public class ExplicitExpansion : AutoMapperSpecBase { - using System.Linq; - using QueryableExtensions; - using Shouldly; - using Xunit; + private Dest[] _dests; - public class ExplicitExpansion : AutoMapperSpecBase + public class Source { - private Dest[] _dests; - - public class Source - { - public ChildSource Child1 { get; set; } - public ChildSource Child2 { get; set; } - public ChildSource Child3 { get; set; } - } + public ChildSource Child1 { get; set; } + public ChildSource Child2 { get; set; } + public ChildSource Child3 { get; set; } + } - public class ChildSource - { - - } + public class ChildSource + { + + } - public class Dest - { - public ChildDest Child1 { get; set; } - public ChildDest Child2 { get; set; } - public ChildDest Child3 { get; set; } - } + public class Dest + { + public ChildDest Child1 { get; set; } + public ChildDest Child2 { get; set; } + public ChildDest Child3 { get; set; } + } - public class ChildDest - { - } + public class ChildDest + { + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateProjection() - .ForMember(m => m.Child1, opt => opt.ExplicitExpansion()) - .ForMember(m => m.Child2, opt => opt.ExplicitExpansion()) - ; - cfg.CreateProjection(); - }); - + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateProjection() + .ForMember(m => m.Child1, opt => opt.ExplicitExpansion()) + .ForMember(m => m.Child2, opt => opt.ExplicitExpansion()) + ; + cfg.CreateProjection(); + }); + - protected override void Because_of() + protected override void Because_of() + { + var sourceList = new[] { - var sourceList = new[] + new Source { - new Source - { - Child1 = new ChildSource(), - Child2 = new ChildSource(), - Child3 = new ChildSource() - } - }; + Child1 = new ChildSource(), + Child2 = new ChildSource(), + Child3 = new ChildSource() + } + }; - _dests = sourceList.AsQueryable().ProjectTo(Configuration, d => d.Child2).ToArray(); - } + _dests = sourceList.AsQueryable().ProjectTo(Configuration, d => d.Child2).ToArray(); + } - [Fact] - public void Should_leave_non_expanded_item_null() - { - _dests[0].Child1.ShouldBeNull(); - } + [Fact] + public void Should_leave_non_expanded_item_null() + { + _dests[0].Child1.ShouldBeNull(); + } - [Fact] - public void Should_expand_explicitly_expanded_item() - { - _dests[0].Child2.ShouldNotBeNull(); - } + [Fact] + public void Should_expand_explicitly_expanded_item() + { + _dests[0].Child2.ShouldNotBeNull(); + } - [Fact] - public void Should_default_to_expand() - { - _dests[0].Child3.ShouldNotBeNull(); - } + [Fact] + public void Should_default_to_expand() + { + _dests[0].Child3.ShouldNotBeNull(); } } \ No newline at end of file diff --git a/src/UnitTests/Projection/ExplicitExpansionWithInheritance.cs b/src/UnitTests/Projection/ExplicitExpansionWithInheritance.cs index 84aa3cad88..cd42517d24 100644 --- a/src/UnitTests/Projection/ExplicitExpansionWithInheritance.cs +++ b/src/UnitTests/Projection/ExplicitExpansionWithInheritance.cs @@ -6,124 +6,123 @@ using System.Threading.Tasks; using Xunit; -namespace AutoMapper.UnitTests.Projection +namespace AutoMapper.UnitTests.Projection; + +public class ExplicitExpansionWithInheritance : AutoMapperSpecBase { - public class ExplicitExpansionWithInheritance : AutoMapperSpecBase + abstract class EntityBase { - abstract class EntityBase - { - public EntityBase() => Id = Guid.NewGuid(); - public Guid Id { get; set; } - public User CreatedBy { get; set; } - public User ModifiedBy { get; set; } - } - - class User { } - class Computer : EntityBase { } - class Script : EntityBase - { - public Computer Computer { get; set; } - public Computer OtherComputer { get; set; } - } + public EntityBase() => Id = Guid.NewGuid(); + public Guid Id { get; set; } + public User CreatedBy { get; set; } + public User ModifiedBy { get; set; } + } - class EntityBaseModel - { - public Guid Id { get; set; } - public UserModel CreatedBy { get; set; } - public UserModel ModifiedBy { get; set; } - } - - class UserModel { } - class ComputerModel : EntityBaseModel { } - class ScriptModel : EntityBaseModel - { - public ComputerModel Computer { get; set; } - public ComputerModel OtherComputer { get; set; } - } + class User { } + class Computer : EntityBase { } + class Script : EntityBase + { + public Computer Computer { get; set; } + public Computer OtherComputer { get; set; } + } - private Script _source; + class EntityBaseModel + { + public Guid Id { get; set; } + public UserModel CreatedBy { get; set; } + public UserModel ModifiedBy { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateProjection(); - cfg.CreateProjection() - .ForMember(d => d.ModifiedBy, o => o.ExplicitExpansion()) - .ForMember(d => d.CreatedBy, o => o.ExplicitExpansion()); - cfg.CreateProjection() - .ForMember(d => d.ModifiedBy, o => o.ExplicitExpansion()) - .ForMember(d => d.CreatedBy, o => o.ExplicitExpansion()); - cfg.CreateProjection() - .ForMember(d => d.Computer, o => o.ExplicitExpansion()) - .ForMember(d => d.ModifiedBy, o => o.ExplicitExpansion()) - .ForMember(d => d.CreatedBy, o => o.ExplicitExpansion()); - }); - - protected override void Because_of() + class UserModel { } + class ComputerModel : EntityBaseModel { } + class ScriptModel : EntityBaseModel + { + public ComputerModel Computer { get; set; } + public ComputerModel OtherComputer { get; set; } + } + + private Script _source; + + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateProjection(); + cfg.CreateProjection() + .ForMember(d => d.ModifiedBy, o => o.ExplicitExpansion()) + .ForMember(d => d.CreatedBy, o => o.ExplicitExpansion()); + cfg.CreateProjection() + .ForMember(d => d.ModifiedBy, o => o.ExplicitExpansion()) + .ForMember(d => d.CreatedBy, o => o.ExplicitExpansion()); + cfg.CreateProjection() + .ForMember(d => d.Computer, o => o.ExplicitExpansion()) + .ForMember(d => d.ModifiedBy, o => o.ExplicitExpansion()) + .ForMember(d => d.CreatedBy, o => o.ExplicitExpansion()); + }); + + protected override void Because_of() + { + _source = new Script { - _source = new Script + CreatedBy = new User(), + ModifiedBy = new User(), + Computer = new Computer() { CreatedBy = new User(), ModifiedBy = new User(), - Computer = new Computer() - { - CreatedBy = new User(), - ModifiedBy = new User(), - }, - OtherComputer = new Computer() - { - CreatedBy = new User(), - ModifiedBy = new User(), - } - }; - } - - [Fact] - public void ComputerCreatedBy_should_be_null_but_ScriptCreatedBy_should_not_be_null_using_lambda_expression_expansions() - { - // act - var scriptModel = new[] { _source }.AsQueryable() - .ProjectTo(Configuration, c => c.Computer, c => c.CreatedBy).Single(); + }, + OtherComputer = new Computer() + { + CreatedBy = new User(), + ModifiedBy = new User(), + } + }; + } - // assert - Assert.Null(scriptModel.Computer.CreatedBy); - Assert.NotNull(scriptModel.CreatedBy); - } + [Fact] + public void ComputerCreatedBy_should_be_null_but_ScriptCreatedBy_should_not_be_null_using_lambda_expression_expansions() + { + // act + var scriptModel = new[] { _source }.AsQueryable() + .ProjectTo(Configuration, c => c.Computer, c => c.CreatedBy).Single(); - [Fact] - public void ComputerCreatedBy_should_not_be_null_but_ScriptCreatedBy_should_be_null_using_lambda_expression_expansions() - { - // act - var scriptModel = new[] { _source }.AsQueryable() - .ProjectTo(Configuration, c => c.Computer.CreatedBy).Single(); - - // assert - Assert.NotNull(scriptModel.Computer.CreatedBy); - Assert.Null(scriptModel.OtherComputer.CreatedBy); - Assert.Null(scriptModel.CreatedBy); - } - - [Fact] - public void ComputerCreatedBy_should_be_null_but_ScriptCreatedBy_should_not_be_null_using_string_expansions() - { - // act - var scriptModel = new[] { _source }.AsQueryable() - .ProjectTo(Configuration, null, "Computer", "CreatedBy").Single(); + // assert + Assert.Null(scriptModel.Computer.CreatedBy); + Assert.NotNull(scriptModel.CreatedBy); + } + + [Fact] + public void ComputerCreatedBy_should_not_be_null_but_ScriptCreatedBy_should_be_null_using_lambda_expression_expansions() + { + // act + var scriptModel = new[] { _source }.AsQueryable() + .ProjectTo(Configuration, c => c.Computer.CreatedBy).Single(); - // assert - Assert.Null(scriptModel.Computer.CreatedBy); - Assert.NotNull(scriptModel.CreatedBy); - } + // assert + Assert.NotNull(scriptModel.Computer.CreatedBy); + Assert.Null(scriptModel.OtherComputer.CreatedBy); + Assert.Null(scriptModel.CreatedBy); + } - [Fact] - public void ComputerCreatedBy_shouldnt_be_null_but_ScriptCreatedBy_should_be_null_using_string_expansions() - { - // act - var scriptModel = new[] { _source }.AsQueryable() - .ProjectTo(Configuration, null, "Computer.CreatedBy").Single(); - - // assert - Assert.NotNull(scriptModel.Computer.CreatedBy); - Assert.Null(scriptModel.CreatedBy); - } + [Fact] + public void ComputerCreatedBy_should_be_null_but_ScriptCreatedBy_should_not_be_null_using_string_expansions() + { + // act + var scriptModel = new[] { _source }.AsQueryable() + .ProjectTo(Configuration, null, "Computer", "CreatedBy").Single(); + + // assert + Assert.Null(scriptModel.Computer.CreatedBy); + Assert.NotNull(scriptModel.CreatedBy); + } + + [Fact] + public void ComputerCreatedBy_shouldnt_be_null_but_ScriptCreatedBy_should_be_null_using_string_expansions() + { + // act + var scriptModel = new[] { _source }.AsQueryable() + .ProjectTo(Configuration, null, "Computer.CreatedBy").Single(); + + // assert + Assert.NotNull(scriptModel.Computer.CreatedBy); + Assert.Null(scriptModel.CreatedBy); } } diff --git a/src/UnitTests/Projection/ExplicitValues.cs b/src/UnitTests/Projection/ExplicitValues.cs index 658b3d7632..687a651e21 100644 --- a/src/UnitTests/Projection/ExplicitValues.cs +++ b/src/UnitTests/Projection/ExplicitValues.cs @@ -1,42 +1,41 @@ -namespace AutoMapper.UnitTests.Projection +namespace AutoMapper.UnitTests.Projection; + +using System.Collections.Generic; +using System.Linq; +using QueryableExtensions; +using Shouldly; +using Xunit; + +public class ExplicitValues : AutoMapperSpecBase { - using System.Collections.Generic; - using System.Linq; - using QueryableExtensions; - using Shouldly; - using Xunit; + private List _dests; + + public class Source + { + public int Value { get; set; } + } + + public class Dest + { + public int Value { get; set; } + } + + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateProjection() + .ForMember(dest => dest.Value, opt => opt.MapFrom(src => 5)); + }); + + protected override void Because_of() + { + var source = new[] { new Source { Value = 10 } }.AsQueryable(); + + _dests = source.ProjectTo(Configuration).ToList(); + } - public class ExplicitValues : AutoMapperSpecBase + [Fact] + public void Should_substitute_value() { - private List _dests; - - public class Source - { - public int Value { get; set; } - } - - public class Dest - { - public int Value { get; set; } - } - - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateProjection() - .ForMember(dest => dest.Value, opt => opt.MapFrom(src => 5)); - }); - - protected override void Because_of() - { - var source = new[] { new Source { Value = 10 } }.AsQueryable(); - - _dests = source.ProjectTo(Configuration).ToList(); - } - - [Fact] - public void Should_substitute_value() - { - _dests[0].Value.ShouldBe(5); - } + _dests[0].Value.ShouldBe(5); } } \ No newline at end of file diff --git a/src/UnitTests/Projection/GenericsTests.cs b/src/UnitTests/Projection/GenericsTests.cs index 5de8f582f9..3824dd5c3e 100644 --- a/src/UnitTests/Projection/GenericsTests.cs +++ b/src/UnitTests/Projection/GenericsTests.cs @@ -1,46 +1,45 @@ -namespace AutoMapper.UnitTests.Projection +namespace AutoMapper.UnitTests.Projection; + +using System.Linq; +using QueryableExtensions; +using Shouldly; +using Xunit; + +public class GenericsTests : AutoMapperSpecBase { - using System.Linq; - using QueryableExtensions; - using Shouldly; - using Xunit; + private Dest[] _dests; - public class GenericsTests : AutoMapperSpecBase + public class Source { - private Dest[] _dests; - - public class Source - { - public T Value { get; set; } - } + public T Value { get; set; } + } - public class Dest - { - public T Value { get; set; } - } + public class Dest + { + public T Value { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(typeof (Source<>), typeof (Dest<>)); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(typeof (Source<>), typeof (Dest<>)); + }); - protected override void Because_of() + protected override void Because_of() + { + var sources = new[] { - var sources = new[] + new Source { - new Source - { - Value = "5" - } - }.AsQueryable(); + Value = "5" + } + }.AsQueryable(); - _dests = sources.ProjectTo>(Configuration).ToArray(); - } + _dests = sources.ProjectTo>(Configuration).ToArray(); + } - [Fact] - public void Should_convert_even_though_mapper_not_explicitly_called_before_hand() - { - _dests[0].Value.ShouldBe("5"); - } + [Fact] + public void Should_convert_even_though_mapper_not_explicitly_called_before_hand() + { + _dests[0].Value.ShouldBe("5"); } } \ No newline at end of file diff --git a/src/UnitTests/Projection/MapFromTest.cs b/src/UnitTests/Projection/MapFromTest.cs index dd9a58acfa..749f88865f 100644 --- a/src/UnitTests/Projection/MapFromTest.cs +++ b/src/UnitTests/Projection/MapFromTest.cs @@ -8,119 +8,118 @@ using AutoMapper.QueryableExtensions.Impl; using AutoMapper.Internal; -namespace AutoMapper.UnitTests.Projection.MapFromTest +namespace AutoMapper.UnitTests.Projection.MapFromTest; + +public class CustomMapFromExpressionTest { - public class CustomMapFromExpressionTest + [Fact] + public void Should_not_fail() { - [Fact] - public void Should_not_fail() + var config = new MapperConfiguration(cfg => { - var config = new MapperConfiguration(cfg => - { - cfg.CreateProjection() - .ForMember(dto => dto.FullName, opt => opt.MapFrom(src => src.LastName + " " + src.FirstName)); - }); + cfg.CreateProjection() + .ForMember(dto => dto.FullName, opt => opt.MapFrom(src => src.LastName + " " + src.FirstName)); + }); - typeof(NullReferenceException).ShouldNotBeThrownBy(() => config.Internal().ProjectionBuilder.GetMapExpression()); //null reference exception here - } + typeof(NullReferenceException).ShouldNotBeThrownBy(() => config.Internal().ProjectionBuilder.GetMapExpression()); //null reference exception here + } - [Fact] - public void Should_map_from_String() - { - var config = new MapperConfiguration(cfg => cfg.CreateMap() - .ForMember(dto => dto.FullName, opt => opt.MapFrom("FirstName"))); + [Fact] + public void Should_map_from_String() + { + var config = new MapperConfiguration(cfg => cfg.CreateMap() + .ForMember(dto => dto.FullName, opt => opt.MapFrom("FirstName"))); - var um = new UserModel(); - um.FirstName = "Hallo"; - var u = new UserDto(); - config.CreateMapper().Map(um, u); + var um = new UserModel(); + um.FirstName = "Hallo"; + var u = new UserDto(); + config.CreateMapper().Map(um, u); - u.FullName.ShouldBe(um.FirstName); - } + u.FullName.ShouldBe(um.FirstName); + } - public class UserModel - { - public string FirstName { get; set; } - public string LastName { get; set; } - } + public class UserModel + { + public string FirstName { get; set; } + public string LastName { get; set; } + } - public class UserDto - { - public string FullName { get; set; } - } - [Fact] - public void Should_project_from_String() - { - var config = new MapperConfiguration(cfg => cfg.CreateMap() - .ForMember(dto => dto.FullName, opt => opt.MapFrom("FirstName"))); - var result = new[] { new UserModel { FirstName = "Hallo" } }.AsQueryable().ProjectTo(config).Single(); - result.FullName.ShouldBe("Hallo"); - } + public class UserDto + { + public string FullName { get; set; } } - public class When_mapping_from_and_source_member_both_can_work : AutoMapperSpecBase + [Fact] + public void Should_project_from_String() { - Dto _destination; + var config = new MapperConfiguration(cfg => cfg.CreateMap() + .ForMember(dto => dto.FullName, opt => opt.MapFrom("FirstName"))); + var result = new[] { new UserModel { FirstName = "Hallo" } }.AsQueryable().ProjectTo(config).Single(); + result.FullName.ShouldBe("Hallo"); + } +} +public class When_mapping_from_and_source_member_both_can_work : AutoMapperSpecBase +{ + Dto _destination; - public class Model - { - public string ShortDescription { get; set; } - } + public class Model + { + public string ShortDescription { get; set; } + } - public class Dto - { - public string ShortDescription { get; set; } - } + public class Dto + { + public string ShortDescription { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(c => c.CreateProjection().ForMember(d => d.ShortDescription, o => o.MapFrom(s => "mappedFrom"))); + protected override MapperConfiguration CreateConfiguration() => new(c => c.CreateProjection().ForMember(d => d.ShortDescription, o => o.MapFrom(s => "mappedFrom"))); - protected override void Because_of() - { - _destination = new[] { new Model() }.AsQueryable().ProjectTo(Configuration).Single(); - } + protected override void Because_of() + { + _destination = new[] { new Model() }.AsQueryable().ProjectTo(Configuration).Single(); + } - [Fact] - public void Map_from_should_prevail() - { - _destination.ShortDescription.ShouldBe("mappedFrom"); - } + [Fact] + public void Map_from_should_prevail() + { + _destination.ShortDescription.ShouldBe("mappedFrom"); } - public class When_mapping_from_chained_properties : AutoMapperSpecBase +} +public class When_mapping_from_chained_properties : AutoMapperSpecBase +{ + class Model { - class Model - { - public InnerModel Inner { get; set; } - } - class InnerModel - { - public InnerModel(string value) => Value = value ?? throw new ArgumentNullException(nameof(value)); - private string Value { get; set; } - } - class Dto - { - public string Value { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(c => c.CreateMap().ForMember(d => d.Value, o => o.MapFrom("Inner.Value"))); - [Fact] - public void Should_map_ok() => Map(new Model { Inner = new InnerModel("mappedFrom") }).Value.ShouldBe("mappedFrom"); + public InnerModel Inner { get; set; } } - public class When_mapping_from_private_method : AutoMapperSpecBase + class InnerModel { - class Model - { - public InnerModel Inner { get; set; } - } - class InnerModel - { - public InnerModel(string value) => SomeValue = value ?? throw new ArgumentNullException(nameof(value)); - private string SomeValue { get; set; } - private string GetSomeValue() => SomeValue; - } - class Dto - { - public string Value { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(c => c.CreateMap().ForMember(d => d.Value, o => o.MapFrom("Inner.GetSomeValue"))); - [Fact] - public void Should_map_ok() => Map(new Model { Inner = new InnerModel("mappedFrom") }).Value.ShouldBe("mappedFrom"); + public InnerModel(string value) => Value = value ?? throw new ArgumentNullException(nameof(value)); + private string Value { get; set; } + } + class Dto + { + public string Value { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(c => c.CreateMap().ForMember(d => d.Value, o => o.MapFrom("Inner.Value"))); + [Fact] + public void Should_map_ok() => Map(new Model { Inner = new InnerModel("mappedFrom") }).Value.ShouldBe("mappedFrom"); +} +public class When_mapping_from_private_method : AutoMapperSpecBase +{ + class Model + { + public InnerModel Inner { get; set; } + } + class InnerModel + { + public InnerModel(string value) => SomeValue = value ?? throw new ArgumentNullException(nameof(value)); + private string SomeValue { get; set; } + private string GetSomeValue() => SomeValue; + } + class Dto + { + public string Value { get; set; } } + protected override MapperConfiguration CreateConfiguration() => new(c => c.CreateMap().ForMember(d => d.Value, o => o.MapFrom("Inner.GetSomeValue"))); + [Fact] + public void Should_map_ok() => Map(new Model { Inner = new InnerModel("mappedFrom") }).Value.ShouldBe("mappedFrom"); } \ No newline at end of file diff --git a/src/UnitTests/Projection/MoreExplanatoryExceptionTests.cs b/src/UnitTests/Projection/MoreExplanatoryExceptionTests.cs index 988283e47b..32ccce1a71 100644 --- a/src/UnitTests/Projection/MoreExplanatoryExceptionTests.cs +++ b/src/UnitTests/Projection/MoreExplanatoryExceptionTests.cs @@ -6,32 +6,31 @@ using Xunit; using AutoMapper.QueryableExtensions; -namespace AutoMapper.UnitTests.Projection +namespace AutoMapper.UnitTests.Projection; + +public class MoreExplanatoryExceptionTests { - public class MoreExplanatoryExceptionTests + [Fact] + public void ConstructorWithUnknownParameterTypeThrowsExplicitException() { - [Fact] - public void ConstructorWithUnknownParameterTypeThrowsExplicitException() - { - // Arrange - var config = new MapperConfiguration(cfg => - cfg.CreateProjection()); + // Arrange + var config = new MapperConfiguration(cfg => + cfg.CreateProjection()); - // Act - var exception = Assert.Throws(() => - new EntitySource[0].AsQueryable().ProjectTo(config)); + // Act + var exception = Assert.Throws(() => + new EntitySource[0].AsQueryable().ProjectTo(config)); - // Assert - Assert.Contains("parameter notSupported", exception.Message, StringComparison.OrdinalIgnoreCase); - } + // Assert + Assert.Contains("parameter notSupported", exception.Message, StringComparison.OrdinalIgnoreCase); + } - class EntitySource - { - public DateTime NotSupported; - } - class EntityDestination - { - public EntityDestination(int notSupported = 0) { } - } + class EntitySource + { + public DateTime NotSupported; + } + class EntityDestination + { + public EntityDestination(int notSupported = 0) { } } } diff --git a/src/UnitTests/Projection/NonGenericQueryableTests.cs b/src/UnitTests/Projection/NonGenericQueryableTests.cs index d64d7d3d22..241c6b77ac 100644 --- a/src/UnitTests/Projection/NonGenericQueryableTests.cs +++ b/src/UnitTests/Projection/NonGenericQueryableTests.cs @@ -1,57 +1,56 @@ -namespace AutoMapper.UnitTests.Projection +namespace AutoMapper.UnitTests.Projection; + +using AutoMapper.QueryableExtensions; +using Shouldly; +using System.Collections.Generic; +using System.Linq; +using Xunit; + +public class NonGenericQueryableTests { - using AutoMapper.QueryableExtensions; - using Shouldly; - using System.Collections.Generic; - using System.Linq; - using Xunit; + private MapperConfiguration _config; - public class NonGenericQueryableTests + public NonGenericQueryableTests() { - private MapperConfiguration _config; - - public NonGenericQueryableTests() + _config = new MapperConfiguration(cfg => { - _config = new MapperConfiguration(cfg => - { - cfg.CreateProjection(); - cfg.CreateProjection(); - }); - } - - [Fact] - public void CanMapNonGenericQueryable() - { - var movies = - new List() { - new Movie() { Actors = new Actor[] { new Actor() { Name = "Actor 1" }, new Actor() { Name = "Actor 2" } } }, - new Movie() { Actors = new Actor[] { new Actor() { Name = "Actor 3" }, new Actor() { Name = "Actor 4" } } } - }.AsQueryable(); + cfg.CreateProjection(); + cfg.CreateProjection(); + }); + } - var mapped = movies.ProjectTo(_config); + [Fact] + public void CanMapNonGenericQueryable() + { + var movies = + new List() { + new Movie() { Actors = new Actor[] { new Actor() { Name = "Actor 1" }, new Actor() { Name = "Actor 2" } } }, + new Movie() { Actors = new Actor[] { new Actor() { Name = "Actor 3" }, new Actor() { Name = "Actor 4" } } } + }.AsQueryable(); - mapped.ElementAt(0).Actors.Length.ShouldBe(2); - mapped.ElementAt(1).Actors[1].Name.ShouldBe("Actor 4"); - } + var mapped = movies.ProjectTo(_config); - public class Movie - { - public Actor[] Actors { get; set; } - } + mapped.ElementAt(0).Actors.Length.ShouldBe(2); + mapped.ElementAt(1).Actors[1].Name.ShouldBe("Actor 4"); + } - public class MovieDto - { - public ActorDto[] Actors { get; set; } - } + public class Movie + { + public Actor[] Actors { get; set; } + } - public class Actor - { - public string Name { get; set; } - } + public class MovieDto + { + public ActorDto[] Actors { get; set; } + } - public class ActorDto - { - public string Name { get; set; } - } + public class Actor + { + public string Name { get; set; } + } + + public class ActorDto + { + public string Name { get; set; } } } \ No newline at end of file diff --git a/src/UnitTests/Projection/NullSubstitutes.cs b/src/UnitTests/Projection/NullSubstitutes.cs index 53aa22b328..6e68b321e5 100644 --- a/src/UnitTests/Projection/NullSubstitutes.cs +++ b/src/UnitTests/Projection/NullSubstitutes.cs @@ -1,78 +1,77 @@ -namespace AutoMapper.UnitTests.Projection -{ - using System.Collections.Generic; - using System.Linq; - using QueryableExtensions; - using Shouldly; - using Xunit; +namespace AutoMapper.UnitTests.Projection; - public class NullSubstitutes : AutoMapperSpecBase - { - private List _dests; +using System.Collections.Generic; +using System.Linq; +using QueryableExtensions; +using Shouldly; +using Xunit; - public class Source - { - public int? Value { get; set; } - } +public class NullSubstitutes : AutoMapperSpecBase +{ + private List _dests; - public class Dest - { - public int? Value { get; set; } - } + public class Source + { + public int? Value { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateProjection().ForMember(m => m.Value, opt => opt.NullSubstitute(5)); - }); + public class Dest + { + public int? Value { get; set; } + } - protected override void Because_of() - { - var source = new[] {new Source()}.AsQueryable(); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateProjection().ForMember(m => m.Value, opt => opt.NullSubstitute(5)); + }); - _dests = source.ProjectTo(Configuration).ToList(); - } + protected override void Because_of() + { + var source = new[] {new Source()}.AsQueryable(); - [Fact] - public void Can_substitute_null_values() - { - _dests[0].Value.ShouldBe(5); - } + _dests = source.ProjectTo(Configuration).ToList(); } - public class NullSubstitutesWithMapFrom : AutoMapperSpecBase + [Fact] + public void Can_substitute_null_values() { - private List _dests; + _dests[0].Value.ShouldBe(5); + } +} - public class Source - { - public int? Value { get; set; } - } +public class NullSubstitutesWithMapFrom : AutoMapperSpecBase +{ + private List _dests; - public class Dest - { - public int? ValuePropertyNotMatching { get; set; } - } + public class Source + { + public int? Value { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => + public class Dest + { + public int? ValuePropertyNotMatching { get; set; } + } + + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateProjection().ForMember(m => m.ValuePropertyNotMatching, opt => { - cfg.CreateProjection().ForMember(m => m.ValuePropertyNotMatching, opt => - { - opt.MapFrom(src => src.Value); - opt.NullSubstitute(5); - }); + opt.MapFrom(src => src.Value); + opt.NullSubstitute(5); }); + }); - protected override void Because_of() - { - var source = new[] {new Source()}.AsQueryable(); + protected override void Because_of() + { + var source = new[] {new Source()}.AsQueryable(); - _dests = source.ProjectTo(Configuration).ToList(); - } + _dests = source.ProjectTo(Configuration).ToList(); + } - [Fact] - public void Can_substitute_null_values() - { - _dests[0].ValuePropertyNotMatching.ShouldBe(5); - } + [Fact] + public void Can_substitute_null_values() + { + _dests[0].ValuePropertyNotMatching.ShouldBe(5); } } \ No newline at end of file diff --git a/src/UnitTests/Projection/ParameterizedQueriesTests.cs b/src/UnitTests/Projection/ParameterizedQueriesTests.cs index eb54055177..dec2ff88d5 100644 --- a/src/UnitTests/Projection/ParameterizedQueriesTests.cs +++ b/src/UnitTests/Projection/ParameterizedQueriesTests.cs @@ -1,205 +1,204 @@ -namespace AutoMapper.UnitTests.Projection +namespace AutoMapper.UnitTests.Projection; + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using QueryableExtensions; +using Shouldly; +using Xunit; + +public class ParameterizedQueriesTests_with_anonymous_object_and_factory : AutoMapperSpecBase { - using System; - using System.Collections.Generic; - using System.Linq; - using System.Linq.Expressions; - using QueryableExtensions; - using Shouldly; - using Xunit; + private Dest[] _dests; + private IQueryable _sources; - public class ParameterizedQueriesTests_with_anonymous_object_and_factory : AutoMapperSpecBase + public class Source { - private Dest[] _dests; - private IQueryable _sources; + } - public class Source - { - } + public class Dest + { + public int Value { get; set; } + } - public class Dest - { - public int Value { get; set; } - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + int value = 0; + + Expression> sourceMember = src => value + 5; + cfg.CreateProjection() + .ForMember(dest => dest.Value, opt => opt.MapFrom(sourceMember)); + }); - protected override MapperConfiguration CreateConfiguration() => new(cfg => + protected override void Because_of() + { + _sources = new[] { - int value = 0; + new Source() + }.AsQueryable(); - Expression> sourceMember = src => value + 5; - cfg.CreateProjection() - .ForMember(dest => dest.Value, opt => opt.MapFrom(sourceMember)); - }); + _dests = _sources.ProjectTo(Configuration, new { value = 10 }).ToArray(); + } - protected override void Because_of() - { - _sources = new[] - { - new Source() - }.AsQueryable(); + [Fact] + public void Should_substitute_parameter_value() + { + _dests[0].Value.ShouldBe(15); + } - _dests = _sources.ProjectTo(Configuration, new { value = 10 }).ToArray(); - } + [Fact] + public void Should_not_cache_parameter_value() + { + var newDests = _sources.ProjectTo(Configuration, new { value = 15 }).ToArray(); - [Fact] - public void Should_substitute_parameter_value() - { - _dests[0].Value.ShouldBe(15); - } + newDests[0].Value.ShouldBe(20); + } +} - [Fact] - public void Should_not_cache_parameter_value() - { - var newDests = _sources.ProjectTo(Configuration, new { value = 15 }).ToArray(); +public class ParameterizedQueriesTests_with_anonymous_object : AutoMapperSpecBase +{ + private Dest[] _dests; + private IQueryable _sources; - newDests[0].Value.ShouldBe(20); - } + public class Source + { } - public class ParameterizedQueriesTests_with_anonymous_object : AutoMapperSpecBase + public class Dest { - private Dest[] _dests; - private IQueryable _sources; + public int Value { get; set; } + } - public class Source - { - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + int value = 0; - public class Dest - { - public int Value { get; set; } - } + Expression> sourceMember = src => value + 5; + cfg.CreateProjection() + .ForMember(dest => dest.Value, opt => opt.MapFrom(sourceMember)); + }); - protected override MapperConfiguration CreateConfiguration() => new(cfg => + protected override void Because_of() + { + _sources = new[] { - int value = 0; + new Source() + }.AsQueryable(); - Expression> sourceMember = src => value + 5; - cfg.CreateProjection() - .ForMember(dest => dest.Value, opt => opt.MapFrom(sourceMember)); - }); + _dests = _sources.ProjectTo(Configuration, new { value = 10 }).ToArray(); + } - protected override void Because_of() - { - _sources = new[] - { - new Source() - }.AsQueryable(); + [Fact] + public void Should_substitute_parameter_value() + { + _dests[0].Value.ShouldBe(15); + } - _dests = _sources.ProjectTo(Configuration, new { value = 10 }).ToArray(); - } + [Fact] + public void Should_not_cache_parameter_value() + { + var newDests = _sources.ProjectTo(Configuration, new {value = 15}).ToArray(); - [Fact] - public void Should_substitute_parameter_value() - { - _dests[0].Value.ShouldBe(15); - } + newDests[0].Value.ShouldBe(20); + } +} - [Fact] - public void Should_not_cache_parameter_value() - { - var newDests = _sources.ProjectTo(Configuration, new {value = 15}).ToArray(); +public class ParameterizedQueriesTests_with_dictionary_object : AutoMapperSpecBase +{ + private Dest[] _dests; + private IQueryable _sources; - newDests[0].Value.ShouldBe(20); - } + public class Source + { } - public class ParameterizedQueriesTests_with_dictionary_object : AutoMapperSpecBase + public class Dest { - private Dest[] _dests; - private IQueryable _sources; + public int Value { get; set; } + } - public class Source - { - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + int value = 0; - public class Dest - { - public int Value { get; set; } - } + Expression> sourceMember = src => value + 5; + cfg.CreateProjection() + .ForMember(dest => dest.Value, opt => opt.MapFrom(sourceMember)); + }); - protected override MapperConfiguration CreateConfiguration() => new(cfg => + protected override void Because_of() + { + _sources = new[] { - int value = 0; + new Source() + }.AsQueryable(); - Expression> sourceMember = src => value + 5; - cfg.CreateProjection() - .ForMember(dest => dest.Value, opt => opt.MapFrom(sourceMember)); - }); - - protected override void Because_of() - { - _sources = new[] - { - new Source() - }.AsQueryable(); + _dests = _sources.ProjectTo(Configuration, new Dictionary{{"value", 10}}).ToArray(); + } - _dests = _sources.ProjectTo(Configuration, new Dictionary{{"value", 10}}).ToArray(); - } + [Fact] + public void Should_substitute_parameter_value() + { + _dests[0].Value.ShouldBe(15); + } - [Fact] - public void Should_substitute_parameter_value() - { - _dests[0].Value.ShouldBe(15); - } + [Fact] + public void Should_not_cache_parameter_value() + { + var newDests = _sources.ProjectTo(Configuration, new Dictionary { { "value", 15 } }).ToArray(); - [Fact] - public void Should_not_cache_parameter_value() - { - var newDests = _sources.ProjectTo(Configuration, new Dictionary { { "value", 15 } }).ToArray(); + newDests[0].Value.ShouldBe(20); + } +} - newDests[0].Value.ShouldBe(20); - } +public class ParameterizedQueriesTests_with_filter : AutoMapperSpecBase +{ + public class User + { + public int Id { get; set; } + public string Name { get; set; } + public DateTime? DateActivated { get; set; } } - public class ParameterizedQueriesTests_with_filter : AutoMapperSpecBase + public class UserViewModel { - public class User - { - public int Id { get; set; } - public string Name { get; set; } - public DateTime? DateActivated { get; set; } - } - - public class UserViewModel - { - public int Id { get; set; } - public string Name { get; set; } - public DateTime? DateActivated { get; set; } - public int position { get; set; } - } + public int Id { get; set; } + public string Name { get; set; } + public DateTime? DateActivated { get; set; } + public int position { get; set; } + } - public class DB + public class DB + { + public DB() { - public DB() + Users = new List() { - Users = new List() - { - new User {DateActivated = new DateTime(2000, 1, 1), Id = 1, Name = "Joe Schmoe"}, - new User {DateActivated = new DateTime(2000, 2, 1), Id = 2, Name = "John Schmoe"}, - new User {DateActivated = new DateTime(2000, 3, 1), Id = 3, Name = "Jim Schmoe"}, - }.AsQueryable(); - } - public IQueryable Users { get; } + new User {DateActivated = new DateTime(2000, 1, 1), Id = 1, Name = "Joe Schmoe"}, + new User {DateActivated = new DateTime(2000, 2, 1), Id = 2, Name = "John Schmoe"}, + new User {DateActivated = new DateTime(2000, 3, 1), Id = 3, Name = "Jim Schmoe"}, + }.AsQueryable(); } + public IQueryable Users { get; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - DB db = null; + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + DB db = null; - cfg.CreateProjection() - .ForMember(a => a.position, - opt => opt.MapFrom(src => db.Users.Count(u => u.DateActivated < src.DateActivated))); - }); + cfg.CreateProjection() + .ForMember(a => a.position, + opt => opt.MapFrom(src => db.Users.Count(u => u.DateActivated < src.DateActivated))); + }); - [Fact] - public void Should_only_replace_outer_parameters() - { - var db = new DB(); + [Fact] + public void Should_only_replace_outer_parameters() + { + var db = new DB(); - var user = db.Users.ProjectTo(Configuration, new { db }).FirstOrDefault(a => a.Id == 2); + var user = db.Users.ProjectTo(Configuration, new { db }).FirstOrDefault(a => a.Id == 2); - user.position.ShouldBe(1); - } + user.position.ShouldBe(1); } } \ No newline at end of file diff --git a/src/UnitTests/Projection/ProjectCollectionEnumerableTest.cs b/src/UnitTests/Projection/ProjectCollectionEnumerableTest.cs index e2275b60b1..2e2e16427a 100644 --- a/src/UnitTests/Projection/ProjectCollectionEnumerableTest.cs +++ b/src/UnitTests/Projection/ProjectCollectionEnumerableTest.cs @@ -1,82 +1,81 @@ using Shouldly; using Xunit; -namespace AutoMapper.UnitTests.Projection -{ - using System.Collections.Generic; - using System.Linq; +namespace AutoMapper.UnitTests.Projection; - using AutoMapper; - using QueryableExtensions; +using System.Collections.Generic; +using System.Linq; - public class ProjectCollectionEnumerableTest - { - private MapperConfiguration _config; - private const string Street1 = "Street1"; - private const string Street2 = "Street2"; +using AutoMapper; +using QueryableExtensions; - public ProjectCollectionEnumerableTest() - { - _config = new MapperConfiguration(cfg => - { - cfg.CreateProjection(); - cfg.CreateProjection(); - }); - } +public class ProjectCollectionEnumerableTest +{ + private MapperConfiguration _config; + private const string Street1 = "Street1"; + private const string Street2 = "Street2"; - [Fact] - public void ProjectWithAssignedCollectionSourceProperty() + public ProjectCollectionEnumerableTest() + { + _config = new MapperConfiguration(cfg => { - var customer = new Customer { Addresses = new List
{ new Address(Street1), new Address(Street2) } }; - var customers = new[] { customer }.AsQueryable(); + cfg.CreateProjection(); + cfg.CreateProjection(); + }); + } - var mapped = customers.ProjectTo(_config).SingleOrDefault(); + [Fact] + public void ProjectWithAssignedCollectionSourceProperty() + { + var customer = new Customer { Addresses = new List
{ new Address(Street1), new Address(Street2) } }; + var customers = new[] { customer }.AsQueryable(); - mapped.ShouldNotBeNull(); + var mapped = customers.ProjectTo(_config).SingleOrDefault(); - mapped.Addresses.ShouldBeOfLength(2); - mapped.Addresses.ElementAt(0).Street.ShouldBe(Street1); - mapped.Addresses.ElementAt(1).Street.ShouldBe(Street2); - } + mapped.ShouldNotBeNull(); - public class Customer + mapped.Addresses.ShouldBeOfLength(2); + mapped.Addresses.ElementAt(0).Street.ShouldBe(Street1); + mapped.Addresses.ElementAt(1).Street.ShouldBe(Street2); + } + + public class Customer + { + public IList
Addresses { get; set; } + } + + public class Address + { + public Address(string street) { - public IList
Addresses { get; set; } + Street = street; } - public class Address - { - public Address(string street) - { - Street = street; - } + public string Street { get; set; } + } - public string Street { get; set; } + public class CustomerDto + { + public IEnumerable Addresses { get; set; } + } + + public class AddressDto + { + public string Street { get; set; } + + public override string ToString() + { + return Street; } - public class CustomerDto + public override bool Equals(object obj) { - public IEnumerable Addresses { get; set; } + return string.Equals(ToString(), obj.ToString()); } - public class AddressDto + public override int GetHashCode() { - public string Street { get; set; } - - public override string ToString() - { - return Street; - } - - public override bool Equals(object obj) - { - return string.Equals(ToString(), obj.ToString()); - } - - public override int GetHashCode() - { - return Street.GetHashCode(); - } + return Street.GetHashCode(); } } } diff --git a/src/UnitTests/Projection/ProjectCollectionListTest.cs b/src/UnitTests/Projection/ProjectCollectionListTest.cs index 58016c0f3c..19ed0f81bc 100644 --- a/src/UnitTests/Projection/ProjectCollectionListTest.cs +++ b/src/UnitTests/Projection/ProjectCollectionListTest.cs @@ -1,102 +1,101 @@ using Shouldly; using Xunit; -namespace AutoMapper.UnitTests.Projection +namespace AutoMapper.UnitTests.Projection; + +using System; +using System.Collections.Generic; +using System.Linq; + +using AutoMapper; +using QueryableExtensions; + + +public class ProjectCollectionListTest { - using System; - using System.Collections.Generic; - using System.Linq; + private MapperConfiguration _config; + private const string Street1 = "Street1"; + private const string Street2 = "Street2"; - using AutoMapper; - using QueryableExtensions; + public ProjectCollectionListTest() + { + _config = new MapperConfiguration(cfg => + { + cfg.CreateProjection(); + cfg.CreateProjection(); + }); + } + [Fact] + public void ProjectWithAssignedCollectionSourceProperty() + { + var customer = new Customer { Addresses = new List
{ new Address(Street1), new Address(Street2) } }; + + var customers = new[] { customer }.AsQueryable(); + + var mapped = customers.ProjectTo(_config).SingleOrDefault(); + + mapped.ShouldNotBeNull(); + + mapped.Addresses.ShouldBeOfLength(2); + mapped.Addresses[0].Street.ShouldBe(Street1); + mapped.Addresses[1].Street.ShouldBe(Street2); + } - public class ProjectCollectionListTest + public class Customer { - private MapperConfiguration _config; - private const string Street1 = "Street1"; - private const string Street2 = "Street2"; + public IList
Addresses { get; set; } + } - public ProjectCollectionListTest() + public class Address + { + public Address(string street) { - _config = new MapperConfiguration(cfg => - { - cfg.CreateProjection(); - cfg.CreateProjection(); - }); + Street = street; } - [Fact] - public void ProjectWithAssignedCollectionSourceProperty() - { - var customer = new Customer { Addresses = new List
{ new Address(Street1), new Address(Street2) } }; - - var customers = new[] { customer }.AsQueryable(); - - var mapped = customers.ProjectTo(_config).SingleOrDefault(); + public string Street { get; set; } + } - mapped.ShouldNotBeNull(); + public class CustomerDto + { + public IList Addresses { get; set; } + } - mapped.Addresses.ShouldBeOfLength(2); - mapped.Addresses[0].Street.ShouldBe(Street1); - mapped.Addresses[1].Street.ShouldBe(Street2); + public class AddressDto : IEquatable + { + public bool Equals(AddressDto other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + return string.Equals(Street, other.Street); } - public class Customer + public override int GetHashCode() { - public IList
Addresses { get; set; } + return (Street != null ? Street.GetHashCode() : 0); } - public class Address + public static bool operator ==(AddressDto left, AddressDto right) { - public Address(string street) - { - Street = street; - } + return Equals(left, right); + } - public string Street { get; set; } + public static bool operator !=(AddressDto left, AddressDto right) + { + return !Equals(left, right); } - public class CustomerDto + public string Street { get; set; } + + public override string ToString() { - public IList Addresses { get; set; } + return Street; } - public class AddressDto : IEquatable + public override bool Equals(object obj) { - public bool Equals(AddressDto other) - { - if (ReferenceEquals(null, other)) return false; - if (ReferenceEquals(this, other)) return true; - return string.Equals(Street, other.Street); - } - - public override int GetHashCode() - { - return (Street != null ? Street.GetHashCode() : 0); - } - - public static bool operator ==(AddressDto left, AddressDto right) - { - return Equals(left, right); - } - - public static bool operator !=(AddressDto left, AddressDto right) - { - return !Equals(left, right); - } - - public string Street { get; set; } - - public override string ToString() - { - return Street; - } - - public override bool Equals(object obj) - { - return string.Equals(ToString(), obj.ToString()); - } + return string.Equals(ToString(), obj.ToString()); } } } diff --git a/src/UnitTests/Projection/ProjectEnumTest.cs b/src/UnitTests/Projection/ProjectEnumTest.cs index fd46819dcf..cf7438ae5f 100644 --- a/src/UnitTests/Projection/ProjectEnumTest.cs +++ b/src/UnitTests/Projection/ProjectEnumTest.cs @@ -1,78 +1,77 @@ using System; -namespace AutoMapper.UnitTests.Projection +namespace AutoMapper.UnitTests.Projection; + +using QueryableExtensions; +using Shouldly; +using System.Linq; +using Xunit; + +public class ProjectEnumTest { - using QueryableExtensions; - using Shouldly; - using System.Linq; - using Xunit; + private MapperConfiguration _config; - public class ProjectEnumTest + public ProjectEnumTest() { - private MapperConfiguration _config; - - public ProjectEnumTest() - { - _config = new MapperConfiguration(cfg => - { - cfg.CreateProjection(); - cfg.CreateProjection().ConvertUsing(ct => ct.ToString().ToUpper()); - }); - } - - [Fact] - public void ProjectingEnumToString() + _config = new MapperConfiguration(cfg => { - var customers = new[] { new Customer() { FirstName = "Bill", LastName = "White", CustomerType = CustomerType.Vip } }.AsQueryable(); + cfg.CreateProjection(); + cfg.CreateProjection().ConvertUsing(ct => ct.ToString().ToUpper()); + }); + } - var projected = customers.ProjectTo(_config); - projected.ShouldNotBeNull(); - Assert.Equal(customers.Single().CustomerType.ToString(), projected.Single().CustomerType, StringComparer.OrdinalIgnoreCase); - } + [Fact] + public void ProjectingEnumToString() + { + var customers = new[] { new Customer() { FirstName = "Bill", LastName = "White", CustomerType = CustomerType.Vip } }.AsQueryable(); - public class Customer - { - public string FirstName { get; set; } + var projected = customers.ProjectTo(_config); + projected.ShouldNotBeNull(); + Assert.Equal(customers.Single().CustomerType.ToString(), projected.Single().CustomerType, StringComparer.OrdinalIgnoreCase); + } - public string LastName { get; set; } + public class Customer + { + public string FirstName { get; set; } - public CustomerType CustomerType { get; set; } - } + public string LastName { get; set; } - public class CustomerDto - { - public string FirstName { get; set; } + public CustomerType CustomerType { get; set; } + } - public string LastName { get; set; } + public class CustomerDto + { + public string FirstName { get; set; } - public string CustomerType { get; set; } - } + public string LastName { get; set; } - public enum CustomerType - { - Regular, - Vip, - } + public string CustomerType { get; set; } } - public class ProjectionOverrides : AutoMapperSpecBase + public enum CustomerType { - public class Source - { - - } + Regular, + Vip, + } +} - public class Dest - { - public int Value { get; set; } - } +public class ProjectionOverrides : AutoMapperSpecBase +{ + public class Source + { + + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateProjection() - .ConvertUsing(src => new Dest {Value = 10}); - }); - [Fact] - public void Validate() => AssertConfigurationIsValid(); + public class Dest + { + public int Value { get; set; } } + + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateProjection() + .ConvertUsing(src => new Dest {Value = 10}); + }); + [Fact] + public void Validate() => AssertConfigurationIsValid(); } \ No newline at end of file diff --git a/src/UnitTests/Projection/ProjectEnumerableToArrayTest.cs b/src/UnitTests/Projection/ProjectEnumerableToArrayTest.cs index 0a24e2d7fd..4345a7317f 100644 --- a/src/UnitTests/Projection/ProjectEnumerableToArrayTest.cs +++ b/src/UnitTests/Projection/ProjectEnumerableToArrayTest.cs @@ -5,56 +5,55 @@ using Xunit; using Shouldly; -namespace AutoMapper.UnitTests.Projection +namespace AutoMapper.UnitTests.Projection; + +using QueryableExtensions; + +public class ProjectEnumerableToArrayTest { - using QueryableExtensions; + private MapperConfiguration _config; - public class ProjectEnumerableToArrayTest + public ProjectEnumerableToArrayTest() { - private MapperConfiguration _config; - - public ProjectEnumerableToArrayTest() + _config = new MapperConfiguration(cfg => { - _config = new MapperConfiguration(cfg => - { - cfg.CreateProjection(); - cfg.CreateProjection(); - }); - } - - [Fact] - public void EnumerablesAreMappedToArrays() - { - var movies = - new List() { - new Movie() { Actors = new Actor[] { new Actor() { Name = "Actor 1" }, new Actor() { Name = "Actor 2" } } }, - new Movie() { Actors = new Actor[] { new Actor() { Name = "Actor 3" }, new Actor() { Name = "Actor 4" } } } - }.AsQueryable(); + cfg.CreateProjection(); + cfg.CreateProjection(); + }); + } - var mapped = movies.ProjectTo(_config); + [Fact] + public void EnumerablesAreMappedToArrays() + { + var movies = + new List() { + new Movie() { Actors = new Actor[] { new Actor() { Name = "Actor 1" }, new Actor() { Name = "Actor 2" } } }, + new Movie() { Actors = new Actor[] { new Actor() { Name = "Actor 3" }, new Actor() { Name = "Actor 4" } } } + }.AsQueryable(); - mapped.ElementAt(0).Actors.Length.ShouldBe(2); - mapped.ElementAt(1).Actors[1].Name.ShouldBe("Actor 4"); - } + var mapped = movies.ProjectTo(_config); - public class Movie - { - public IEnumerable Actors { get; set; } - } + mapped.ElementAt(0).Actors.Length.ShouldBe(2); + mapped.ElementAt(1).Actors[1].Name.ShouldBe("Actor 4"); + } - public class MovieDto - { - public ActorDto[] Actors { get; set; } - } + public class Movie + { + public IEnumerable Actors { get; set; } + } - public class Actor - { - public string Name { get; set; } - } + public class MovieDto + { + public ActorDto[] Actors { get; set; } + } - public class ActorDto - { - public string Name { get; set; } - } + public class Actor + { + public string Name { get; set; } + } + + public class ActorDto + { + public string Name { get; set; } } } diff --git a/src/UnitTests/Projection/ProjectIReadOnlyCollection.cs b/src/UnitTests/Projection/ProjectIReadOnlyCollection.cs index 80aa4d99f1..12f0d14439 100644 --- a/src/UnitTests/Projection/ProjectIReadOnlyCollection.cs +++ b/src/UnitTests/Projection/ProjectIReadOnlyCollection.cs @@ -1,67 +1,66 @@ using Shouldly; using Xunit; -namespace AutoMapper.UnitTests.Projection -{ - using System.Collections.Generic; - using System.Linq; +namespace AutoMapper.UnitTests.Projection; - using AutoMapper; - using QueryableExtensions; +using System.Collections.Generic; +using System.Linq; - public class ProjectIReadOnlyCollection - { - private MapperConfiguration _config; - private const string Street1 = "Street1"; - private const string Street2 = "Street2"; +using AutoMapper; +using QueryableExtensions; - public ProjectIReadOnlyCollection() - { - _config = new MapperConfiguration(cfg => - { - cfg.CreateProjection(); - cfg.CreateProjection(); - }); - } +public class ProjectIReadOnlyCollection +{ + private MapperConfiguration _config; + private const string Street1 = "Street1"; + private const string Street2 = "Street2"; - [Fact] - public void ProjectWithAssignedCollectionSourceProperty() + public ProjectIReadOnlyCollection() + { + _config = new MapperConfiguration(cfg => { - var customer = new Customer { Addresses = new List
{ new Address(Street1), new Address(Street2) } }; - var customers = new[] { customer }.AsQueryable(); - - var mapped = customers.ProjectTo(_config).SingleOrDefault(); + cfg.CreateProjection(); + cfg.CreateProjection(); + }); + } - mapped.ShouldNotBeNull(); + [Fact] + public void ProjectWithAssignedCollectionSourceProperty() + { + var customer = new Customer { Addresses = new List
{ new Address(Street1), new Address(Street2) } }; + var customers = new[] { customer }.AsQueryable(); - mapped.Addresses.ShouldBeOfLength(2); - mapped.Addresses.ElementAt(0).Street.ShouldBe(Street1); - mapped.Addresses.ElementAt(1).Street.ShouldBe(Street2); - } + var mapped = customers.ProjectTo(_config).SingleOrDefault(); - public class Customer - { - public IList
Addresses { get; set; } - } + mapped.ShouldNotBeNull(); - public class Address - { - public Address(string street) - { - Street = street; - } + mapped.Addresses.ShouldBeOfLength(2); + mapped.Addresses.ElementAt(0).Street.ShouldBe(Street1); + mapped.Addresses.ElementAt(1).Street.ShouldBe(Street2); + } - public string Street { get; set; } - } + public class Customer + { + public IList
Addresses { get; set; } + } - public class CustomerDto + public class Address + { + public Address(string street) { - public IReadOnlyCollection Addresses { get; set; } + Street = street; } - public class AddressDto - { - public string Street { get; set; } - } + public string Street { get; set; } + } + + public class CustomerDto + { + public IReadOnlyCollection Addresses { get; set; } + } + + public class AddressDto + { + public string Street { get; set; } } } \ No newline at end of file diff --git a/src/UnitTests/Projection/ProjectTest.cs b/src/UnitTests/Projection/ProjectTest.cs index 1acc893444..ffff115a30 100644 --- a/src/UnitTests/Projection/ProjectTest.cs +++ b/src/UnitTests/Projection/ProjectTest.cs @@ -1,112 +1,111 @@ using Xunit; using Shouldly; -namespace AutoMapper.UnitTests.Projection +namespace AutoMapper.UnitTests.Projection; + +using System; +using System.Collections.Generic; +using System.Linq; + +using AutoMapper; +using QueryableExtensions; + +public class ProjectWithFields : AutoMapperSpecBase { - using System; - using System.Collections.Generic; - using System.Linq; + public class Foo + { + public int A; + } - using AutoMapper; - using QueryableExtensions; + public class FooDto + { + public int A; + } - public class ProjectWithFields : AutoMapperSpecBase + protected override MapperConfiguration CreateConfiguration() => new(cfg => { - public class Foo - { - public int A; - } + cfg.CreateProjection(); + }); - public class FooDto - { - public int A; - } + [Fact] + public void Should_work() + { + new[] { new Foo() }.AsQueryable().ProjectTo(Configuration).Single().A.ShouldBe(0); + } +} - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateProjection(); - }); +public class ProjectTest +{ + private MapperConfiguration _config; - [Fact] - public void Should_work() + public ProjectTest() + { + _config = new MapperConfiguration(cfg => { - new[] { new Foo() }.AsQueryable().ProjectTo(Configuration).Single().A.ShouldBe(0); - } + cfg.CreateProjection(); + cfg.CreateProjection(); + }); } - public class ProjectTest + [Fact] + public void ProjectToWithUnmappedTypeShouldThrowException() { - private MapperConfiguration _config; + var customers = + new[] { new Customer { FirstName = "Bill", LastName = "White", Address = new Address("Street1") } } + .AsQueryable(); - public ProjectTest() - { - _config = new MapperConfiguration(cfg => - { - cfg.CreateProjection(); - cfg.CreateProjection(); - }); - } - - [Fact] - public void ProjectToWithUnmappedTypeShouldThrowException() - { - var customers = - new[] { new Customer { FirstName = "Bill", LastName = "White", Address = new Address("Street1") } } - .AsQueryable(); - - IList projected = null; + IList projected = null; - typeof(InvalidOperationException).ShouldBeThrownBy(() => projected = customers.ProjectTo(_config).ToList()); + typeof(InvalidOperationException).ShouldBeThrownBy(() => projected = customers.ProjectTo(_config).ToList()); - projected.ShouldBeNull(); - } + projected.ShouldBeNull(); + } - [Fact] - public void DynamicProjectToShouldWork() - { - var customers = - new[] { new Customer { FirstName = "Bill", LastName = "White", Address = new Address("Street1") } } - .AsQueryable(); + [Fact] + public void DynamicProjectToShouldWork() + { + var customers = + new[] { new Customer { FirstName = "Bill", LastName = "White", Address = new Address("Street1") } } + .AsQueryable(); - IQueryable projected = customers.ProjectTo(typeof(CustomerDto), _config); + IQueryable projected = customers.ProjectTo(typeof(CustomerDto), _config); - projected.Cast().Single().FirstName.ShouldBe("Bill"); - } + projected.Cast().Single().FirstName.ShouldBe("Bill"); + } - public class Customer - { - public string FirstName { get; set; } + public class Customer + { + public string FirstName { get; set; } - public string LastName { get; set; } + public string LastName { get; set; } - public Address Address { get; set; } - } + public Address Address { get; set; } + } - public class Address + public class Address + { + public Address(string street) { - public Address(string street) - { - Street = street; - } - - public string Street { get; set; } + Street = street; } - public class CustomerDto - { - public string FirstName { get; set; } + public string Street { get; set; } + } - public AddressDto Address { get; set; } - } + public class CustomerDto + { + public string FirstName { get; set; } - public class AddressDto - { - public string Street { get; set; } - } + public AddressDto Address { get; set; } + } - public class Unmapped - { - public string FirstName { get; set; } - } + public class AddressDto + { + public string Street { get; set; } + } + + public class Unmapped + { + public string FirstName { get; set; } } } diff --git a/src/UnitTests/Projection/ProjectionMappers.cs b/src/UnitTests/Projection/ProjectionMappers.cs index 9d3b068073..fdc79d299d 100644 --- a/src/UnitTests/Projection/ProjectionMappers.cs +++ b/src/UnitTests/Projection/ProjectionMappers.cs @@ -8,40 +8,39 @@ using AutoMapper.QueryableExtensions.Impl; using AutoMapper.Internal; -namespace AutoMapper.UnitTests.Projection -{ - using static Expression; +namespace AutoMapper.UnitTests.Projection; + +using static Expression; - public class ProjectionMappers : AutoMapperSpecBase +public class ProjectionMappers : AutoMapperSpecBase +{ + class Source { - class Source - { - public ConsoleColor Color { get; set; } - } + public ConsoleColor Color { get; set; } + } - class Destination - { - public int Color { get; set; } - } + class Destination + { + public int Color { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.Internal().ProjectionMappers.Add(new EnumToUnderlyingTypeProjectionMapper()); - cfg.CreateProjection(); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.Internal().ProjectionMappers.Add(new EnumToUnderlyingTypeProjectionMapper()); + cfg.CreateProjection(); + }); - [Fact] - public void Should_work_with_projections() - { - var destination = new[] { new Source { Color = ConsoleColor.Cyan } }.AsQueryable().ProjectTo(Configuration).First(); - destination.Color.ShouldBe(11); - } - private class EnumToUnderlyingTypeProjectionMapper : IProjectionMapper - { - public Expression Project(IGlobalConfiguration configuration, in ProjectionRequest request, Expression resolvedSource, LetPropertyMaps letPropertyMaps) => - Convert(resolvedSource, request.DestinationType); - public bool IsMatch(TypePair context) => - context.SourceType.IsEnum && Enum.GetUnderlyingType(context.SourceType) == context.DestinationType; - } + [Fact] + public void Should_work_with_projections() + { + var destination = new[] { new Source { Color = ConsoleColor.Cyan } }.AsQueryable().ProjectTo(Configuration).First(); + destination.Color.ShouldBe(11); + } + private class EnumToUnderlyingTypeProjectionMapper : IProjectionMapper + { + public Expression Project(IGlobalConfiguration configuration, in ProjectionRequest request, Expression resolvedSource, LetPropertyMaps letPropertyMaps) => + Convert(resolvedSource, request.DestinationType); + public bool IsMatch(TypePair context) => + context.SourceType.IsEnum && Enum.GetUnderlyingType(context.SourceType) == context.DestinationType; } } \ No newline at end of file diff --git a/src/UnitTests/Projection/ProjectionTests.cs b/src/UnitTests/Projection/ProjectionTests.cs index 3ee0103929..581e993a98 100644 --- a/src/UnitTests/Projection/ProjectionTests.cs +++ b/src/UnitTests/Projection/ProjectionTests.cs @@ -5,75 +5,74 @@ using AutoMapper.QueryableExtensions; using System.Collections.Generic; -namespace AutoMapper.UnitTests.Projection +namespace AutoMapper.UnitTests.Projection; + +public class NonNullableToNullable : AutoMapperSpecBase { - public class NonNullableToNullable : AutoMapperSpecBase + class Source + { + public int Id { get; set; } + } + class Destination { - class Source - { - public int Id { get; set; } - } - class Destination - { - public int? Id { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(c=>c.CreateProjection()); - [Fact] - public void Should_project() => ProjectTo(new[] { new Source() }.AsQueryable()).First().Id.ShouldBe(0); + public int? Id { get; set; } } - public class InMemoryMapObjectPropertyFromSubQuery : AutoMapperSpecBase + protected override MapperConfiguration CreateConfiguration() => new(c=>c.CreateProjection()); + [Fact] + public void Should_project() => ProjectTo(new[] { new Source() }.AsQueryable()).First().Id.ShouldBe(0); +} +public class InMemoryMapObjectPropertyFromSubQuery : AutoMapperSpecBase +{ + protected override MapperConfiguration CreateConfiguration() => new(cfg => { - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateProjection() - .ForMember(d => d.Price, o => o.MapFrom(source => source.Articles.Where(x => x.IsDefault && x.NationId == 1 && source.ECommercePublished).FirstOrDefault())); - cfg.CreateProjection() - .ForMember(d => d.RegionId, o => o.MapFrom(s => s.NationId)); - }); + cfg.CreateProjection() + .ForMember(d => d.Price, o => o.MapFrom(source => source.Articles.Where(x => x.IsDefault && x.NationId == 1 && source.ECommercePublished).FirstOrDefault())); + cfg.CreateProjection() + .ForMember(d => d.RegionId, o => o.MapFrom(s => s.NationId)); + }); - [Fact] - public void Should_cache_the_subquery() - { - var products = new[] { new Product { Id = 1, ECommercePublished = true, Articles = new[] { new Article { Id = 1, IsDefault = true, NationId = 1, ProductId = 1 } } } }.AsQueryable(); - var projection = products.ProjectTo(Configuration); - var productModel = projection.First(); - productModel.Price.RegionId.ShouldBe((short)1); - productModel.Price.IsDefault.ShouldBeTrue(); - productModel.Price.Id.ShouldBe(1); - productModel.Id.ShouldBe(1); - } + [Fact] + public void Should_cache_the_subquery() + { + var products = new[] { new Product { Id = 1, ECommercePublished = true, Articles = new[] { new Article { Id = 1, IsDefault = true, NationId = 1, ProductId = 1 } } } }.AsQueryable(); + var projection = products.ProjectTo(Configuration); + var productModel = projection.First(); + productModel.Price.RegionId.ShouldBe((short)1); + productModel.Price.IsDefault.ShouldBeTrue(); + productModel.Price.Id.ShouldBe(1); + productModel.Id.ShouldBe(1); + } - public partial class Article - { - public int Id { get; set; } - public int ProductId { get; set; } - public bool IsDefault { get; set; } - public short NationId { get; set; } - public virtual Product Product { get; set; } - } + public partial class Article + { + public int Id { get; set; } + public int ProductId { get; set; } + public bool IsDefault { get; set; } + public short NationId { get; set; } + public virtual Product Product { get; set; } + } - public partial class Product - { - public int Id { get; set; } - public string Name { get; set; } - public bool ECommercePublished { get; set; } - public virtual ICollection
Articles { get; set; } - public int Value { get; } - public int NotMappedValue { get; set; } - public virtual List
OtherArticles { get; } - } + public partial class Product + { + public int Id { get; set; } + public string Name { get; set; } + public bool ECommercePublished { get; set; } + public virtual ICollection
Articles { get; set; } + public int Value { get; } + public int NotMappedValue { get; set; } + public virtual List
OtherArticles { get; } + } - public class PriceModel - { - public int Id { get; set; } - public short RegionId { get; set; } - public bool IsDefault { get; set; } - } + public class PriceModel + { + public int Id { get; set; } + public short RegionId { get; set; } + public bool IsDefault { get; set; } + } - public class ProductModel - { - public int Id { get; set; } - public PriceModel Price { get; set; } - } + public class ProductModel + { + public int Id { get; set; } + public PriceModel Price { get; set; } } } \ No newline at end of file diff --git a/src/UnitTests/Projection/RecursiveQuery.cs b/src/UnitTests/Projection/RecursiveQuery.cs index ebab07e774..2437e1f622 100644 --- a/src/UnitTests/Projection/RecursiveQuery.cs +++ b/src/UnitTests/Projection/RecursiveQuery.cs @@ -7,36 +7,35 @@ using System.Threading.Tasks; using Xunit; -namespace AutoMapper.UnitTests.Projection +namespace AutoMapper.UnitTests.Projection; + +public class RecursiveQuery : AutoMapperSpecBase { - public class RecursiveQuery : AutoMapperSpecBase + class Source + { + public int Id { get; set; } + public Source Parent { get; set; } + } + class Destination + { + public int Id { get; set; } + public Destination Parent { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(c=> + { + c.CreateProjection(); + c.Internal().RecursiveQueriesMaxDepth = 1; + }); + [Fact] + public void Should_work() { - class Source - { - public int Id { get; set; } - public Source Parent { get; set; } - } - class Destination - { - public int Id { get; set; } - public Destination Parent { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(c=> - { - c.CreateProjection(); - c.Internal().RecursiveQueriesMaxDepth = 1; - }); - [Fact] - public void Should_work() - { - var source = new[] { new Source { Id = 1, Parent = new Source { Id = 2, Parent = new Source { } } }, new Source { Id = 3, Parent = new Source { Id = 4, Parent = new Source { } } } }; - var result = ProjectTo(source.AsQueryable()).ToArray(); - result[0].Id.ShouldBe(1); - result[0].Parent.Id.ShouldBe(2); - result[0].Parent.Parent.ShouldBeNull(); - result[1].Id.ShouldBe(3); - result[1].Parent.Id.ShouldBe(4); - result[1].Parent.Parent.ShouldBeNull(); - } + var source = new[] { new Source { Id = 1, Parent = new Source { Id = 2, Parent = new Source { } } }, new Source { Id = 3, Parent = new Source { Id = 4, Parent = new Source { } } } }; + var result = ProjectTo(source.AsQueryable()).ToArray(); + result[0].Id.ShouldBe(1); + result[0].Parent.Id.ShouldBe(2); + result[0].Parent.Parent.ShouldBeNull(); + result[1].Id.ShouldBe(3); + result[1].Parent.Id.ShouldBe(4); + result[1].Parent.Parent.ShouldBeNull(); } } \ No newline at end of file diff --git a/src/UnitTests/Projection/ToStringTests.cs b/src/UnitTests/Projection/ToStringTests.cs index 93105600bc..9f3a712df8 100644 --- a/src/UnitTests/Projection/ToStringTests.cs +++ b/src/UnitTests/Projection/ToStringTests.cs @@ -1,85 +1,84 @@ -namespace AutoMapper.UnitTests.Projection +namespace AutoMapper.UnitTests.Projection; + +using System.Linq; +using QueryableExtensions; +using Shouldly; +using Xunit; + +public class ToStringTests : AutoMapperSpecBase { - using System.Linq; - using QueryableExtensions; - using Shouldly; - using Xunit; + private Dest[] _dests; - public class ToStringTests : AutoMapperSpecBase + public class Source { - private Dest[] _dests; - - public class Source - { - public int Value { get; set; } - } + public int Value { get; set; } + } - public class Dest - { - public string Value { get; set; } - } + public class Dest + { + public string Value { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateProjection(); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateProjection(); + }); - protected override void Because_of() + protected override void Because_of() + { + var sources = new[] { - var sources = new[] + new Source { - new Source - { - Value = 5 - } - }.AsQueryable(); + Value = 5 + } + }.AsQueryable(); - _dests = sources.ProjectTo(Configuration).ToArray(); - } - - [Fact] - public void Should_convert_to_string() - { - _dests[0].Value.ShouldBe("5"); - } + _dests = sources.ProjectTo(Configuration).ToArray(); } - public class NullableToStringTests : AutoMapperSpecBase + [Fact] + public void Should_convert_to_string() { - private Dest[] _dests; + _dests[0].Value.ShouldBe("5"); + } +} - public class Source - { - public int? Value { get; set; } - } +public class NullableToStringTests : AutoMapperSpecBase +{ + private Dest[] _dests; - public class Dest - { - public string Value { get; set; } - } + public class Source + { + public int? Value { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateProjection(); - }); + public class Dest + { + public string Value { get; set; } + } + + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateProjection(); + }); - protected override void Because_of() + protected override void Because_of() + { + var sources = new[] { - var sources = new[] + new Source { - new Source - { - Value = 5 - } - }.AsQueryable(); + Value = 5 + } + }.AsQueryable(); - _dests = sources.ProjectTo(Configuration).ToArray(); - } + _dests = sources.ProjectTo(Configuration).ToArray(); + } - [Fact] - public void Should_convert_to_string() - { - _dests[0].Value.ShouldBe("5"); - } + [Fact] + public void Should_convert_to_string() + { + _dests[0].Value.ShouldBe("5"); } } \ No newline at end of file diff --git a/src/UnitTests/ReverseMapWithPreserveReferences.cs b/src/UnitTests/ReverseMapWithPreserveReferences.cs index 5dc58885e3..d401775c14 100644 --- a/src/UnitTests/ReverseMapWithPreserveReferences.cs +++ b/src/UnitTests/ReverseMapWithPreserveReferences.cs @@ -3,80 +3,79 @@ using Shouldly; using Xunit; -namespace AutoMapper.UnitTests +namespace AutoMapper.UnitTests; + +public class ReverseMapWithPreserveReferences : AutoMapperSpecBase { - public class ReverseMapWithPreserveReferences : AutoMapperSpecBase + UserDto _destination; + + public class UserModel { - UserDto _destination; + public virtual CategoryModel Category { get; set; } + public virtual UserGroupModel Group { get; set; } + } - public class UserModel - { - public virtual CategoryModel Category { get; set; } - public virtual UserGroupModel Group { get; set; } - } + public class CategoryModel + { + public CategoryModel Category { get; set; } + } - public class CategoryModel + public class UserGroupModel + { + public UserGroupModel() { - public CategoryModel Category { get; set; } + Users = new List(); } - public class UserGroupModel - { - public UserGroupModel() - { - Users = new List(); - } + public virtual ICollection Users { get; set; } + } - public virtual ICollection Users { get; set; } - } + public class UserDto + { + public virtual CategoryDto Category { get; set; } + public virtual UserGroupDto Group { get; set; } + } - public class UserDto - { - public virtual CategoryDto Category { get; set; } - public virtual UserGroupDto Group { get; set; } - } + public class CategoryDto + { + public CategoryDto Category { get; set; } + } - public class CategoryDto + public class UserGroupDto + { + public UserGroupDto() { - public CategoryDto Category { get; set; } + Users = new List(); } - public class UserGroupDto - { - public UserGroupDto() - { - Users = new List(); - } - - public virtual ICollection Users { get; set; } - } + public virtual ICollection Users { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(MemberList.Destination).PreserveReferences().ReverseMap(); - cfg.CreateMap(MemberList.Destination).PreserveReferences().ReverseMap(); - cfg.CreateMap(MemberList.Destination).PreserveReferences().ReverseMap(); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(MemberList.Destination).PreserveReferences().ReverseMap(); + cfg.CreateMap(MemberList.Destination).PreserveReferences().ReverseMap(); + cfg.CreateMap(MemberList.Destination).PreserveReferences().ReverseMap(); + }); - protected override void Because_of() - { - var categoryModel = new CategoryModel(); - categoryModel.Category = categoryModel; + protected override void Because_of() + { + var categoryModel = new CategoryModel(); + categoryModel.Category = categoryModel; - var userModel = new UserModel(); - var userGroupModel = new UserGroupModel(); + var userModel = new UserModel(); + var userGroupModel = new UserGroupModel(); - userModel.Category = categoryModel; - userModel.Group = userGroupModel; - userGroupModel.Users.Add(userModel); + userModel.Category = categoryModel; + userModel.Group = userGroupModel; + userGroupModel.Users.Add(userModel); - _destination = Mapper.Map(userModel); - } + _destination = Mapper.Map(userModel); + } - [Fact] - public void Should_map_ok() - { - _destination.Group.Users.SequenceEqual(new[] { _destination }).ShouldBeTrue(); - } + [Fact] + public void Should_map_ok() + { + _destination.Group.Users.SequenceEqual(new[] { _destination }).ShouldBeTrue(); } } diff --git a/src/UnitTests/ReverseMapWithoutPreserveReferences.cs b/src/UnitTests/ReverseMapWithoutPreserveReferences.cs index 484fe49959..564986e4b5 100644 --- a/src/UnitTests/ReverseMapWithoutPreserveReferences.cs +++ b/src/UnitTests/ReverseMapWithoutPreserveReferences.cs @@ -3,80 +3,79 @@ using Shouldly; using Xunit; -namespace AutoMapper.UnitTests +namespace AutoMapper.UnitTests; + +public class ReverseMapWithoutPreserveReferences : AutoMapperSpecBase { - public class ReverseMapWithoutPreserveReferences : AutoMapperSpecBase + UserDto _destination; + + public class UserModel { - UserDto _destination; + public virtual CategoryModel Category { get; set; } + public virtual UserGroupModel Group { get; set; } + } - public class UserModel - { - public virtual CategoryModel Category { get; set; } - public virtual UserGroupModel Group { get; set; } - } + public class CategoryModel + { + public CategoryModel Category { get; set; } + } - public class CategoryModel + public class UserGroupModel + { + public UserGroupModel() { - public CategoryModel Category { get; set; } + Users = new List(); } - public class UserGroupModel - { - public UserGroupModel() - { - Users = new List(); - } + public virtual ICollection Users { get; set; } + } - public virtual ICollection Users { get; set; } - } + public class UserDto + { + public virtual CategoryDto Category { get; set; } + public virtual UserGroupDto Group { get; set; } + } - public class UserDto - { - public virtual CategoryDto Category { get; set; } - public virtual UserGroupDto Group { get; set; } - } + public class CategoryDto + { + public CategoryDto Category { get; set; } + } - public class CategoryDto + public class UserGroupDto + { + public UserGroupDto() { - public CategoryDto Category { get; set; } + Users = new List(); } - public class UserGroupDto - { - public UserGroupDto() - { - Users = new List(); - } - - public virtual ICollection Users { get; set; } - } + public virtual ICollection Users { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(MemberList.Destination).ReverseMap(); - cfg.CreateMap(MemberList.Destination).ReverseMap(); - cfg.CreateMap(MemberList.Destination).ReverseMap(); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(MemberList.Destination).ReverseMap(); + cfg.CreateMap(MemberList.Destination).ReverseMap(); + cfg.CreateMap(MemberList.Destination).ReverseMap(); + }); - protected override void Because_of() - { - var categoryModel = new CategoryModel(); - categoryModel.Category = categoryModel; + protected override void Because_of() + { + var categoryModel = new CategoryModel(); + categoryModel.Category = categoryModel; - var userModel = new UserModel(); - var userGroupModel = new UserGroupModel(); + var userModel = new UserModel(); + var userGroupModel = new UserGroupModel(); - userModel.Category = categoryModel; - userModel.Group = userGroupModel; - userGroupModel.Users.Add(userModel); + userModel.Category = categoryModel; + userModel.Group = userGroupModel; + userGroupModel.Users.Add(userModel); - _destination = Mapper.Map(userModel); - } + _destination = Mapper.Map(userModel); + } - [Fact] - public void Should_map_ok() - { - _destination.Group.Users.SequenceEqual(new[] { _destination }).ShouldBeTrue(); - } + [Fact] + public void Should_map_ok() + { + _destination.Group.Users.SequenceEqual(new[] { _destination }).ShouldBeTrue(); } } diff --git a/src/UnitTests/ReverseMapping.cs b/src/UnitTests/ReverseMapping.cs index 23a7cdbf86..d472823577 100644 --- a/src/UnitTests/ReverseMapping.cs +++ b/src/UnitTests/ReverseMapping.cs @@ -6,678 +6,677 @@ using System.Reflection; using AutoMapper.Internal; -namespace AutoMapper.UnitTests +namespace AutoMapper.UnitTests; + +public class ReverseMapWithStaticField : AutoMapperSpecBase { - public class ReverseMapWithStaticField : AutoMapperSpecBase + class Source { - class Source - { - public Guid Id { get; set; } - } - class Destination - { - public Guid Id { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(c=> - c.CreateMap().ForMember(src => src.Id, opt => opt.MapFrom(_ => Guid.Empty)).ReverseMap()); - [Fact] - public void Validate() => AssertConfigurationIsValid(); + public Guid Id { get; set; } } - public class InvalidReverseMap : NonValidatingSpecBase + class Destination { - public class One - { - public string Name { get; set; } - public Three2 Three2 { get; set; } - } - - public class Two - { - public string Name { get; set; } - public Three Three { get; set; } - } - - public class Three - { - } + public Guid Id { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(c=> + c.CreateMap().ForMember(src => src.Id, opt => opt.MapFrom(_ => Guid.Empty)).ReverseMap()); + [Fact] + public void Validate() => AssertConfigurationIsValid(); +} +public class InvalidReverseMap : NonValidatingSpecBase +{ + public class One + { + public string Name { get; set; } + public Three2 Three2 { get; set; } + } - public class Three2 - { - } + public class Two + { + public string Name { get; set; } + public Three Three { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg=> - { - cfg.CreateMap() - .ForMember(d => d.Name, o => o.MapFrom(s => "name")) - .ForMember(d => d.Three, o => o.MapFrom(s => s.Three2)) - .ReverseMap(); - cfg.CreateMap(); - }); + public class Three + { + } - [Fact] - public void Should_report_the_error() - { - new Action(AssertConfigurationIsValid) - .ShouldThrowException((AutoMapperConfigurationException ex) => - { - ex.MemberMap.DestinationName.ShouldBe("Three"); - ex.Types.ShouldBe(new TypePair(typeof(One), typeof(Two))); - }); - } + public class Three2 + { } - public class MapFromReverseResolveUsing : AutoMapperSpecBase + protected override MapperConfiguration CreateConfiguration() => new(cfg=> { - public class Source - { - public int Total { get; set; } - } + cfg.CreateMap() + .ForMember(d => d.Name, o => o.MapFrom(s => "name")) + .ForMember(d => d.Three, o => o.MapFrom(s => s.Three2)) + .ReverseMap(); + cfg.CreateMap(); + }); + + [Fact] + public void Should_report_the_error() + { + new Action(AssertConfigurationIsValid) + .ShouldThrowException((AutoMapperConfigurationException ex) => + { + ex.MemberMap.DestinationName.ShouldBe("Three"); + ex.Types.ShouldBe(new TypePair(typeof(One), typeof(Two))); + }); + } +} - public class Destination - { - public int Total { get; set; } - } +public class MapFromReverseResolveUsing : AutoMapperSpecBase +{ + public class Source + { + public int Total { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(c => - { - c.CreateMap() - .ForMember(dest => dest.Total, opt => opt.MapFrom(x => x.Total)) - .ReverseMap() - .ForMember(dest => dest.Total, opt => opt.MapFrom()); - }); + public class Destination + { + public int Total { get; set; } + } - public class CustomResolver : IValueResolver - { - public int Resolve(Source source, Destination destination, int member, ResolutionContext context) - { - return Int32.MaxValue; - } - } + protected override MapperConfiguration CreateConfiguration() => new(c => + { + c.CreateMap() + .ForMember(dest => dest.Total, opt => opt.MapFrom(x => x.Total)) + .ReverseMap() + .ForMember(dest => dest.Total, opt => opt.MapFrom()); + }); - [Fact] - public void Should_use_the_resolver() + public class CustomResolver : IValueResolver + { + public int Resolve(Source source, Destination destination, int member, ResolutionContext context) { - Mapper.Map(new Source()).Total.ShouldBe(int.MaxValue); + return Int32.MaxValue; } } - public class MethodsWithReverse : AutoMapperSpecBase + [Fact] + public void Should_use_the_resolver() { - class Order - { - public OrderItem[] OrderItems { get; set; } - } - - class OrderItem - { - public string Product { get; set; } - } + Mapper.Map(new Source()).Total.ShouldBe(int.MaxValue); + } +} - class OrderDto - { - public int OrderItemsCount { get; set; } - } +public class MethodsWithReverse : AutoMapperSpecBase +{ + class Order + { + public OrderItem[] OrderItems { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(c=> - { - c.CreateMap().ReverseMap(); - }); + class OrderItem + { + public string Product { get; set; } + } - [Fact] - public void ShouldMapOk() - { - Mapper.Map(new OrderDto()); - } + class OrderDto + { + public int OrderItemsCount { get; set; } } - public class ReverseForPath : AutoMapperSpecBase + protected override MapperConfiguration CreateConfiguration() => new(c=> { - public class Order - { - public CustomerHolder CustomerHolder { get; set; } - } + c.CreateMap().ReverseMap(); + }); - public class CustomerHolder - { - public Customer Customer { get; set; } - } + [Fact] + public void ShouldMapOk() + { + Mapper.Map(new OrderDto()); + } +} - public class Customer - { - public string Name { get; set; } - public decimal Total { get; set; } - } +public class ReverseForPath : AutoMapperSpecBase +{ + public class Order + { + public CustomerHolder CustomerHolder { get; set; } + } - public class OrderDto - { - public string CustomerName { get; set; } - public decimal Total { get; set; } - } + public class CustomerHolder + { + public Customer Customer { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ForPath(o => o.CustomerHolder.Customer.Name, o => o.MapFrom(s => s.CustomerName)) - .ForPath(o => o.CustomerHolder.Customer.Total, o => o.MapFrom(s => s.Total)) - .ReverseMap(); - }); + public class Customer + { + public string Name { get; set; } + public decimal Total { get; set; } + } - [Fact] - public void Should_flatten() - { - var model = new Order { - CustomerHolder = new CustomerHolder { - Customer = new Customer { Name = "George Costanza", Total = 74.85m } - } - }; - var dto = Mapper.Map(model); - dto.CustomerName.ShouldBe("George Costanza"); - dto.Total.ShouldBe(74.85m); - } + public class OrderDto + { + public string CustomerName { get; set; } + public decimal Total { get; set; } } - public class ReverseMapFrom : AutoMapperSpecBase + protected override MapperConfiguration CreateConfiguration() => new(cfg => { - public class Order - { - public CustomerHolder CustomerHolder { get; set; } - } + cfg.CreateMap() + .ForPath(o => o.CustomerHolder.Customer.Name, o => o.MapFrom(s => s.CustomerName)) + .ForPath(o => o.CustomerHolder.Customer.Total, o => o.MapFrom(s => s.Total)) + .ReverseMap(); + }); + + [Fact] + public void Should_flatten() + { + var model = new Order { + CustomerHolder = new CustomerHolder { + Customer = new Customer { Name = "George Costanza", Total = 74.85m } + } + }; + var dto = Mapper.Map(model); + dto.CustomerName.ShouldBe("George Costanza"); + dto.Total.ShouldBe(74.85m); + } +} - public class CustomerHolder - { - public Customer Customer { get; set; } - } +public class ReverseMapFrom : AutoMapperSpecBase +{ + public class Order + { + public CustomerHolder CustomerHolder { get; set; } + } - public class Customer - { - public string Name { get; set; } - public decimal Total { get; set; } - } + public class CustomerHolder + { + public Customer Customer { get; set; } + } - public class OrderDto - { - public string CustomerName { get; set; } - public decimal Total { get; set; } - } + public class Customer + { + public string Name { get; set; } + public decimal Total { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ForMember(d => d.CustomerName, o => o.MapFrom(s => s.CustomerHolder.Customer.Name)) - .ForMember(d => d.Total, o => o.MapFrom(s => s.CustomerHolder.Customer.Total)) - .ReverseMap(); - }); + public class OrderDto + { + public string CustomerName { get; set; } + public decimal Total { get; set; } + } - [Fact] - public void Should_unflatten() - { - var dto = new OrderDto { CustomerName = "George Costanza", Total = 74.85m }; - var model = Mapper.Map(dto); - model.CustomerHolder.Customer.Name.ShouldBe("George Costanza"); - model.CustomerHolder.Customer.Total.ShouldBe(74.85m); - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .ForMember(d => d.CustomerName, o => o.MapFrom(s => s.CustomerHolder.Customer.Name)) + .ForMember(d => d.Total, o => o.MapFrom(s => s.CustomerHolder.Customer.Total)) + .ReverseMap(); + }); + + [Fact] + public void Should_unflatten() + { + var dto = new OrderDto { CustomerName = "George Costanza", Total = 74.85m }; + var model = Mapper.Map(dto); + model.CustomerHolder.Customer.Name.ShouldBe("George Costanza"); + model.CustomerHolder.Customer.Total.ShouldBe(74.85m); } +} - public class ReverseMapFromNamingConvention : AutoMapperSpecBase +public class ReverseMapFromNamingConvention : AutoMapperSpecBase +{ + public class OrderEntity { - public class OrderEntity - { - public int order_id { get; set; } - public string order_name { get; set; } - } + public int order_id { get; set; } + public string order_name { get; set; } + } - public class OrderDto - { - public int OrderId { get; set; } - public string OrderName { get; set; } - } + public class OrderDto + { + public int OrderId { get; set; } + public string OrderName { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.SourceMemberNamingConvention = new LowerUnderscoreNamingConvention(); - cfg.DestinationMemberNamingConvention = new PascalCaseNamingConvention(); - cfg.CreateMap() - .ReverseMap(); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.SourceMemberNamingConvention = new LowerUnderscoreNamingConvention(); + cfg.DestinationMemberNamingConvention = new PascalCaseNamingConvention(); + cfg.CreateMap() + .ReverseMap(); + }); + + [Fact] + public void Should_map_reverse() + { + var dto = new OrderDto { OrderId = 123, OrderName = "Test order" }; + var model = Mapper.Map(dto); + model.order_id.ShouldBe(123); + model.order_name.ShouldBe("Test order"); + } +} - [Fact] - public void Should_map_reverse() - { - var dto = new OrderDto { OrderId = 123, OrderName = "Test order" }; - var model = Mapper.Map(dto); - model.order_id.ShouldBe(123); - model.order_name.ShouldBe("Test order"); - } +public class ReverseMapFromSourceMemberName : AutoMapperSpecBase +{ + public class Source + { + public int Value { get; set; } } - public class ReverseMapFromSourceMemberName : AutoMapperSpecBase + public class Destination { - public class Source - { - public int Value { get; set; } - } + public int Value2 { get; set; } + } - public class Destination - { - public int Value2 { get; set; } - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .ForMember(d => d.Value2, o => o.MapFrom("Value")) + .ReverseMap(); + }); - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ForMember(d => d.Value2, o => o.MapFrom("Value")) - .ReverseMap(); - }); + [Fact] + public void Should_reverse_map_ok() + { + Destination destination = new Destination { Value2 = 1337 }; + Source source = Mapper.Map(destination); + source.Value.ShouldBe(1337); + } +} - [Fact] - public void Should_reverse_map_ok() - { - Destination destination = new Destination { Value2 = 1337 }; - Source source = Mapper.Map(destination); - source.Value.ShouldBe(1337); - } +public class ReverseDefaultFlatteningWithIgnoreMember : AutoMapperSpecBase +{ + public class Order + { + public CustomerHolder Customerholder { get; set; } } - public class ReverseDefaultFlatteningWithIgnoreMember : AutoMapperSpecBase + public class CustomerHolder { - public class Order - { - public CustomerHolder Customerholder { get; set; } - } + public Customer Customer { get; set; } + } - public class CustomerHolder - { - public Customer Customer { get; set; } - } + public class Customer + { + public string Name { get; set; } + public decimal Total { get; set; } + } - public class Customer - { - public string Name { get; set; } - public decimal Total { get; set; } - } + public class OrderDto + { + public string CustomerholderCustomerName { get; set; } + public decimal CustomerholderCustomerTotal { get; set; } + } - public class OrderDto - { - public string CustomerholderCustomerName { get; set; } - public decimal CustomerholderCustomerTotal { get; set; } - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .ReverseMap() + .ForMember(d=>d.Customerholder, o=>o.Ignore()) + .ForPath(d=>d.Customerholder.Customer.Total, o=>o.MapFrom(s=>s.CustomerholderCustomerTotal)); + }); + + [Fact] + public void Should_unflatten() + { + var dto = new OrderDto { CustomerholderCustomerName = "George Costanza", CustomerholderCustomerTotal = 74.85m }; + var model = Mapper.Map(dto); + model.Customerholder.Customer.Name.ShouldBeNull(); + model.Customerholder.Customer.Total.ShouldBe(74.85m); + } +} - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ReverseMap() - .ForMember(d=>d.Customerholder, o=>o.Ignore()) - .ForPath(d=>d.Customerholder.Customer.Total, o=>o.MapFrom(s=>s.CustomerholderCustomerTotal)); - }); +public class ReverseDefaultFlattening : AutoMapperSpecBase +{ + public class Order + { + public CustomerHolder Customerholder { get; set; } + } - [Fact] - public void Should_unflatten() - { - var dto = new OrderDto { CustomerholderCustomerName = "George Costanza", CustomerholderCustomerTotal = 74.85m }; - var model = Mapper.Map(dto); - model.Customerholder.Customer.Name.ShouldBeNull(); - model.Customerholder.Customer.Total.ShouldBe(74.85m); - } + public class CustomerHolder + { + public Customer Customer { get; set; } } - public class ReverseDefaultFlattening : AutoMapperSpecBase + public class Customer { - public class Order - { - public CustomerHolder Customerholder { get; set; } - } + public string Name { get; set; } + public decimal Total { get; set; } + } - public class CustomerHolder - { - public Customer Customer { get; set; } - } + public class OrderDto + { + public string CustomerholderCustomerName { get; set; } + public decimal CustomerholderCustomerTotal { get; set; } + } - public class Customer - { - public string Name { get; set; } - public decimal Total { get; set; } - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .ReverseMap(); + }); - public class OrderDto - { - public string CustomerholderCustomerName { get; set; } - public decimal CustomerholderCustomerTotal { get; set; } - } + [Fact] + public void Should_unflatten() + { + var dto = new OrderDto { CustomerholderCustomerName = "George Costanza", CustomerholderCustomerTotal = 74.85m }; + var model = Mapper.Map(dto); + model.Customerholder.Customer.Name.ShouldBe("George Costanza"); + model.Customerholder.Customer.Total.ShouldBe(74.85m); + } +} - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ReverseMap(); - }); +public class ReverseMapConventions : AutoMapperSpecBase +{ + Rotator_Ad_Run _destination; + DateTime _startDate = DateTime.Now, _endDate = DateTime.Now.AddHours(2); - [Fact] - public void Should_unflatten() - { - var dto = new OrderDto { CustomerholderCustomerName = "George Costanza", CustomerholderCustomerTotal = 74.85m }; - var model = Mapper.Map(dto); - model.Customerholder.Customer.Name.ShouldBe("George Costanza"); - model.Customerholder.Customer.Total.ShouldBe(74.85m); - } + public class Rotator_Ad_Run + { + public DateTime Start_Date { get; set; } + public DateTime End_Date { get; set; } + public bool Enabled { get; set; } } - public class ReverseMapConventions : AutoMapperSpecBase + public class RotatorAdRunViewModel { - Rotator_Ad_Run _destination; - DateTime _startDate = DateTime.Now, _endDate = DateTime.Now.AddHours(2); - - public class Rotator_Ad_Run - { - public DateTime Start_Date { get; set; } - public DateTime End_Date { get; set; } - public bool Enabled { get; set; } - } - - public class RotatorAdRunViewModel - { - public DateTime StartDate { get; set; } - public DateTime EndDate { get; set; } - public bool Enabled { get; set; } - } + public DateTime StartDate { get; set; } + public DateTime EndDate { get; set; } + public bool Enabled { get; set; } + } - public class UnderscoreNamingConvention : INamingConvention - { - public Regex SplittingExpression { get; } = new Regex(@"\p{Lu}[a-z0-9]*(?=_?)"); + public class UnderscoreNamingConvention : INamingConvention + { + public Regex SplittingExpression { get; } = new Regex(@"\p{Lu}[a-z0-9]*(?=_?)"); - public string SeparatorCharacter => "_"; - public string[] Split(string input) => SplittingExpression.Matches(input).Select(m => m.Value).ToArray(); - } + public string SeparatorCharacter => "_"; + public string[] Split(string input) => SplittingExpression.Matches(input).Select(m => m.Value).ToArray(); + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateProfile("MyMapperProfile", prf => { - cfg.CreateProfile("MyMapperProfile", prf => - { - prf.SourceMemberNamingConvention = new UnderscoreNamingConvention(); - prf.CreateMap(); - }); - cfg.CreateProfile("MyMapperProfile2", prf => - { - prf.DestinationMemberNamingConvention = new UnderscoreNamingConvention(); - prf.CreateMap(); - }); + prf.SourceMemberNamingConvention = new UnderscoreNamingConvention(); + prf.CreateMap(); }); - - protected override void Because_of() + cfg.CreateProfile("MyMapperProfile2", prf => { - _destination = Mapper.Map(new RotatorAdRunViewModel { Enabled = true, EndDate = _endDate, StartDate = _startDate }); - } + prf.DestinationMemberNamingConvention = new UnderscoreNamingConvention(); + prf.CreateMap(); + }); + }); - [Fact] - public void Should_apply_the_convention_in_reverse() - { - _destination.Enabled.ShouldBeTrue(); - _destination.End_Date.ShouldBe(_endDate); - _destination.Start_Date.ShouldBe(_startDate); - } + protected override void Because_of() + { + _destination = Mapper.Map(new RotatorAdRunViewModel { Enabled = true, EndDate = _endDate, StartDate = _startDate }); } - public class When_reverse_mapping_classes_with_simple_properties : AutoMapperSpecBase + [Fact] + public void Should_apply_the_convention_in_reverse() { - private Source _source; + _destination.Enabled.ShouldBeTrue(); + _destination.End_Date.ShouldBe(_endDate); + _destination.Start_Date.ShouldBe(_startDate); + } +} - public class Source - { - public int Value { get; set; } - } - public class Destination - { - public int Value { get; set; } - } +public class When_reverse_mapping_classes_with_simple_properties : AutoMapperSpecBase +{ + private Source _source; - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ReverseMap(); - }); + public class Source + { + public int Value { get; set; } + } + public class Destination + { + public int Value { get; set; } + } - protected override void Because_of() - { - var dest = new Destination - { - Value = 10 - }; - _source = Mapper.Map(dest); - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .ReverseMap(); + }); - [Fact] - public void Should_create_a_map_with_the_reverse_items() + protected override void Because_of() + { + var dest = new Destination { - _source.Value.ShouldBe(10); - } + Value = 10 + }; + _source = Mapper.Map(dest); } - public class When_validating_only_against_source_members_and_source_matches : AutoMapperSpecBase + [Fact] + public void Should_create_a_map_with_the_reverse_items() { - public class Source - { - public int Value { get; set; } - } - public class Destination - { - public int Value { get; set; } - public int Value2 { get; set; } - } + _source.Value.ShouldBe(10); + } +} - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(MemberList.Source); - }); +public class When_validating_only_against_source_members_and_source_matches : AutoMapperSpecBase +{ + public class Source + { + public int Value { get; set; } + } + public class Destination + { + public int Value { get; set; } + public int Value2 { get; set; } + } - [Fact] - public void Should_only_map_source_members() - { - var typeMap = Configuration.FindTypeMapFor(); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(MemberList.Source); + }); - typeMap.PropertyMaps.Count().ShouldBe(1); - } + [Fact] + public void Should_only_map_source_members() + { + var typeMap = Configuration.FindTypeMapFor(); + + typeMap.PropertyMaps.Count().ShouldBe(1); } +} - public class When_validating_only_against_source_members_and_source_does_not_match : NonValidatingSpecBase +public class When_validating_only_against_source_members_and_source_does_not_match : NonValidatingSpecBase +{ + public class Source { - public class Source - { - public int Value { get; set; } - public int Value2 { get; set; } - } - public class Destination - { - public int Value { get; set; } - } + public int Value { get; set; } + public int Value2 { get; set; } + } + public class Destination + { + public int Value { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(MemberList.Source); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(MemberList.Source); + }); - [Fact] - public void Should_throw_a_configuration_validation_error() - { - typeof(AutoMapperConfigurationException).ShouldBeThrownBy(AssertConfigurationIsValid); - } + [Fact] + public void Should_throw_a_configuration_validation_error() + { + typeof(AutoMapperConfigurationException).ShouldBeThrownBy(AssertConfigurationIsValid); } +} - public class When_validating_only_against_source_members_and_unmatching_source_members_are_manually_mapped : AutoMapperSpecBase +public class When_validating_only_against_source_members_and_unmatching_source_members_are_manually_mapped : AutoMapperSpecBase +{ + public class Source { - public class Source - { - public int Value { get; set; } - public int Value2 { get; set; } - } - public class Destination - { - public int Value { get; set; } - public int Value3 { get; set; } - } + public int Value { get; set; } + public int Value2 { get; set; } + } + public class Destination + { + public int Value { get; set; } + public int Value3 { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(MemberList.Source) - .ForMember(dest => dest.Value3, opt => opt.MapFrom(src => src.Value2)); - }); - [Fact] - public void Validate() => AssertConfigurationIsValid(); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(MemberList.Source) + .ForMember(dest => dest.Value3, opt => opt.MapFrom(src => src.Value2)); + }); + [Fact] + public void Validate() => AssertConfigurationIsValid(); +} + +public class When_validating_only_against_source_members_and_unmatching_source_members_are_manually_mapped_with_resolvers : AutoMapperSpecBase +{ + public class Source + { + public int Value { get; set; } + public int Value2 { get; set; } + } + public class Destination + { + public int Value { get; set; } + public int Value3 { get; set; } } - public class When_validating_only_against_source_members_and_unmatching_source_members_are_manually_mapped_with_resolvers : AutoMapperSpecBase + protected override MapperConfiguration CreateConfiguration() => new(cfg => { - public class Source - { - public int Value { get; set; } - public int Value2 { get; set; } - } - public class Destination - { - public int Value { get; set; } - public int Value3 { get; set; } - } + cfg.CreateMap(MemberList.Source) + .ForMember(dest => dest.Value3, opt => opt.MapFrom(src => src.Value2)) + .ForSourceMember(src => src.Value2, opt => opt.DoNotValidate()); + }); + [Fact] + public void Validate() => AssertConfigurationIsValid(); +} + +public class When_reverse_mapping_and_ignoring_via_method : AutoMapperSpecBase +{ + public class Source + { + public int Value { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(MemberList.Source) - .ForMember(dest => dest.Value3, opt => opt.MapFrom(src => src.Value2)) - .ForSourceMember(src => src.Value2, opt => opt.DoNotValidate()); - }); - [Fact] - public void Validate() => AssertConfigurationIsValid(); + public class Dest + { + public int Value { get; set; } + public int Ignored { get; set; } } - public class When_reverse_mapping_and_ignoring_via_method : AutoMapperSpecBase + protected override MapperConfiguration CreateConfiguration() => new(cfg => { - public class Source - { - public int Value { get; set; } - } + cfg.CreateMap() + .ForMember(d => d.Ignored, opt => opt.Ignore()) + .ReverseMap(); + }); + [Fact] + public void Validate() => AssertConfigurationIsValid(); +} + +public class When_reverse_mapping_and_ignoring : NonValidatingSpecBase +{ + public class Foo + { + public string Bar { get; set; } + public string Baz { get; set; } + } - public class Dest - { - public int Value { get; set; } - public int Ignored { get; set; } - } + public class Foo2 + { + public string Bar { get; set; } + public string Boo { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => + [Fact] + public void GetUnmappedPropertyNames_ShouldReturnBoo() + { + //Arrange + var config = new MapperConfiguration(cfg => { - cfg.CreateMap() - .ForMember(d => d.Ignored, opt => opt.Ignore()) - .ReverseMap(); + cfg.CreateMap(); }); - [Fact] - public void Validate() => AssertConfigurationIsValid(); + var typeMap = config.GetAllTypeMaps() + .First(x => x.SourceType == typeof(Foo) && x.DestinationType == typeof(Foo2)); + //Act + var unmappedPropertyNames = typeMap.GetUnmappedPropertyNames(); + //Assert + unmappedPropertyNames[0].ShouldBe("Boo"); } - public class When_reverse_mapping_and_ignoring : NonValidatingSpecBase + [Fact] + public void WhenSecondCallTo_GetUnmappedPropertyNames_ShouldReturnBoo() { - public class Foo - { - public string Bar { get; set; } - public string Baz { get; set; } - } - - public class Foo2 + //Arrange + var config = new MapperConfiguration(cfg => { - public string Bar { get; set; } - public string Boo { get; set; } - } + cfg.CreateMap().ReverseMap(); + }); + var typeMap = config.GetAllTypeMaps() + .First(x => x.SourceType == typeof(Foo2) && x.DestinationType == typeof(Foo)); + //Act + var unmappedPropertyNames = typeMap.GetUnmappedPropertyNames(); + //Assert + unmappedPropertyNames[0].ShouldBe("Boo"); + } +} - [Fact] - public void GetUnmappedPropertyNames_ShouldReturnBoo() - { - //Arrange - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap(); - }); - var typeMap = config.GetAllTypeMaps() - .First(x => x.SourceType == typeof(Foo) && x.DestinationType == typeof(Foo2)); - //Act - var unmappedPropertyNames = typeMap.GetUnmappedPropertyNames(); - //Assert - unmappedPropertyNames[0].ShouldBe("Boo"); - } +public class When_reverse_mapping_open_generics : AutoMapperSpecBase +{ + private Source _source; - [Fact] - public void WhenSecondCallTo_GetUnmappedPropertyNames_ShouldReturnBoo() - { - //Arrange - var config = new MapperConfiguration(cfg => - { - cfg.CreateMap().ReverseMap(); - }); - var typeMap = config.GetAllTypeMaps() - .First(x => x.SourceType == typeof(Foo2) && x.DestinationType == typeof(Foo)); - //Act - var unmappedPropertyNames = typeMap.GetUnmappedPropertyNames(); - //Assert - unmappedPropertyNames[0].ShouldBe("Boo"); - } + public class Source + { + public T Value { get; set; } } - - public class When_reverse_mapping_open_generics : AutoMapperSpecBase + public class Destination { - private Source _source; - - public class Source - { - public T Value { get; set; } - } - public class Destination - { - public T Value { get; set; } - } - - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(typeof(Source<>), typeof(Destination<>)) - .ReverseMap(); - }); + public T Value { get; set; } + } - protected override void Because_of() - { - var dest = new Destination - { - Value = 10 - }; - _source = Mapper.Map, Source>(dest); - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(typeof(Source<>), typeof(Destination<>)) + .ReverseMap(); + }); - [Fact] - public void Should_create_a_map_with_the_reverse_items() + protected override void Because_of() + { + var dest = new Destination { - _source.Value.ShouldBe(10); - } + Value = 10 + }; + _source = Mapper.Map, Source>(dest); } - public class When_reverse_mapping_open_generics_with_MapFrom : AutoMapperSpecBase + [Fact] + public void Should_create_a_map_with_the_reverse_items() { - public class Source - { - public T Value { get; set; } - public string StringValue { get; set; } - } - public class Destination - { - public T Value2 { get; set; } - public string StringValue2 { get; set; } - } + _source.Value.ShouldBe(10); + } +} - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(typeof(Source<>), typeof(Destination<>)) - .ForMember("Value2", o => o.MapFrom("Value")) - .ForMember("StringValue2", o => o.MapFrom("StringValue")) - .ReverseMap(); - }); +public class When_reverse_mapping_open_generics_with_MapFrom : AutoMapperSpecBase +{ + public class Source + { + public T Value { get; set; } + public string StringValue { get; set; } + } + public class Destination + { + public T Value2 { get; set; } + public string StringValue2 { get; set; } + } - [Fact] - public void Should_reverse_map_ok() - { - Destination destination = new Destination { Value2 = 1337, StringValue2 = "StringValue2" }; - Source source = Mapper.Map, Source>(destination); - source.Value.ShouldBe(1337); - source.StringValue.ShouldBe("StringValue2"); - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(typeof(Source<>), typeof(Destination<>)) + .ForMember("Value2", o => o.MapFrom("Value")) + .ForMember("StringValue2", o => o.MapFrom("StringValue")) + .ReverseMap(); + }); + + [Fact] + public void Should_reverse_map_ok() + { + Destination destination = new Destination { Value2 = 1337, StringValue2 = "StringValue2" }; + Source source = Mapper.Map, Source>(destination); + source.Value.ShouldBe(1337); + source.StringValue.ShouldBe("StringValue2"); } } \ No newline at end of file diff --git a/src/UnitTests/SeparateConfiguration.cs b/src/UnitTests/SeparateConfiguration.cs index 8219298743..f04b60e588 100644 --- a/src/UnitTests/SeparateConfiguration.cs +++ b/src/UnitTests/SeparateConfiguration.cs @@ -1,35 +1,34 @@ -namespace AutoMapper.UnitTests -{ - using Configuration; - using Shouldly; - using Xunit; +namespace AutoMapper.UnitTests; + +using Configuration; +using Shouldly; +using Xunit; - public class SeparateConfiguration : NonValidatingSpecBase +public class SeparateConfiguration : NonValidatingSpecBase +{ + public class Source + { + public int Value { get; set; } + } + public class Dest { - public class Source - { - public int Value { get; set; } - } - public class Dest - { - public int Value { get; set; } - } - protected override MapperConfiguration CreateConfiguration() - { - var expr = new MapperConfigurationExpression(); + public int Value { get; set; } + } + protected override MapperConfiguration CreateConfiguration() + { + var expr = new MapperConfigurationExpression(); - expr.CreateMap(); + expr.CreateMap(); - return new MapperConfiguration(expr); - } + return new MapperConfiguration(expr); + } - [Fact] - public void Should_use_passed_in_configuration() - { - var source = new Source {Value = 5}; - var dest = Mapper.Map(source); + [Fact] + public void Should_use_passed_in_configuration() + { + var source = new Source {Value = 5}; + var dest = Mapper.Map(source); - dest.Value.ShouldBe(source.Value); - } + dest.Value.ShouldBe(source.Value); } } \ No newline at end of file diff --git a/src/UnitTests/ShouldUseConstructor.cs b/src/UnitTests/ShouldUseConstructor.cs index 7df906aeed..5228a5c4cc 100644 --- a/src/UnitTests/ShouldUseConstructor.cs +++ b/src/UnitTests/ShouldUseConstructor.cs @@ -2,208 +2,207 @@ using Shouldly; using Xunit; -namespace AutoMapper.UnitTests +namespace AutoMapper.UnitTests; + +public class ShouldUseConstructorInternal : NonValidatingSpecBase { - public class ShouldUseConstructorInternal : NonValidatingSpecBase + class Destination { - class Destination + internal Destination(int a, string b) { - internal Destination(int a, string b) - { - } - - public int A { get; } + } - public string B { get; } + public int A { get; } - public Destination(int a) - { + public string B { get; } - } + public Destination(int a) + { - private Destination() - { - } } - class Source + private Destination() { - public int A { get; set; } } - - protected override MapperConfiguration CreateConfiguration() => new( - cfg => - { - cfg.ShouldUseConstructor = c => c.IsAssembly; - cfg.CreateMap(); - }); - - [Fact] - public void Should_only_map_internal_ctor() => Should.Throw(AssertConfigurationIsValid); } - public class ShouldUseConstructorPrivate : NonValidatingSpecBase + class Source { + public int A { get; set; } + } - class Destination + protected override MapperConfiguration CreateConfiguration() => new( + cfg => { - private Destination(int a, string b) - { - } + cfg.ShouldUseConstructor = c => c.IsAssembly; + cfg.CreateMap(); + }); - public int A { get; } + [Fact] + public void Should_only_map_internal_ctor() => Should.Throw(AssertConfigurationIsValid); +} - public string B { get; } +public class ShouldUseConstructorPrivate : NonValidatingSpecBase +{ - internal Destination(int a) - { + class Destination + { + private Destination(int a, string b) + { + } - } + public int A { get; } - public Destination() - { - } - } + public string B { get; } - class Source + internal Destination(int a) { - public int A { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new( - cfg => - { - cfg.ShouldUseConstructor = c => c.IsPrivate; - cfg.CreateMap(); - }); + } - [Fact] - public void Should_only_map_private_ctor() => Should.Throw(AssertConfigurationIsValid); + public Destination() + { + } } - public class ShouldUseConstructorPublic : NonValidatingSpecBase + class Source { - class Destination + public int A { get; set; } + } + + protected override MapperConfiguration CreateConfiguration() => new( + cfg => { - public Destination(int a, string b) - { - } + cfg.ShouldUseConstructor = c => c.IsPrivate; + cfg.CreateMap(); + }); - public int A { get; } + [Fact] + public void Should_only_map_private_ctor() => Should.Throw(AssertConfigurationIsValid); +} - public string B { get; } +public class ShouldUseConstructorPublic : NonValidatingSpecBase +{ + class Destination + { + public Destination(int a, string b) + { + } + + public int A { get; } - internal Destination(int a) - { + public string B { get; } - } + internal Destination(int a) + { - private Destination() - { - } } - class Source + private Destination() { - public int A { get; set; } } + } - protected override MapperConfiguration CreateConfiguration() => new( - cfg => - { - cfg.ShouldUseConstructor = c => c.IsPublic; - cfg.CreateMap(); - }); + class Source + { + public int A { get; set; } + } - [Fact] - public void Should_only_map_public_ctor() + protected override MapperConfiguration CreateConfiguration() => new( + cfg => { - Should.Throw(AssertConfigurationIsValid); - } + cfg.ShouldUseConstructor = c => c.IsPublic; + cfg.CreateMap(); + }); + + [Fact] + public void Should_only_map_public_ctor() + { + Should.Throw(AssertConfigurationIsValid); } +} - public class ShouldUseConstructorDefault : AutoMapperSpecBase +public class ShouldUseConstructorDefault : AutoMapperSpecBase +{ + class Destination { - class Destination + public Destination(int a, string b) { - public Destination(int a, string b) - { - } - - public int A { get; } + } - public string B { get; } + public int A { get; } - private Destination() - { - } - } + public string B { get; } - class Source + private Destination() { - public int A { get; set; } } - - protected override MapperConfiguration CreateConfiguration() => - new MapperConfiguration(cfg => { cfg.CreateMap(); }); - [Fact] - public void Validate() => AssertConfigurationIsValid(); } - public class ShouldIgnoreExplicitStaticConstructor : NonValidatingSpecBase + class Source { - class Destination - { - public string B { get; } + public int A { get; set; } + } - static Destination() - { - } + protected override MapperConfiguration CreateConfiguration() => + new MapperConfiguration(cfg => { cfg.CreateMap(); }); + [Fact] + public void Validate() => AssertConfigurationIsValid(); +} - public Destination(string b) - { - B = b; - } - } +public class ShouldIgnoreExplicitStaticConstructor : NonValidatingSpecBase +{ + class Destination + { + public string B { get; } - class Source + static Destination() { - public string A { get; set; } } - protected override MapperConfiguration CreateConfiguration() => - new MapperConfiguration(cfg => { cfg.CreateMap(); }); - - [Fact] - public void Should_ignore_static_constructor() + public Destination(string b) { - Should.Throw(AssertConfigurationIsValid); + B = b; } } - public class ShouldIgnoreImplicitStaticConstructor : NonValidatingSpecBase + class Source { - class Destination - { - public static string C { get; } = "C"; - public string B { get; } + public string A { get; set; } + } - public Destination(string b) - { - B = b; - } - } + protected override MapperConfiguration CreateConfiguration() => + new MapperConfiguration(cfg => { cfg.CreateMap(); }); + + [Fact] + public void Should_ignore_static_constructor() + { + Should.Throw(AssertConfigurationIsValid); + } +} - class Source +public class ShouldIgnoreImplicitStaticConstructor : NonValidatingSpecBase +{ + class Destination + { + public static string C { get; } = "C"; + public string B { get; } + + public Destination(string b) { - public string A { get; set; } + B = b; } + } - protected override MapperConfiguration CreateConfiguration() => - new MapperConfiguration(cfg => { cfg.CreateMap(); }); - - [Fact] - public void Should_ignore_implicit_static_constructor() => - Should.Throw(AssertConfigurationIsValid); + class Source + { + public string A { get; set; } } + + protected override MapperConfiguration CreateConfiguration() => + new MapperConfiguration(cfg => { cfg.CreateMap(); }); + + [Fact] + public void Should_ignore_implicit_static_constructor() => + Should.Throw(AssertConfigurationIsValid); } diff --git a/src/UnitTests/TesterExtensions.cs b/src/UnitTests/TesterExtensions.cs index 7b9b241afa..127448baea 100644 --- a/src/UnitTests/TesterExtensions.cs +++ b/src/UnitTests/TesterExtensions.cs @@ -2,14 +2,13 @@ using System.Linq; using Shouldly; -namespace AutoMapper.UnitTests +namespace AutoMapper.UnitTests; + +public static class StopgapNBehaveExtensions { - public static class StopgapNBehaveExtensions + public static void ShouldBeOfLength(this IEnumerable collection, int length) { - public static void ShouldBeOfLength(this IEnumerable collection, int length) - { - collection.ShouldNotBeNull(); - collection.Count().ShouldBe(length); - } + collection.ShouldNotBeNull(); + collection.Count().ShouldBe(length); } } \ No newline at end of file diff --git a/src/UnitTests/TypeConverters.cs b/src/UnitTests/TypeConverters.cs index cb698180c6..0d55db210c 100644 --- a/src/UnitTests/TypeConverters.cs +++ b/src/UnitTests/TypeConverters.cs @@ -2,368 +2,367 @@ using System.Collections.Generic; using Shouldly; using Xunit; -namespace AutoMapper.UnitTests.CustomMapping +namespace AutoMapper.UnitTests.CustomMapping; + +public class NullableConverter : AutoMapperSpecBase { - public class NullableConverter : AutoMapperSpecBase + public enum GreekLetters { - public enum GreekLetters - { - Alpha = 11, - Beta = 12, - Gamma = 13 - } + Alpha = 11, + Beta = 12, + Gamma = 13 + } - protected override MapperConfiguration CreateConfiguration() => new(c => - { - c.CreateMap().ConvertUsing(n => n == null ? GreekLetters.Beta : GreekLetters.Gamma); - }); + protected override MapperConfiguration CreateConfiguration() => new(c => + { + c.CreateMap().ConvertUsing(n => n == null ? GreekLetters.Beta : GreekLetters.Gamma); + }); - [Fact] - public void Should_map_nullable() - { - Mapper.Map(null).ShouldBe(GreekLetters.Beta); - Mapper.Map(42).ShouldBe(GreekLetters.Gamma); - } + [Fact] + public void Should_map_nullable() + { + Mapper.Map(null).ShouldBe(GreekLetters.Beta); + Mapper.Map(42).ShouldBe(GreekLetters.Gamma); } +} - public class MissingConverter : AutoMapperSpecBase +public class MissingConverter : AutoMapperSpecBase +{ + protected override MapperConfiguration CreateConfiguration() => new(c => { - protected override MapperConfiguration CreateConfiguration() => new(c => - { - c.ConstructServicesUsing(t => null); - c.CreateMap().ConvertUsing>(); - }); + c.ConstructServicesUsing(t => null); + c.CreateMap().ConvertUsing>(); + }); - [Fact] - public void Should_report_the_missing_converter() - { - new Action(()=>Mapper.Map(0)) - .ShouldThrowException(e=>e.Message.ShouldBe("Cannot create an instance of type AutoMapper.ITypeConverter`2[System.Int32,System.Int32]")); - } + [Fact] + public void Should_report_the_missing_converter() + { + new Action(()=>Mapper.Map(0)) + .ShouldThrowException(e=>e.Message.ShouldBe("Cannot create an instance of type AutoMapper.ITypeConverter`2[System.Int32,System.Int32]")); } +} - public class DecimalAndNullableDecimal : AutoMapperSpecBase +public class DecimalAndNullableDecimal : AutoMapperSpecBase +{ + Destination _destination; + + class Source { - Destination _destination; + public decimal Value1 { get; set; } + public decimal? Value2 { get; set; } + public decimal? Value3 { get; set; } + } - class Source - { - public decimal Value1 { get; set; } - public decimal? Value2 { get; set; } - public decimal? Value3 { get; set; } - } + class Destination + { + public decimal? Value1 { get; set; } + public decimal Value2 { get; set; } + public decimal? Value3 { get; set; } + } - class Destination - { - public decimal? Value1 { get; set; } - public decimal Value2 { get; set; } - public decimal? Value3 { get; set; } - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + cfg.CreateMap().ConvertUsing(source => source ?? decimal.MaxValue); + cfg.CreateMap().ConvertUsing(source => source == decimal.MaxValue ? new decimal?() : source); + }); - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - cfg.CreateMap().ConvertUsing(source => source ?? decimal.MaxValue); - cfg.CreateMap().ConvertUsing(source => source == decimal.MaxValue ? new decimal?() : source); - }); + protected override void Because_of() + { + _destination = Mapper.Map(new Source { Value1 = decimal.MaxValue }); + } - protected override void Because_of() - { - _destination = Mapper.Map(new Source { Value1 = decimal.MaxValue }); - } + [Fact] + public void Should_treat_max_value_as_null() + { + _destination.Value1.ShouldBeNull(); + _destination.Value2.ShouldBe(decimal.MaxValue); + _destination.Value3.ShouldBeNull(); + } +} - [Fact] - public void Should_treat_max_value_as_null() - { - _destination.Value1.ShouldBeNull(); - _destination.Value2.ShouldBe(decimal.MaxValue); - _destination.Value3.ShouldBeNull(); - } +public class When_converting_to_string : AutoMapperSpecBase +{ + Destination _destination; + + class Source + { + public Id TheId { get; set; } } - public class When_converting_to_string : AutoMapperSpecBase + class Destination { - Destination _destination; + public string TheId { get; set; } + } - class Source - { - public Id TheId { get; set; } - } + interface IId + { + string Serialize(); + } - class Destination - { - public string TheId { get; set; } - } + class Id : IId + { + public string Prefix { get; set; } + + public string Value { get; set; } - interface IId + public string Serialize() { - string Serialize(); + return Prefix + "_" + Value; } + } - class Id : IId - { - public string Prefix { get; set; } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + cfg.CreateMap().ConvertUsing(id => id.Serialize()); + }); - public string Value { get; set; } + protected override void Because_of() + { + _destination = Mapper.Map(new Source { TheId = new Id { Prefix = "p", Value = "v" } }); + } - public string Serialize() - { - return Prefix + "_" + Value; - } - } + [Fact] + public void Should_use_the_type_converter() + { + _destination.TheId.ShouldBe("p_v"); + } +} - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); - cfg.CreateMap().ConvertUsing(id => id.Serialize()); - }); +public class When_specifying_type_converters_for_object_mapper_types : AutoMapperSpecBase +{ + class Source + { + public IDictionary Values { get; set; } + } + class Destination + { + public IDictionary Values { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(typeof(IDictionary<,>), typeof(IDictionary<,>)).ConvertUsing(typeof(DictionaryConverter<,>)); + cfg.CreateMap(); + }); + [Fact] + public void Should_override_the_built_in_mapper() + { + var destination = Mapper.Map(new Source { Values = new Dictionary() }); + destination.Values.ShouldBeSameAs(DictionaryConverter.Instance); + var destinationString = Mapper.Map>(new Dictionary()); + destinationString.ShouldBeSameAs(DictionaryConverter.Instance); + } + private class DictionaryConverter : ITypeConverter, IDictionary> + { + public static readonly IDictionary Instance = new Dictionary(); + public IDictionary Convert(IDictionary source, IDictionary destination, ResolutionContext context) => Instance; + } +} - protected override void Because_of() - { - _destination = Mapper.Map(new Source { TheId = new Id { Prefix = "p", Value = "v" } }); - } +public class When_specifying_type_converters : AutoMapperSpecBase +{ + private Destination _result; - [Fact] - public void Should_use_the_type_converter() - { - _destination.TheId.ShouldBe("p_v"); - } + public class Source + { + public string Value1 { get; set; } + public string Value2 { get; set; } + public string Value3 { get; set; } } - public class When_specifying_type_converters_for_object_mapper_types : AutoMapperSpecBase + public class Destination { - class Source - { - public IDictionary Values { get; set; } - } - class Destination - { - public IDictionary Values { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(typeof(IDictionary<,>), typeof(IDictionary<,>)).ConvertUsing(typeof(DictionaryConverter<,>)); - cfg.CreateMap(); - }); - [Fact] - public void Should_override_the_built_in_mapper() - { - var destination = Mapper.Map(new Source { Values = new Dictionary() }); - destination.Values.ShouldBeSameAs(DictionaryConverter.Instance); - var destinationString = Mapper.Map>(new Dictionary()); - destinationString.ShouldBeSameAs(DictionaryConverter.Instance); - } - private class DictionaryConverter : ITypeConverter, IDictionary> - { - public static readonly IDictionary Instance = new Dictionary(); - public IDictionary Convert(IDictionary source, IDictionary destination, ResolutionContext context) => Instance; - } + public int Value1 { get; set; } + public DateTime Value2 { get; set; } + public Type Value3 { get; set; } } - public class When_specifying_type_converters : AutoMapperSpecBase + public class DateTimeTypeConverter : ITypeConverter { - private Destination _result; - - public class Source + public DateTime Convert(string source, DateTime destination, ResolutionContext context) { - public string Value1 { get; set; } - public string Value2 { get; set; } - public string Value3 { get; set; } + return System.Convert.ToDateTime(source); } + } - public class Destination + public class TypeTypeConverter : ITypeConverter + { + public Type Convert(string source, Type destination, ResolutionContext context) { - public int Value1 { get; set; } - public DateTime Value2 { get; set; } - public Type Value3 { get; set; } + Type type = typeof(TypeTypeConverter).Assembly.GetType(source); + return type; } + } - public class DateTimeTypeConverter : ITypeConverter - { - public DateTime Convert(string source, DateTime destination, ResolutionContext context) - { - return System.Convert.ToDateTime(source); - } - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().ConvertUsing((string arg) => Convert.ToInt32(arg)); + cfg.CreateMap().ConvertUsing(new DateTimeTypeConverter()); + cfg.CreateMap().ConvertUsing(); + cfg.CreateMap(); - public class TypeTypeConverter : ITypeConverter - { - public Type Convert(string source, Type destination, ResolutionContext context) - { - Type type = typeof(TypeTypeConverter).Assembly.GetType(source); - return type; - } - } + }); - protected override MapperConfiguration CreateConfiguration() => new(cfg => + protected override void Because_of() + { + var source = new Source { - cfg.CreateMap().ConvertUsing((string arg) => Convert.ToInt32(arg)); - cfg.CreateMap().ConvertUsing(new DateTimeTypeConverter()); - cfg.CreateMap().ConvertUsing(); - cfg.CreateMap(); + Value1 = "5", + Value2 = "01/01/2000", + Value3 = "AutoMapper.UnitTests.CustomMapping.When_specifying_type_converters+Destination" + }; - }); + _result = Mapper.Map(source); + } - protected override void Because_of() - { - var source = new Source - { - Value1 = "5", - Value2 = "01/01/2000", - Value3 = "AutoMapper.UnitTests.CustomMapping.When_specifying_type_converters+Destination" - }; - - _result = Mapper.Map(source); - } + [Fact] + public void Should_convert_type_using_expression() + { + _result.Value1.ShouldBe(5); + } - [Fact] - public void Should_convert_type_using_expression() - { - _result.Value1.ShouldBe(5); - } + [Fact] + public void Should_convert_type_using_instance() + { + _result.Value2.ShouldBe(new DateTime(2000, 1, 1)); + } - [Fact] - public void Should_convert_type_using_instance() - { - _result.Value2.ShouldBe(new DateTime(2000, 1, 1)); - } + [Fact] + public void Should_convert_type_using_Func_that_returns_instance() + { + _result.Value3.ShouldBe(typeof(Destination)); + } +} - [Fact] - public void Should_convert_type_using_Func_that_returns_instance() - { - _result.Value3.ShouldBe(typeof(Destination)); - } +public class When_specifying_type_converters_on_types_with_incompatible_members : AutoMapperSpecBase +{ + private ParentDestination _result; + + public class Source + { + public string Foo { get; set; } } - public class When_specifying_type_converters_on_types_with_incompatible_members : AutoMapperSpecBase + public class Destination { - private ParentDestination _result; + public int Type { get; set; } + } - public class Source - { - public string Foo { get; set; } - } + public class ParentSource + { + public Source Value { get; set; } + } - public class Destination - { - public int Type { get; set; } - } + public class ParentDestination + { + public Destination Value { get; set; } + } - public class ParentSource - { - public Source Value { get; set; } - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().ConvertUsing(arg => new Destination {Type = Convert.ToInt32(arg.Foo)}); + cfg.CreateMap(); - public class ParentDestination - { - public Destination Value { get; set; } - } + }); - protected override MapperConfiguration CreateConfiguration() => new(cfg => + protected override void Because_of() + { + var source = new ParentSource { - cfg.CreateMap().ConvertUsing(arg => new Destination {Type = Convert.ToInt32(arg.Foo)}); - cfg.CreateMap(); - - }); + Value = new Source { Foo = "5", } + }; - protected override void Because_of() - { - var source = new ParentSource - { - Value = new Source { Foo = "5", } - }; + _result = Mapper.Map(source); + } - _result = Mapper.Map(source); - } + [Fact] + public void Should_convert_type_using_expression() + { + _result.Value.Type.ShouldBe(5); + } +} +public class When_specifying_a_type_converter_for_a_non_generic_configuration : NonValidatingSpecBase +{ + private Destination _result; - [Fact] - public void Should_convert_type_using_expression() - { - _result.Value.Type.ShouldBe(5); - } + public class Source + { + public int Value { get; set; } } - public class When_specifying_a_type_converter_for_a_non_generic_configuration : NonValidatingSpecBase + + public class Destination { - private Destination _result; + public int OtherValue { get; set; } + } - public class Source + public class CustomConverter : ITypeConverter + { + public Destination Convert(Source source, Destination destination, ResolutionContext context) { - public int Value { get; set; } + return new Destination + { + OtherValue = source.Value + 10 + }; } + } - public class Destination - { - public int OtherValue { get; set; } - } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().ConvertUsing(); + }); - public class CustomConverter : ITypeConverter - { - public Destination Convert(Source source, Destination destination, ResolutionContext context) - { - return new Destination - { - OtherValue = source.Value + 10 - }; - } - } + protected override void Because_of() + { + _result = Mapper.Map(new Source {Value = 5}); + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().ConvertUsing(); - }); + [Fact] + public void Should_use_converter_specified() + { + _result.OtherValue.ShouldBe(15); + } +} - protected override void Because_of() - { - _result = Mapper.Map(new Source {Value = 5}); - } +public class When_specifying_a_non_generic_type_converter_for_a_non_generic_configuration : AutoMapperSpecBase +{ + private Destination _result; - [Fact] - public void Should_use_converter_specified() - { - _result.OtherValue.ShouldBe(15); - } + public class Source + { + public int Value { get; set; } } - public class When_specifying_a_non_generic_type_converter_for_a_non_generic_configuration : AutoMapperSpecBase + public class Destination { - private Destination _result; - - public class Source - { - public int Value { get; set; } - } - - public class Destination - { - public int OtherValue { get; set; } - } + public int OtherValue { get; set; } + } - public class CustomConverter : ITypeConverter + public class CustomConverter : ITypeConverter + { + public Destination Convert(Source source, Destination destination, ResolutionContext context) { - public Destination Convert(Source source, Destination destination, ResolutionContext context) - { - return new Destination - { - OtherValue = source.Value + 10 - }; - } + return new Destination + { + OtherValue = source.Value + 10 + }; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(typeof (Source), typeof (Destination)).ConvertUsing(typeof (CustomConverter)); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(typeof (Source), typeof (Destination)).ConvertUsing(typeof (CustomConverter)); + }); - protected override void Because_of() - { - _result = Mapper.Map(new Source {Value = 5}); - } + protected override void Because_of() + { + _result = Mapper.Map(new Source {Value = 5}); + } - [Fact] - public void Should_use_converter_specified() - { - _result.OtherValue.ShouldBe(15); - } + [Fact] + public void Should_use_converter_specified() + { + _result.OtherValue.ShouldBe(15); } } \ No newline at end of file diff --git a/src/UnitTests/TypeExtensionsTests.cs b/src/UnitTests/TypeExtensionsTests.cs index 5b0c1070ca..bc8d8a4ac6 100644 --- a/src/UnitTests/TypeExtensionsTests.cs +++ b/src/UnitTests/TypeExtensionsTests.cs @@ -1,30 +1,29 @@ -namespace AutoMapper.UnitTests -{ - using Shouldly; - using Xunit; +namespace AutoMapper.UnitTests; + +using Shouldly; +using Xunit; - public class TypeExtensionsTests +public class TypeExtensionsTests +{ + public class Foo { - public class Foo + public Foo() { - public Foo() - { - Value2 = "adsf"; - Value4 = "Fasdfadsf"; - } + Value2 = "adsf"; + Value4 = "Fasdfadsf"; + } - public string Value1 { get; set; } - public string Value2 { get; private set; } - protected string Value3 { get; set; } - private string Value4 { get; set; } - public string Value5 => "ASDf"; - public string Value6 { set { Value4 = value; } } + public string Value1 { get; set; } + public string Value2 { get; private set; } + protected string Value3 { get; set; } + private string Value4 { get; set; } + public string Value5 => "ASDf"; + public string Value6 { set { Value4 = value; } } - [Fact] - public void Should_recognize_public_members() - { + [Fact] + public void Should_recognize_public_members() + { // typeof(Foo).GetProperties().Length.ShouldBe(4); - } - } - } + } + } } \ No newline at end of file diff --git a/src/UnitTests/UsingEngineInsideMap.cs b/src/UnitTests/UsingEngineInsideMap.cs index 254c05019a..c7ed8bc600 100644 --- a/src/UnitTests/UsingEngineInsideMap.cs +++ b/src/UnitTests/UsingEngineInsideMap.cs @@ -1,67 +1,66 @@ -namespace AutoMapper.UnitTests +namespace AutoMapper.UnitTests; + +using Shouldly; +using Xunit; + +public class UsingEngineInsideMap : AutoMapperSpecBase { - using Shouldly; - using Xunit; + private Dest _dest; - public class UsingEngineInsideMap : AutoMapperSpecBase + public class Source { - private Dest _dest; - - public class Source - { - public int Foo { get; set; } - } + public int Foo { get; set; } + } - public class Dest - { - public int Foo { get; set; } - public ChildDest Child { get; set; } - } + public class Dest + { + public int Foo { get; set; } + public ChildDest Child { get; set; } + } - public class ChildDest - { - public int Foo { get; set; } - } + public class ChildDest + { + public int Foo { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ForMember(dest => dest.Child, - opt => - opt.MapFrom( - (src, dest, destMember, context) => - context.Mapper.Map(src, destMember, typeof (Source), typeof (ChildDest)))); - cfg.CreateMap(); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .ForMember(dest => dest.Child, + opt => + opt.MapFrom( + (src, dest, destMember, context) => + context.Mapper.Map(src, destMember, typeof (Source), typeof (ChildDest)))); + cfg.CreateMap(); + }); - protected override void Because_of() - { - _dest = Mapper.Map(new Source {Foo = 5}); - } + protected override void Because_of() + { + _dest = Mapper.Map(new Source {Foo = 5}); + } - [Fact] - public void Should_map_child_property() - { - _dest.Child.ShouldNotBeNull(); - _dest.Child.Foo.ShouldBe(5); - } + [Fact] + public void Should_map_child_property() + { + _dest.Child.ShouldNotBeNull(); + _dest.Child.Foo.ShouldBe(5); } +} - public class When_mapping_null_with_context_mapper : AutoMapperSpecBase +public class When_mapping_null_with_context_mapper : AutoMapperSpecBase +{ + class Source { - class Source - { - } + } - class Destination - { - public string Value { get; set; } - } + class Destination + { + public string Value { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg=> - cfg.CreateMap().ForMember(d=>d.Value, o=>o.MapFrom((s,d,dm, context)=>context.Mapper.Map(null)))); + protected override MapperConfiguration CreateConfiguration() => new(cfg=> + cfg.CreateMap().ForMember(d=>d.Value, o=>o.MapFrom((s,d,dm, context)=>context.Mapper.Map(null)))); - [Fact] - public void Should_return_null() => Mapper.Map(new Source()).Value.ShouldBeNull(); - } + [Fact] + public void Should_return_null() => Mapper.Map(new Source()).Value.ShouldBeNull(); } \ No newline at end of file diff --git a/src/UnitTests/ValueConverters.cs b/src/UnitTests/ValueConverters.cs index 3bac752446..f79455e9ec 100644 --- a/src/UnitTests/ValueConverters.cs +++ b/src/UnitTests/ValueConverters.cs @@ -2,665 +2,664 @@ using System; using Xunit; -namespace AutoMapper.UnitTests +namespace AutoMapper.UnitTests; + +public class ValueConverters { - public class ValueConverters + public class When_specifying_value_converter_for_matching_member : AutoMapperSpecBase { - public class When_specifying_value_converter_for_matching_member : AutoMapperSpecBase + public class EightDigitIntToStringConverter : IValueConverter { - public class EightDigitIntToStringConverter : IValueConverter - { - public string Convert(int sourceMember, ResolutionContext context) - => sourceMember.ToString("d8"); - } - public class FourDigitIntToStringConverter : IValueConverter - { - public string Convert(int sourceMember, ResolutionContext context) - => sourceMember.ToString("d4"); - } + public string Convert(int sourceMember, ResolutionContext context) + => sourceMember.ToString("d8"); + } + public class FourDigitIntToStringConverter : IValueConverter + { + public string Convert(int sourceMember, ResolutionContext context) + => sourceMember.ToString("d4"); + } - public class Source - { - public int Value1 { get; set; } - public int Value2 { get; set; } - public int Value3 { get; set; } - public int Value4 { get; set; } - } + public class Source + { + public int Value1 { get; set; } + public int Value2 { get; set; } + public int Value3 { get; set; } + public int Value4 { get; set; } + } - public class Dest - { - public string Value1 { get; set; } - public string Value2 { get; set; } - public string Value3 { get; set; } - public string Value4 { get; set; } - } + public class Dest + { + public string Value1 { get; set; } + public string Value2 { get; set; } + public string Value3 { get; set; } + public string Value4 { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ForMember(d => d.Value1, opt => opt.ConvertUsing()) - .ForMember(d => d.Value2, opt => opt.ConvertUsing()) - .ForMember(d => d.Value3, opt => opt.ConvertUsing()) - .ForMember(d => d.Value4, opt => opt.ConvertUsing()); - }); - - [Fact] - public void Should_apply_converters() + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .ForMember(d => d.Value1, opt => opt.ConvertUsing()) + .ForMember(d => d.Value2, opt => opt.ConvertUsing()) + .ForMember(d => d.Value3, opt => opt.ConvertUsing()) + .ForMember(d => d.Value4, opt => opt.ConvertUsing()); + }); + + [Fact] + public void Should_apply_converters() + { + var source = new Source { - var source = new Source - { - Value1 = 1, - Value2 = 2, - Value3 = 3, - Value4 = 4 - }; + Value1 = 1, + Value2 = 2, + Value3 = 3, + Value4 = 4 + }; - var dest = Mapper.Map(source); + var dest = Mapper.Map(source); - dest.Value1.ShouldBe("00000001"); - dest.Value2.ShouldBe("00000002"); - dest.Value3.ShouldBe("0003"); - dest.Value4.ShouldBe("0004"); - } + dest.Value1.ShouldBe("00000001"); + dest.Value2.ShouldBe("00000002"); + dest.Value3.ShouldBe("0003"); + dest.Value4.ShouldBe("0004"); } + } - public class When_specifying_value_converter_for_non_matching_member : AutoMapperSpecBase + public class When_specifying_value_converter_for_non_matching_member : AutoMapperSpecBase + { + public class EightDigitIntToStringConverter : IValueConverter { - public class EightDigitIntToStringConverter : IValueConverter - { - public string Convert(int sourceMember, ResolutionContext context) - => sourceMember.ToString("d8"); - } - public class FourDigitIntToStringConverter : IValueConverter - { - public string Convert(int sourceMember, ResolutionContext context) - => sourceMember.ToString("d4"); - } + public string Convert(int sourceMember, ResolutionContext context) + => sourceMember.ToString("d8"); + } + public class FourDigitIntToStringConverter : IValueConverter + { + public string Convert(int sourceMember, ResolutionContext context) + => sourceMember.ToString("d4"); + } - public class Source - { - public int Value1 { get; set; } - public int Value2 { get; set; } - public int Value3 { get; set; } - public int Value4 { get; set; } - } + public class Source + { + public int Value1 { get; set; } + public int Value2 { get; set; } + public int Value3 { get; set; } + public int Value4 { get; set; } + } - public class Dest - { - public string ValueFoo1 { get; set; } - public string ValueFoo2 { get; set; } - public string ValueFoo3 { get; set; } - public string ValueFoo4 { get; set; } - } + public class Dest + { + public string ValueFoo1 { get; set; } + public string ValueFoo2 { get; set; } + public string ValueFoo3 { get; set; } + public string ValueFoo4 { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ForMember(d => d.ValueFoo1, opt => opt.ConvertUsing(src => src.Value1)) - .ForMember(d => d.ValueFoo2, opt => opt.ConvertUsing(src => src.Value2)) - .ForMember(d => d.ValueFoo3, opt => opt.ConvertUsing(src => src.Value3)) - .ForMember(d => d.ValueFoo4, opt => opt.ConvertUsing(src => src.Value4)); - }); - - [Fact] - public void Should_apply_converters() + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .ForMember(d => d.ValueFoo1, opt => opt.ConvertUsing(src => src.Value1)) + .ForMember(d => d.ValueFoo2, opt => opt.ConvertUsing(src => src.Value2)) + .ForMember(d => d.ValueFoo3, opt => opt.ConvertUsing(src => src.Value3)) + .ForMember(d => d.ValueFoo4, opt => opt.ConvertUsing(src => src.Value4)); + }); + + [Fact] + public void Should_apply_converters() + { + var source = new Source { - var source = new Source - { - Value1 = 1, - Value2 = 2, - Value3 = 3, - Value4 = 4 - }; + Value1 = 1, + Value2 = 2, + Value3 = 3, + Value4 = 4 + }; - var dest = Mapper.Map(source); + var dest = Mapper.Map(source); - dest.ValueFoo1.ShouldBe("00000001"); - dest.ValueFoo2.ShouldBe("00000002"); - dest.ValueFoo3.ShouldBe("0003"); - dest.ValueFoo4.ShouldBe("0004"); - } + dest.ValueFoo1.ShouldBe("00000001"); + dest.ValueFoo2.ShouldBe("00000002"); + dest.ValueFoo3.ShouldBe("0003"); + dest.ValueFoo4.ShouldBe("0004"); } - public class When_specifying_value_converter_with_no_source : AutoMapperSpecBase + } + public class When_specifying_value_converter_with_no_source : AutoMapperSpecBase + { + public class EightDigitIntToStringConverter : IValueConverter { - public class EightDigitIntToStringConverter : IValueConverter - { - public string Convert(int sourceMember, ResolutionContext context) => sourceMember.ToString("d8"); - } - public class Source - { - } - public class Dest - { - public string ValueFoo1 { get; set; } - } - protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.CreateMap() - .ForMember(d => d.ValueFoo1, opt => opt.ConvertUsing())); - [Fact] - public void Should_report_error() => new Action(()=>Map(new Source())).ShouldThrow().InnerException.Message.ShouldBe( - "Cannot find a source member to pass to the value converter of type AutoMapper.UnitTests.ValueConverters+When_specifying_value_converter_with_no_source+EightDigitIntToStringConverter. Configure a source member to map from."); + public string Convert(int sourceMember, ResolutionContext context) => sourceMember.ToString("d8"); } + public class Source + { + } + public class Dest + { + public string ValueFoo1 { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.CreateMap() + .ForMember(d => d.ValueFoo1, opt => opt.ConvertUsing())); + [Fact] + public void Should_report_error() => new Action(()=>Map(new Source())).ShouldThrow().InnerException.Message.ShouldBe( + "Cannot find a source member to pass to the value converter of type AutoMapper.UnitTests.ValueConverters+When_specifying_value_converter_with_no_source+EightDigitIntToStringConverter. Configure a source member to map from."); + } - public class When_specifying_value_converter_for_string_based_matching_member : AutoMapperSpecBase + public class When_specifying_value_converter_for_string_based_matching_member : AutoMapperSpecBase + { + public class EightDigitIntToStringConverter : IValueConverter { - public class EightDigitIntToStringConverter : IValueConverter - { - public string Convert(int sourceMember, ResolutionContext context) - => sourceMember.ToString("d8"); - } - public class FourDigitIntToStringConverter : IValueConverter - { - public string Convert(int sourceMember, ResolutionContext context) - => sourceMember.ToString("d4"); - } + public string Convert(int sourceMember, ResolutionContext context) + => sourceMember.ToString("d8"); + } + public class FourDigitIntToStringConverter : IValueConverter + { + public string Convert(int sourceMember, ResolutionContext context) + => sourceMember.ToString("d4"); + } - public class Source - { - public int Value1 { get; set; } - public int Value2 { get; set; } - public int Value3 { get; set; } - public int Value4 { get; set; } - } + public class Source + { + public int Value1 { get; set; } + public int Value2 { get; set; } + public int Value3 { get; set; } + public int Value4 { get; set; } + } - public class Dest - { - public string Value1 { get; set; } - public string Value2 { get; set; } - public string Value3 { get; set; } - public string Value4 { get; set; } - } + public class Dest + { + public string Value1 { get; set; } + public string Value2 { get; set; } + public string Value3 { get; set; } + public string Value4 { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ForMember("Value1", opt => opt.ConvertUsing()) - .ForMember("Value2", opt => opt.ConvertUsing()) - .ForMember("Value3", opt => opt.ConvertUsing()) - .ForMember("Value4", opt => opt.ConvertUsing()); - }); - - [Fact] - public void Should_apply_converters() + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .ForMember("Value1", opt => opt.ConvertUsing()) + .ForMember("Value2", opt => opt.ConvertUsing()) + .ForMember("Value3", opt => opt.ConvertUsing()) + .ForMember("Value4", opt => opt.ConvertUsing()); + }); + + [Fact] + public void Should_apply_converters() + { + var source = new Source { - var source = new Source - { - Value1 = 1, - Value2 = 2, - Value3 = 3, - Value4 = 4 - }; + Value1 = 1, + Value2 = 2, + Value3 = 3, + Value4 = 4 + }; - var dest = Mapper.Map(source); + var dest = Mapper.Map(source); - dest.Value1.ShouldBe("00000001"); - dest.Value2.ShouldBe("00000002"); - dest.Value3.ShouldBe("0003"); - dest.Value4.ShouldBe("0004"); - } + dest.Value1.ShouldBe("00000001"); + dest.Value2.ShouldBe("00000002"); + dest.Value3.ShouldBe("0003"); + dest.Value4.ShouldBe("0004"); } + } - public class When_specifying_value_converter_for_string_based_non_matching_member : AutoMapperSpecBase + public class When_specifying_value_converter_for_string_based_non_matching_member : AutoMapperSpecBase + { + public class EightDigitIntToStringConverter : IValueConverter { - public class EightDigitIntToStringConverter : IValueConverter - { - public string Convert(int sourceMember, ResolutionContext context) - => sourceMember.ToString("d8"); - } - public class FourDigitIntToStringConverter : IValueConverter - { - public string Convert(int sourceMember, ResolutionContext context) - => sourceMember.ToString("d4"); - } + public string Convert(int sourceMember, ResolutionContext context) + => sourceMember.ToString("d8"); + } + public class FourDigitIntToStringConverter : IValueConverter + { + public string Convert(int sourceMember, ResolutionContext context) + => sourceMember.ToString("d4"); + } - public class Source - { - public int Value1 { get; set; } - public int Value2 { get; set; } - public int Value3 { get; set; } - public int Value4 { get; set; } - } + public class Source + { + public int Value1 { get; set; } + public int Value2 { get; set; } + public int Value3 { get; set; } + public int Value4 { get; set; } + } - public class Dest - { - public string ValueFoo1 { get; set; } - public string ValueFoo2 { get; set; } - public string ValueFoo3 { get; set; } - public string ValueFoo4 { get; set; } - } + public class Dest + { + public string ValueFoo1 { get; set; } + public string ValueFoo2 { get; set; } + public string ValueFoo3 { get; set; } + public string ValueFoo4 { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ForMember("ValueFoo1", opt => opt.ConvertUsing("Value1")) - .ForMember("ValueFoo2", opt => opt.ConvertUsing("Value2")) - .ForMember("ValueFoo3", opt => opt.ConvertUsing("Value3")) - .ForMember("ValueFoo4", opt => opt.ConvertUsing("Value4")); - }); - - [Fact] - public void Should_apply_converters() + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .ForMember("ValueFoo1", opt => opt.ConvertUsing("Value1")) + .ForMember("ValueFoo2", opt => opt.ConvertUsing("Value2")) + .ForMember("ValueFoo3", opt => opt.ConvertUsing("Value3")) + .ForMember("ValueFoo4", opt => opt.ConvertUsing("Value4")); + }); + + [Fact] + public void Should_apply_converters() + { + var source = new Source { - var source = new Source - { - Value1 = 1, - Value2 = 2, - Value3 = 3, - Value4 = 4 - }; + Value1 = 1, + Value2 = 2, + Value3 = 3, + Value4 = 4 + }; - var dest = Mapper.Map(source); + var dest = Mapper.Map(source); - dest.ValueFoo1.ShouldBe("00000001"); - dest.ValueFoo2.ShouldBe("00000002"); - dest.ValueFoo3.ShouldBe("0003"); - dest.ValueFoo4.ShouldBe("0004"); - } + dest.ValueFoo1.ShouldBe("00000001"); + dest.ValueFoo2.ShouldBe("00000002"); + dest.ValueFoo3.ShouldBe("0003"); + dest.ValueFoo4.ShouldBe("0004"); } + } - public class When_specifying_value_converter_for_type_and_string_based_matching_member : AutoMapperSpecBase + public class When_specifying_value_converter_for_type_and_string_based_matching_member : AutoMapperSpecBase + { + public class EightDigitIntToStringConverter : IValueConverter { - public class EightDigitIntToStringConverter : IValueConverter - { - public string Convert(int sourceMember, ResolutionContext context) - => sourceMember.ToString("d8"); - } - public class FourDigitIntToStringConverter : IValueConverter - { - public string Convert(int sourceMember, ResolutionContext context) - => sourceMember.ToString("d4"); - } + public string Convert(int sourceMember, ResolutionContext context) + => sourceMember.ToString("d8"); + } + public class FourDigitIntToStringConverter : IValueConverter + { + public string Convert(int sourceMember, ResolutionContext context) + => sourceMember.ToString("d4"); + } - public class Source - { - public int Value1 { get; set; } - public int Value2 { get; set; } - public int Value3 { get; set; } - public int Value4 { get; set; } - } + public class Source + { + public int Value1 { get; set; } + public int Value2 { get; set; } + public int Value3 { get; set; } + public int Value4 { get; set; } + } - public class Dest - { - public string Value1 { get; set; } - public string Value2 { get; set; } - public string Value3 { get; set; } - public string Value4 { get; set; } - } + public class Dest + { + public string Value1 { get; set; } + public string Value2 { get; set; } + public string Value3 { get; set; } + public string Value4 { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(typeof(Source), typeof(Dest)) - .ForMember("Value1", opt => opt.ConvertUsing(typeof(EightDigitIntToStringConverter))) - .ForMember("Value2", opt => opt.ConvertUsing(typeof(EightDigitIntToStringConverter))) - .ForMember("Value3", opt => opt.ConvertUsing(typeof(FourDigitIntToStringConverter))) - .ForMember("Value4", opt => opt.ConvertUsing(typeof(FourDigitIntToStringConverter))); - }); - - [Fact] - public void Should_apply_converters() + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(typeof(Source), typeof(Dest)) + .ForMember("Value1", opt => opt.ConvertUsing(typeof(EightDigitIntToStringConverter))) + .ForMember("Value2", opt => opt.ConvertUsing(typeof(EightDigitIntToStringConverter))) + .ForMember("Value3", opt => opt.ConvertUsing(typeof(FourDigitIntToStringConverter))) + .ForMember("Value4", opt => opt.ConvertUsing(typeof(FourDigitIntToStringConverter))); + }); + + [Fact] + public void Should_apply_converters() + { + var source = new Source { - var source = new Source - { - Value1 = 1, - Value2 = 2, - Value3 = 3, - Value4 = 4 - }; + Value1 = 1, + Value2 = 2, + Value3 = 3, + Value4 = 4 + }; - var dest = Mapper.Map(source); + var dest = Mapper.Map(source); - dest.Value1.ShouldBe("00000001"); - dest.Value2.ShouldBe("00000002"); - dest.Value3.ShouldBe("0003"); - dest.Value4.ShouldBe("0004"); - } + dest.Value1.ShouldBe("00000001"); + dest.Value2.ShouldBe("00000002"); + dest.Value3.ShouldBe("0003"); + dest.Value4.ShouldBe("0004"); } + } - public class When_specifying_value_converter_for_type_and_string_based_non_matching_member : AutoMapperSpecBase + public class When_specifying_value_converter_for_type_and_string_based_non_matching_member : AutoMapperSpecBase + { + public class EightDigitIntToStringConverter : IValueConverter { - public class EightDigitIntToStringConverter : IValueConverter - { - public string Convert(int sourceMember, ResolutionContext context) - => sourceMember.ToString("d8"); - } - public class FourDigitIntToStringConverter : IValueConverter - { - public string Convert(int sourceMember, ResolutionContext context) - => sourceMember.ToString("d4"); - } + public string Convert(int sourceMember, ResolutionContext context) + => sourceMember.ToString("d8"); + } + public class FourDigitIntToStringConverter : IValueConverter + { + public string Convert(int sourceMember, ResolutionContext context) + => sourceMember.ToString("d4"); + } - public class Source - { - public int Value1 { get; set; } - public int Value2 { get; set; } - public int Value3 { get; set; } - public int Value4 { get; set; } - } + public class Source + { + public int Value1 { get; set; } + public int Value2 { get; set; } + public int Value3 { get; set; } + public int Value4 { get; set; } + } - public class Dest - { - public string ValueFoo1 { get; set; } - public string ValueFoo2 { get; set; } - public string ValueFoo3 { get; set; } - public string ValueFoo4 { get; set; } - } + public class Dest + { + public string ValueFoo1 { get; set; } + public string ValueFoo2 { get; set; } + public string ValueFoo3 { get; set; } + public string ValueFoo4 { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(typeof(Source), typeof(Dest)) - .ForMember("ValueFoo1", opt => opt.ConvertUsing(typeof(EightDigitIntToStringConverter), "Value1")) - .ForMember("ValueFoo2", opt => opt.ConvertUsing(typeof(EightDigitIntToStringConverter), "Value2")) - .ForMember("ValueFoo3", opt => opt.ConvertUsing(typeof(FourDigitIntToStringConverter), "Value3")) - .ForMember("ValueFoo4", opt => opt.ConvertUsing(typeof(FourDigitIntToStringConverter), "Value4")); - }); - - [Fact] - public void Should_apply_converters() + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(typeof(Source), typeof(Dest)) + .ForMember("ValueFoo1", opt => opt.ConvertUsing(typeof(EightDigitIntToStringConverter), "Value1")) + .ForMember("ValueFoo2", opt => opt.ConvertUsing(typeof(EightDigitIntToStringConverter), "Value2")) + .ForMember("ValueFoo3", opt => opt.ConvertUsing(typeof(FourDigitIntToStringConverter), "Value3")) + .ForMember("ValueFoo4", opt => opt.ConvertUsing(typeof(FourDigitIntToStringConverter), "Value4")); + }); + + [Fact] + public void Should_apply_converters() + { + var source = new Source { - var source = new Source - { - Value1 = 1, - Value2 = 2, - Value3 = 3, - Value4 = 4 - }; + Value1 = 1, + Value2 = 2, + Value3 = 3, + Value4 = 4 + }; - var dest = Mapper.Map(source); + var dest = Mapper.Map(source); - dest.ValueFoo1.ShouldBe("00000001"); - dest.ValueFoo2.ShouldBe("00000002"); - dest.ValueFoo3.ShouldBe("0003"); - dest.ValueFoo4.ShouldBe("0004"); - } + dest.ValueFoo1.ShouldBe("00000001"); + dest.ValueFoo2.ShouldBe("00000002"); + dest.ValueFoo3.ShouldBe("0003"); + dest.ValueFoo4.ShouldBe("0004"); } + } - public class When_specifying_value_converter_instance_for_matching_member : AutoMapperSpecBase + public class When_specifying_value_converter_instance_for_matching_member : AutoMapperSpecBase + { + public class EightDigitIntToStringConverter : IValueConverter { - public class EightDigitIntToStringConverter : IValueConverter - { - public string Convert(int sourceMember, ResolutionContext context) - => sourceMember.ToString("d8"); - } - public class FourDigitIntToStringConverter : IValueConverter - { - public string Convert(int sourceMember, ResolutionContext context) - => sourceMember.ToString("d4"); - } + public string Convert(int sourceMember, ResolutionContext context) + => sourceMember.ToString("d8"); + } + public class FourDigitIntToStringConverter : IValueConverter + { + public string Convert(int sourceMember, ResolutionContext context) + => sourceMember.ToString("d4"); + } - public class Source - { - public int Value1 { get; set; } - public int Value2 { get; set; } - public int Value3 { get; set; } - public int Value4 { get; set; } - } + public class Source + { + public int Value1 { get; set; } + public int Value2 { get; set; } + public int Value3 { get; set; } + public int Value4 { get; set; } + } - public class Dest - { - public string Value1 { get; set; } - public string Value2 { get; set; } - public string Value3 { get; set; } - public string Value4 { get; set; } - } + public class Dest + { + public string Value1 { get; set; } + public string Value2 { get; set; } + public string Value3 { get; set; } + public string Value4 { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ForMember(d => d.Value1, opt => opt.ConvertUsing(new EightDigitIntToStringConverter())) - .ForMember(d => d.Value2, opt => opt.ConvertUsing(new EightDigitIntToStringConverter())) - .ForMember(d => d.Value3, opt => opt.ConvertUsing(new FourDigitIntToStringConverter())) - .ForMember(d => d.Value4, opt => opt.ConvertUsing(new FourDigitIntToStringConverter())); - }); - - [Fact] - public void Should_apply_converters() + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .ForMember(d => d.Value1, opt => opt.ConvertUsing(new EightDigitIntToStringConverter())) + .ForMember(d => d.Value2, opt => opt.ConvertUsing(new EightDigitIntToStringConverter())) + .ForMember(d => d.Value3, opt => opt.ConvertUsing(new FourDigitIntToStringConverter())) + .ForMember(d => d.Value4, opt => opt.ConvertUsing(new FourDigitIntToStringConverter())); + }); + + [Fact] + public void Should_apply_converters() + { + var source = new Source { - var source = new Source - { - Value1 = 1, - Value2 = 2, - Value3 = 3, - Value4 = 4 - }; + Value1 = 1, + Value2 = 2, + Value3 = 3, + Value4 = 4 + }; - var dest = Mapper.Map(source); + var dest = Mapper.Map(source); - dest.Value1.ShouldBe("00000001"); - dest.Value2.ShouldBe("00000002"); - dest.Value3.ShouldBe("0003"); - dest.Value4.ShouldBe("0004"); - } + dest.Value1.ShouldBe("00000001"); + dest.Value2.ShouldBe("00000002"); + dest.Value3.ShouldBe("0003"); + dest.Value4.ShouldBe("0004"); } + } - public class When_specifying_value_converter_instance_for_non_matching_member : AutoMapperSpecBase + public class When_specifying_value_converter_instance_for_non_matching_member : AutoMapperSpecBase + { + public class EightDigitIntToStringConverter : IValueConverter { - public class EightDigitIntToStringConverter : IValueConverter - { - public string Convert(int sourceMember, ResolutionContext context) - => sourceMember.ToString("d8"); - } - public class FourDigitIntToStringConverter : IValueConverter - { - public string Convert(int sourceMember, ResolutionContext context) - => sourceMember.ToString("d4"); - } + public string Convert(int sourceMember, ResolutionContext context) + => sourceMember.ToString("d8"); + } + public class FourDigitIntToStringConverter : IValueConverter + { + public string Convert(int sourceMember, ResolutionContext context) + => sourceMember.ToString("d4"); + } - public class Source - { - public int Value1 { get; set; } - public int Value2 { get; set; } - public int Value3 { get; set; } - public int Value4 { get; set; } - } + public class Source + { + public int Value1 { get; set; } + public int Value2 { get; set; } + public int Value3 { get; set; } + public int Value4 { get; set; } + } - public class Dest - { - public string ValueFoo1 { get; set; } - public string ValueFoo2 { get; set; } - public string ValueFoo3 { get; set; } - public string ValueFoo4 { get; set; } - } + public class Dest + { + public string ValueFoo1 { get; set; } + public string ValueFoo2 { get; set; } + public string ValueFoo3 { get; set; } + public string ValueFoo4 { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ForMember(d => d.ValueFoo1, opt => opt.ConvertUsing(new EightDigitIntToStringConverter(), src => src.Value1)) - .ForMember(d => d.ValueFoo2, opt => opt.ConvertUsing(new EightDigitIntToStringConverter(), src => src.Value2)) - .ForMember(d => d.ValueFoo3, opt => opt.ConvertUsing(new FourDigitIntToStringConverter(), src => src.Value3)) - .ForMember(d => d.ValueFoo4, opt => opt.ConvertUsing(new FourDigitIntToStringConverter(), src => src.Value4)); - }); - - [Fact] - public void Should_apply_converters() + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .ForMember(d => d.ValueFoo1, opt => opt.ConvertUsing(new EightDigitIntToStringConverter(), src => src.Value1)) + .ForMember(d => d.ValueFoo2, opt => opt.ConvertUsing(new EightDigitIntToStringConverter(), src => src.Value2)) + .ForMember(d => d.ValueFoo3, opt => opt.ConvertUsing(new FourDigitIntToStringConverter(), src => src.Value3)) + .ForMember(d => d.ValueFoo4, opt => opt.ConvertUsing(new FourDigitIntToStringConverter(), src => src.Value4)); + }); + + [Fact] + public void Should_apply_converters() + { + var source = new Source { - var source = new Source - { - Value1 = 1, - Value2 = 2, - Value3 = 3, - Value4 = 4 - }; + Value1 = 1, + Value2 = 2, + Value3 = 3, + Value4 = 4 + }; - var dest = Mapper.Map(source); + var dest = Mapper.Map(source); - dest.ValueFoo1.ShouldBe("00000001"); - dest.ValueFoo2.ShouldBe("00000002"); - dest.ValueFoo3.ShouldBe("0003"); - dest.ValueFoo4.ShouldBe("0004"); - } + dest.ValueFoo1.ShouldBe("00000001"); + dest.ValueFoo2.ShouldBe("00000002"); + dest.ValueFoo3.ShouldBe("0003"); + dest.ValueFoo4.ShouldBe("0004"); } + } - public class When_specifying_value_converter_instance_for_string_based_matching_member : AutoMapperSpecBase + public class When_specifying_value_converter_instance_for_string_based_matching_member : AutoMapperSpecBase + { + public class EightDigitIntToStringConverter : IValueConverter { - public class EightDigitIntToStringConverter : IValueConverter - { - public string Convert(int sourceMember, ResolutionContext context) - => sourceMember.ToString("d8"); - } - public class FourDigitIntToStringConverter : IValueConverter - { - public string Convert(int sourceMember, ResolutionContext context) - => sourceMember.ToString("d4"); - } + public string Convert(int sourceMember, ResolutionContext context) + => sourceMember.ToString("d8"); + } + public class FourDigitIntToStringConverter : IValueConverter + { + public string Convert(int sourceMember, ResolutionContext context) + => sourceMember.ToString("d4"); + } - public class Source - { - public int Value1 { get; set; } - public int Value2 { get; set; } - public int Value3 { get; set; } - public int Value4 { get; set; } - } + public class Source + { + public int Value1 { get; set; } + public int Value2 { get; set; } + public int Value3 { get; set; } + public int Value4 { get; set; } + } - public class Dest - { - public string Value1 { get; set; } - public string Value2 { get; set; } - public string Value3 { get; set; } - public string Value4 { get; set; } - } + public class Dest + { + public string Value1 { get; set; } + public string Value2 { get; set; } + public string Value3 { get; set; } + public string Value4 { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ForMember("Value1", opt => opt.ConvertUsing(new EightDigitIntToStringConverter())) - .ForMember("Value2", opt => opt.ConvertUsing(new EightDigitIntToStringConverter())) - .ForMember("Value3", opt => opt.ConvertUsing(new FourDigitIntToStringConverter())) - .ForMember("Value4", opt => opt.ConvertUsing(new FourDigitIntToStringConverter())); - }); - - [Fact] - public void Should_apply_converters() + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .ForMember("Value1", opt => opt.ConvertUsing(new EightDigitIntToStringConverter())) + .ForMember("Value2", opt => opt.ConvertUsing(new EightDigitIntToStringConverter())) + .ForMember("Value3", opt => opt.ConvertUsing(new FourDigitIntToStringConverter())) + .ForMember("Value4", opt => opt.ConvertUsing(new FourDigitIntToStringConverter())); + }); + + [Fact] + public void Should_apply_converters() + { + var source = new Source { - var source = new Source - { - Value1 = 1, - Value2 = 2, - Value3 = 3, - Value4 = 4 - }; + Value1 = 1, + Value2 = 2, + Value3 = 3, + Value4 = 4 + }; - var dest = Mapper.Map(source); + var dest = Mapper.Map(source); - dest.Value1.ShouldBe("00000001"); - dest.Value2.ShouldBe("00000002"); - dest.Value3.ShouldBe("0003"); - dest.Value4.ShouldBe("0004"); - } + dest.Value1.ShouldBe("00000001"); + dest.Value2.ShouldBe("00000002"); + dest.Value3.ShouldBe("0003"); + dest.Value4.ShouldBe("0004"); } + } - public class When_specifying_value_converter_instance_for_string_based_non_matching_member : AutoMapperSpecBase + public class When_specifying_value_converter_instance_for_string_based_non_matching_member : AutoMapperSpecBase + { + public class EightDigitIntToStringConverter : IValueConverter { - public class EightDigitIntToStringConverter : IValueConverter - { - public string Convert(int sourceMember, ResolutionContext context) - => sourceMember.ToString("d8"); - } - public class FourDigitIntToStringConverter : IValueConverter - { - public string Convert(int sourceMember, ResolutionContext context) - => sourceMember.ToString("d4"); - } + public string Convert(int sourceMember, ResolutionContext context) + => sourceMember.ToString("d8"); + } + public class FourDigitIntToStringConverter : IValueConverter + { + public string Convert(int sourceMember, ResolutionContext context) + => sourceMember.ToString("d4"); + } - public class Source - { - public int Value1 { get; set; } - public int Value2 { get; set; } - public int Value3 { get; set; } - public int Value4 { get; set; } - } + public class Source + { + public int Value1 { get; set; } + public int Value2 { get; set; } + public int Value3 { get; set; } + public int Value4 { get; set; } + } - public class Dest - { - public string ValueFoo1 { get; set; } - public string ValueFoo2 { get; set; } - public string ValueFoo3 { get; set; } - public string ValueFoo4 { get; set; } - } + public class Dest + { + public string ValueFoo1 { get; set; } + public string ValueFoo2 { get; set; } + public string ValueFoo3 { get; set; } + public string ValueFoo4 { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ForMember("ValueFoo1", opt => opt.ConvertUsing(new EightDigitIntToStringConverter(), "Value1")) - .ForMember("ValueFoo2", opt => opt.ConvertUsing(new EightDigitIntToStringConverter(), "Value2")) - .ForMember("ValueFoo3", opt => opt.ConvertUsing(new FourDigitIntToStringConverter(), "Value3")) - .ForMember("ValueFoo4", opt => opt.ConvertUsing(new FourDigitIntToStringConverter(), "Value4")); - }); - - [Fact] - public void Should_apply_converters() + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .ForMember("ValueFoo1", opt => opt.ConvertUsing(new EightDigitIntToStringConverter(), "Value1")) + .ForMember("ValueFoo2", opt => opt.ConvertUsing(new EightDigitIntToStringConverter(), "Value2")) + .ForMember("ValueFoo3", opt => opt.ConvertUsing(new FourDigitIntToStringConverter(), "Value3")) + .ForMember("ValueFoo4", opt => opt.ConvertUsing(new FourDigitIntToStringConverter(), "Value4")); + }); + + [Fact] + public void Should_apply_converters() + { + var source = new Source { - var source = new Source - { - Value1 = 1, - Value2 = 2, - Value3 = 3, - Value4 = 4 - }; + Value1 = 1, + Value2 = 2, + Value3 = 3, + Value4 = 4 + }; - var dest = Mapper.Map(source); + var dest = Mapper.Map(source); - dest.ValueFoo1.ShouldBe("00000001"); - dest.ValueFoo2.ShouldBe("00000002"); - dest.ValueFoo3.ShouldBe("0003"); - dest.ValueFoo4.ShouldBe("0004"); - } + dest.ValueFoo1.ShouldBe("00000001"); + dest.ValueFoo2.ShouldBe("00000002"); + dest.ValueFoo3.ShouldBe("0003"); + dest.ValueFoo4.ShouldBe("0004"); } + } - public class When_specifying_value_converter_for_all_members : AutoMapperSpecBase + public class When_specifying_value_converter_for_all_members : AutoMapperSpecBase + { + public class EightDigitIntToStringConverter : IValueConverter { - public class EightDigitIntToStringConverter : IValueConverter - { - public string Convert(int sourceMember, ResolutionContext context) - => sourceMember.ToString("d8"); - } + public string Convert(int sourceMember, ResolutionContext context) + => sourceMember.ToString("d8"); + } - public class Source - { - public int Value { get; set; } - } + public class Source + { + public int Value { get; set; } + } - public class OtherSource - { - public int Value { get; set; } - } + public class OtherSource + { + public int Value { get; set; } + } - public class Dest - { - public string Value { get; set; } - } + public class Dest + { + public string Value { get; set; } + } - public class OtherDest - { - public string Value { get; set; } - } + public class OtherDest + { + public string Value { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); + cfg.CreateMap(); + cfg.ForAllPropertyMaps + (pm => pm.SourceType == typeof(int) && pm.DestinationType == typeof(string), + (pm, opt) => opt.ConvertUsing(new EightDigitIntToStringConverter())); + }); + + [Fact] + public void Should_apply_converters() + { + var source = new Source { - cfg.CreateMap(); - cfg.CreateMap(); - cfg.ForAllPropertyMaps - (pm => pm.SourceType == typeof(int) && pm.DestinationType == typeof(string), - (pm, opt) => opt.ConvertUsing(new EightDigitIntToStringConverter())); - }); - - [Fact] - public void Should_apply_converters() + Value = 1, + }; + var otherSource = new OtherSource { - var source = new Source - { - Value = 1, - }; - var otherSource = new OtherSource - { - Value = 2, - }; + Value = 2, + }; - var dest = Mapper.Map(source); - var otherDest = Mapper.Map(otherSource); + var dest = Mapper.Map(source); + var otherDest = Mapper.Map(otherSource); - dest.Value.ShouldBe("00000001"); - otherDest.Value.ShouldBe("00000002"); - } + dest.Value.ShouldBe("00000001"); + otherDest.Value.ShouldBe("00000002"); } - } + } \ No newline at end of file diff --git a/src/UnitTests/ValueTypes.cs b/src/UnitTests/ValueTypes.cs index 4cb9fa0600..415ca4e2e2 100644 --- a/src/UnitTests/ValueTypes.cs +++ b/src/UnitTests/ValueTypes.cs @@ -3,204 +3,203 @@ using Shouldly; using System.Linq; -namespace AutoMapper.UnitTests.ValueTypes +namespace AutoMapper.UnitTests.ValueTypes; + +public class When_value_types_are_the_source_of_map_cycles : AutoMapperSpecBase { - public class When_value_types_are_the_source_of_map_cycles : AutoMapperSpecBase + public struct Source { - public struct Source - { - public InnerSource Value { get; set; } - } + public InnerSource Value { get; set; } + } - public class InnerSource - { - public Source Parent { get; set; } - } + public class InnerSource + { + public Source Parent { get; set; } + } - public struct Destination - { - public InnerDestination Value { get; set; } - } + public struct Destination + { + public InnerDestination Value { get; set; } + } - public class InnerDestination - { - public Destination Parent { get; set; } - } + public class InnerDestination + { + public Destination Parent { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg=> - { - cfg.CreateMap().MaxDepth(2); - cfg.CreateMap(); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg=> + { + cfg.CreateMap().MaxDepth(2); + cfg.CreateMap(); + }); - [Fact] - public void Should_work() - { - var innerSource = new InnerSource(); - var source = new Source { Value = innerSource }; - innerSource.Parent = source; - Mapper.Map(source); - } + [Fact] + public void Should_work() + { + var innerSource = new InnerSource(); + var source = new Source { Value = innerSource }; + innerSource.Parent = source; + Mapper.Map(source); } +} - public class When_value_types_are_the_source_of_map_cycles_with_PreserveReferences : AutoMapperSpecBase +public class When_value_types_are_the_source_of_map_cycles_with_PreserveReferences : AutoMapperSpecBase +{ + public struct Source { - public struct Source - { - public InnerSource Value { get; set; } - } + public InnerSource Value { get; set; } + } - public class InnerSource - { - public Source Parent { get; set; } - public InnerSource Inner { get; set; } - } + public class InnerSource + { + public Source Parent { get; set; } + public InnerSource Inner { get; set; } + } - public struct Destination - { - public InnerDestination Value { get; set; } - } + public struct Destination + { + public InnerDestination Value { get; set; } + } - public class InnerDestination - { - public Destination Parent { get; set; } - public InnerDestination Inner { get; set; } - } + public class InnerDestination + { + public Destination Parent { get; set; } + public InnerDestination Inner { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().MaxDepth(2); - cfg.CreateMap(); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().MaxDepth(2); + cfg.CreateMap(); + }); - [Fact] - public void Should_work() - { - var innerSource = new InnerSource(); - var source = new Source { Value = innerSource }; - innerSource.Parent = source; - innerSource.Inner = innerSource; - var destinationValue = Mapper.Map(source).Value; - destinationValue.Inner.ShouldBe(destinationValue); - FindTypeMapFor().MemberMaps.Single(m => m.DestinationName == nameof(InnerDestination.Inner)).Inline.ShouldBeFalse(); - } + [Fact] + public void Should_work() + { + var innerSource = new InnerSource(); + var source = new Source { Value = innerSource }; + innerSource.Parent = source; + innerSource.Inner = innerSource; + var destinationValue = Mapper.Map(source).Value; + destinationValue.Inner.ShouldBe(destinationValue); + FindTypeMapFor().MemberMaps.Single(m => m.DestinationName == nameof(InnerDestination.Inner)).Inline.ShouldBeFalse(); } +} - public class When_destination_type_is_a_value_type : AutoMapperSpecBase - { - private Destination _destination; +public class When_destination_type_is_a_value_type : AutoMapperSpecBase +{ + private Destination _destination; - public class Source - { - public int Value1 { get; set; } - public string Value2 { get; set; } - } + public class Source + { + public int Value1 { get; set; } + public string Value2 { get; set; } + } - public struct Destination - { - public int Value1 { get; set; } - public string Value2; - } + public struct Destination + { + public int Value1 { get; set; } + public string Value2; + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap(); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap(); - }); + }); - protected override void Because_of() - { - _destination = Mapper.Map(new Source {Value1 = 4, Value2 = "hello"}); - } + protected override void Because_of() + { + _destination = Mapper.Map(new Source {Value1 = 4, Value2 = "hello"}); + } - [Fact] - public void Should_map_property_value() - { - _destination.Value1.ShouldBe(4); - } + [Fact] + public void Should_map_property_value() + { + _destination.Value1.ShouldBe(4); + } - [Fact] - public void Should_map_field_value() - { - _destination.Value2.ShouldBe("hello"); - } + [Fact] + public void Should_map_field_value() + { + _destination.Value2.ShouldBe("hello"); } +} - public class When_source_struct_config_has_custom_mappings : AutoMapperSpecBase +public class When_source_struct_config_has_custom_mappings : AutoMapperSpecBase +{ + public struct matrixDigiInStruct1 { - public struct matrixDigiInStruct1 - { - public ushort CNCinfo; - public ushort Reg1; - public ushort Reg2; - } - public class DigiIn1 - { - public ushort CncInfo { get; set; } - public ushort Reg1 { get; set; } - public ushort Reg2 { get; set; } - } + public ushort CNCinfo; + public ushort Reg1; + public ushort Reg2; + } + public class DigiIn1 + { + public ushort CncInfo { get; set; } + public ushort Reg1 { get; set; } + public ushort Reg2 { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new( - cfg => cfg.CreateMap() - .ForMember(d => d.CncInfo, x => x.MapFrom(s => s.CNCinfo))); + protected override MapperConfiguration CreateConfiguration() => new( + cfg => cfg.CreateMap() + .ForMember(d => d.CncInfo, x => x.MapFrom(s => s.CNCinfo))); - [Fact] - public void Should_map_correctly() + [Fact] + public void Should_map_correctly() + { + var source = new matrixDigiInStruct1 { - var source = new matrixDigiInStruct1 - { - CNCinfo = 5, - Reg1 = 6, - Reg2 = 7 - }; - var dest = Mapper.Map(source); + CNCinfo = 5, + Reg1 = 6, + Reg2 = 7 + }; + var dest = Mapper.Map(source); - dest.CncInfo.ShouldBe(source.CNCinfo); - dest.Reg1.ShouldBe(source.Reg1); - dest.Reg2.ShouldBe(source.Reg2); - } + dest.CncInfo.ShouldBe(source.CNCinfo); + dest.Reg1.ShouldBe(source.Reg1); + dest.Reg2.ShouldBe(source.Reg2); } +} - public class When_destination_type_is_a_nullable_value_type : AutoMapperSpecBase - { - private Destination _destination; +public class When_destination_type_is_a_nullable_value_type : AutoMapperSpecBase +{ + private Destination _destination; - public class Source - { - public string Value1 { get; set; } - public string Value2 { get; set; } - } + public class Source + { + public string Value1 { get; set; } + public string Value2 { get; set; } + } - public struct Destination - { - public int Value1 { get; set; } - public int? Value2 { get; set; } - } + public struct Destination + { + public int Value1 { get; set; } + public int? Value2 { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap().ConvertUsing((string s) => Convert.ToInt32(s)); - cfg.CreateMap().ConvertUsing((string s) => (int?) Convert.ToInt32(s)); - cfg.CreateMap(); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap().ConvertUsing((string s) => Convert.ToInt32(s)); + cfg.CreateMap().ConvertUsing((string s) => (int?) Convert.ToInt32(s)); + cfg.CreateMap(); + }); - protected override void Because_of() - { - _destination = Mapper.Map(new Source {Value1 = "10", Value2 = "20"}); - } + protected override void Because_of() + { + _destination = Mapper.Map(new Source {Value1 = "10", Value2 = "20"}); + } - [Fact] - public void Should_use_map_registered_for_underlying_type() - { - _destination.Value2.ShouldBe(20); - } + [Fact] + public void Should_use_map_registered_for_underlying_type() + { + _destination.Value2.ShouldBe(20); + } - [Fact] - public void Should_still_map_value_type() - { - _destination.Value1.ShouldBe(10); - } + [Fact] + public void Should_still_map_value_type() + { + _destination.Value1.ShouldBe(10); } } \ No newline at end of file From 288c4adbbe71e3b83038a1d49bd056efe91f6fd2 Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Sat, 3 Sep 2022 19:27:54 +0300 Subject: [PATCH 49/67] global usings --- .editorconfig | 2 +- Directory.Build.props | 9 +++++++++ src/AutoMapper/AssemblyInfo.cs | 3 +-- src/AutoMapper/AutoMapper.csproj | 9 +++++++-- src/AutoMapper/AutoMapperMappingException.cs | 3 --- .../Annotations/AutoMapAttribute.cs | 4 +--- .../Configuration/Annotations/IgnoreAttribute.cs | 4 +--- .../Annotations/MapAtRuntimeAttribute.cs | 4 +--- .../Annotations/MappingOrderAttribute.cs | 4 +--- .../Annotations/NullSubstituteAttribute.cs | 4 +--- .../Annotations/SourceMemberAttribute.cs | 6 +----- .../Annotations/UseExistingValueAttribute.cs | 4 +--- .../Annotations/ValueConverterAttribute.cs | 5 +---- .../Annotations/ValueResolverAttribute.cs | 5 +---- .../Configuration/ConfigurationValidator.cs | 5 ----- src/AutoMapper/Configuration/Conventions.cs | 6 ------ .../CtorParamConfigurationExpression.cs | 9 +-------- .../Configuration/IMappingExpression.cs | 5 ----- .../Configuration/IMappingExpressionBase.cs | 4 ---- .../Configuration/IMappingOperationOptions.cs | 5 +---- .../IMemberConfigurationExpression.cs | 4 ---- .../Configuration/INamingConvention.cs | 2 -- .../Configuration/IProfileExpression.cs | 3 --- .../Configuration/MapperConfiguration.cs | 10 ---------- .../MapperConfigurationExpression.cs | 6 ------ .../Configuration/MappingExpression.cs | 7 ------- .../MemberConfigurationExpression.cs | 9 --------- .../Configuration/PathConfigurationExpression.cs | 9 +-------- src/AutoMapper/Configuration/Profile.cs | 8 -------- .../Configuration/SourceMappingExpression.cs | 4 ---- .../Configuration/TypeMapConfiguration.cs | 12 +----------- src/AutoMapper/ConstructorMap.cs | 11 +---------- src/AutoMapper/Execution/ExpressionBuilder.cs | 9 --------- src/AutoMapper/Execution/ObjectFactory.cs | 9 --------- src/AutoMapper/Execution/ProxyGenerator.cs | 7 ------- src/AutoMapper/Execution/TypeMapPlanBuilder.cs | 11 ----------- src/AutoMapper/Features.cs | 7 +------ src/AutoMapper/Internal/InternalApi.cs | 9 +-------- .../Internal/LockingConcurrentDictionary.cs | 1 - src/AutoMapper/Internal/MemberPath.cs | 9 +-------- src/AutoMapper/Internal/PrimitiveHelper.cs | 7 +------ src/AutoMapper/Internal/ReflectionHelper.cs | 7 ------- src/AutoMapper/Internal/TypeDetails.cs | 7 ------- src/AutoMapper/Internal/TypeExtensions.cs | 4 ---- src/AutoMapper/Internal/TypePair.cs | 2 -- src/AutoMapper/Mapper.cs | 6 ------ src/AutoMapper/Mappers/AssignableMapper.cs | 1 - src/AutoMapper/Mappers/CollectionMapper.cs | 9 --------- src/AutoMapper/Mappers/ConstructorMapper.cs | 7 +------ .../Mappers/ConversionOperatorMapper.cs | 5 ----- src/AutoMapper/Mappers/ConvertMapper.cs | 6 +----- src/AutoMapper/Mappers/EnumToEnumMapper.cs | 6 ------ src/AutoMapper/Mappers/FromDynamicMapper.cs | 7 ------- .../Mappers/FromStringDictionaryMapper.cs | 10 +--------- src/AutoMapper/Mappers/IObjectMapper.cs | 6 ------ src/AutoMapper/Mappers/KeyValueMapper.cs | 7 +------ src/AutoMapper/Mappers/MapperRegistry.cs | 1 - .../Mappers/NullableDestinationMapper.cs | 3 --- src/AutoMapper/Mappers/NullableSourceMapper.cs | 3 --- src/AutoMapper/Mappers/ParseStringMapper.cs | 4 +--- src/AutoMapper/Mappers/StringToEnumMapper.cs | 7 ------- src/AutoMapper/Mappers/ToDynamicMapper.cs | 7 ------- .../Mappers/ToStringDictionaryMapper.cs | 9 +-------- src/AutoMapper/Mappers/ToStringMapper.cs | 6 +----- .../Mappers/UnderlyingEnumTypeMapper.cs | 1 - src/AutoMapper/MemberMap.cs | 11 ----------- src/AutoMapper/PathMap.cs | 10 +--------- src/AutoMapper/ProfileMap.cs | 13 ------------- src/AutoMapper/PropertyMap.cs | 7 ------- src/AutoMapper/QueryableExtensions/Extensions.cs | 7 ------- .../QueryableExtensions/NullsafeQueryRewriter.cs | 5 ----- .../QueryableExtensions/ProjectionBuilder.cs | 14 +------------- .../AssignableProjectionMapper.cs | 5 ----- .../ProjectionMappers/EnumProjectionMapper.cs | 8 +------- .../EnumerableProjectionMapper.cs | 10 ---------- .../NullableSourceProjectionMapper.cs | 6 +----- .../ProjectionMappers/StringProjectionMapper.cs | 4 ---- src/AutoMapper/ResolutionContext.cs | 3 --- src/AutoMapper/TypeMap.cs | 15 +-------------- src/Benchmark/BenchEngine.cs | 3 --- src/Benchmark/FlatteningMapper.cs | 3 --- src/Benchmark/HiPerfTimer.cs | 2 -- src/Benchmark/IObjectToObjectMapper.cs | 2 -- src/Benchmark/Program.cs | 4 +--- .../AutoMapper.IntegrationTests.csproj | 11 ++++++++++- src/IntegrationTests/BuiltInTypes/ByteArray.cs | 10 +--------- .../BuiltInTypes/ConvertUsing.cs | 9 +-------- .../BuiltInTypes/DateTimeToNullableDateTime.cs | 10 +--------- src/IntegrationTests/BuiltInTypes/Enums.cs | 10 +--------- .../BuiltInTypes/NullableToNonNullable.cs | 10 +--------- .../ProjectEnumerableOfIntToHashSet.cs | 9 +-------- .../BuiltInTypes/ProjectEnumerableOfIntToList.cs | 11 +---------- src/IntegrationTests/ChildClassTests.cs | 11 +---------- src/IntegrationTests/ConstructorDefaultValue.cs | 6 +----- .../CustomMapFrom/CustomMapFromTest.cs | 8 +------- .../MapObjectPropertyFromSubQuery.cs | 13 +------------ src/IntegrationTests/CustomProjection.cs | 9 +-------- .../ExplicitExpansion/ExpandCollections.cs | 12 +----------- .../ExpandCollectionsWithStrings.cs | 12 +----------- .../ExplicitExpansion/ExpandMembersPath.cs | 12 +----------- ...licitlyExpandCollectionsAndChildReferences.cs | 12 +----------- .../MembersToExpandExpressions.cs | 9 +-------- .../ExplicitExpansion/NestedExplicitExpand.cs | 10 +--------- .../NestedExplicitExpandWithFields.cs | 10 +--------- .../ProjectAndAllowNullCollections.cs | 9 +-------- .../ProjectionWithExplicitExpansion.cs | 13 +------------ .../ICollectionAggregateProjections.cs | 14 +------------- .../IEnumerableAggregateProjections.cs | 14 +------------- .../IEnumerableMemberProjections.cs | 14 +------------- src/IntegrationTests/IncludeMembers.cs | 12 +----------- .../Inheritance/DerivedComplexTypes.cs | 11 +---------- .../OverrideDestinationMappingsTest.cs | 9 +-------- .../Inheritance/ProjectToAbstractType.cs | 10 +--------- src/IntegrationTests/Inheritance/ProxyTests.cs | 10 +--------- .../QueryableInterfaceInheritanceIssue.cs | 9 +-------- src/IntegrationTests/IntegrationTest.cs | 7 +------ src/IntegrationTests/LocalDbContext.cs | 4 +--- .../MaxDepth/MaxDepthWithCollections.cs | 11 +---------- .../MaxDepth/NavigationPropertySO.cs | 12 +----------- src/IntegrationTests/MaxDepth/NestedDtos.cs | 12 +----------- src/IntegrationTests/NullCheckCollections.cs | 14 +------------- src/IntegrationTests/NullSubstitute.cs | 11 +---------- src/IntegrationTests/ParameterizedQueries.cs | 11 +---------- src/IntegrationTests/ProjectionAdvanced.cs | 7 +------ src/IntegrationTests/ProjectionOrderTest.cs | 10 +--------- src/IntegrationTests/ValueTransformerTests.cs | 9 +-------- src/UnitTests/AddProfiles.cs | 6 +----- src/UnitTests/ArraysAndLists.cs | 9 --------- src/UnitTests/AssemblyScanning.cs | 8 +------- src/UnitTests/AssertionExtensions.cs | 7 +------ src/UnitTests/AttributeBasedMaps.cs | 4 ---- src/UnitTests/AutoMapper.UnitTests.csproj | 7 ++++++- src/UnitTests/AutoMapperSpecBase.cs | 6 ------ src/UnitTests/AutoMapperTester.cs | 4 ---- src/UnitTests/BasicFlattening.cs | 8 +------- src/UnitTests/BeforeAfterMapping.cs | 7 ------- src/UnitTests/BidirectionalRelationships.cs | 10 +--------- .../BidirectionalRelationshipsWithoutPR.cs | 7 ------- ...gurationForNonMatchingDestinationMemberBug.cs | 4 ---- src/UnitTests/Bug/AfterMapNestedObjects.cs | 5 +---- .../Bug/AllowNullCollectionsAssignableArray.cs | 7 +------ .../Bug/AllowNullDestinationValuesBugs.cs | 3 --- .../Bug/AssertConfigurationIsValidNullables.cs | 6 +----- src/UnitTests/Bug/AssignableCollectionBug.cs | 4 ---- .../Bug/AutoMapperInheritanceProblemDemo.cs | 5 +---- .../BaseMapWithIncludesAndUnincludedMappings.cs | 4 +--- src/UnitTests/Bug/CannotConvertEnumToNullable.cs | 5 +---- ...notMapICollectionToAggregateSumDestination.cs | 8 +------- ...tProjectIEnumerableToAggregateDestinations.cs | 8 +------- .../Bug/CannotProjectStringToNullableEnum.cs | 8 +------- src/UnitTests/Bug/CaseSensitivityBug.cs | 3 --- .../Bug/CollectionBaseClassGetConvention.cs | 9 +-------- .../Bug/CollectionMapperMapsISetIncorrectly.cs | 7 +------ src/UnitTests/Bug/CollectionWhere.cs | 8 +------- src/UnitTests/Bug/CollectionsNullability.cs | 7 +------ src/UnitTests/Bug/ConditionBug.cs | 16 ---------------- src/UnitTests/Bug/ConstructUsingReturnsNull.cs | 6 +----- .../Bug/ConstructorParameterNamedType.cs | 6 +----- src/UnitTests/Bug/ContextValuesIncorrect.cs | 5 +---- src/UnitTests/Bug/ConvertMapperThreading.cs | 10 +--------- .../CreateMapExpressionWithIgnoredPropertyBug.cs | 11 +---------- src/UnitTests/Bug/CustomConverters.cs | 6 +----- src/UnitTests/Bug/CustomIEnumerableBug.cs | 8 -------- src/UnitTests/Bug/DeepCloningBug.cs | 4 ---- src/UnitTests/Bug/DeepInheritanceIssue.cs | 5 +---- src/UnitTests/Bug/DestinationCtorCalledTwice.cs | 5 +---- .../Bug/DestinationValueInitializedByCtorBug.cs | 8 -------- src/UnitTests/Bug/DuplicateExtensionMethods.cs | 7 +------ src/UnitTests/Bug/DuplicateValuesBug.cs | 4 ---- src/UnitTests/Bug/DuplicateValuesBugWithoutPR.cs | 4 ---- src/UnitTests/Bug/EFCollections.cs | 8 +------- src/UnitTests/Bug/EmptyNullSubstituteBug.cs | 4 ---- src/UnitTests/Bug/EnumCaseSensitivityBug.cs | 7 +------ src/UnitTests/Bug/EnumConditionsBug.cs | 8 +------- src/UnitTests/Bug/EnumMatchingOnValue.cs | 3 --- src/UnitTests/Bug/ExistingArrays.cs | 7 +------ .../ForAllMembersAndDoNotUseDestinationValue.cs | 6 +----- .../GenericCreateMapWithCircularReferences.cs | 6 +----- src/UnitTests/Bug/GenericTypeConverter.cs | 9 +-------- src/UnitTests/Bug/GuidTryExpression.cs | 6 +----- src/UnitTests/Bug/IgnoreAll.cs | 5 ----- src/UnitTests/Bug/IncludeBaseInheritance.cs | 6 +----- src/UnitTests/Bug/IncludeInheritance.cs | 6 +----- src/UnitTests/Bug/InitializeNRE.cs | 7 +------ src/UnitTests/Bug/IntToNullableDecimal.cs | 6 +----- .../Bug/InterfaceMultipleInheritance.cs | 4 ---- src/UnitTests/Bug/InterfaceSelfMappingBug.cs | 5 +---- src/UnitTests/Bug/InternalProperties.cs | 6 +----- src/UnitTests/Bug/JsonNet.cs | 9 +-------- src/UnitTests/Bug/LazyCollectionMapping.cs | 9 +-------- src/UnitTests/Bug/ListSourceMapperBug.cs | 9 --------- src/UnitTests/Bug/MapAtRuntime/BaseEntity.cs | 8 +------- src/UnitTests/Bug/MapAtRuntime/BaseEntityDTO.cs | 8 +------- src/UnitTests/Bug/MapAtRuntime/Entity1.cs | 8 +------- src/UnitTests/Bug/MapAtRuntime/Entity10.cs | 4 +--- src/UnitTests/Bug/MapAtRuntime/Entity11.cs | 8 +------- src/UnitTests/Bug/MapAtRuntime/Entity12.cs | 8 +------- src/UnitTests/Bug/MapAtRuntime/Entity13.cs | 8 +------- src/UnitTests/Bug/MapAtRuntime/Entity14.cs | 9 +-------- src/UnitTests/Bug/MapAtRuntime/Entity15.cs | 8 +------- src/UnitTests/Bug/MapAtRuntime/Entity16.cs | 8 +------- src/UnitTests/Bug/MapAtRuntime/Entity17.cs | 8 +------- src/UnitTests/Bug/MapAtRuntime/Entity18.cs | 4 +--- src/UnitTests/Bug/MapAtRuntime/Entity19.cs | 4 +--- src/UnitTests/Bug/MapAtRuntime/Entity2.cs | 4 +--- src/UnitTests/Bug/MapAtRuntime/Entity20.cs | 8 +------- src/UnitTests/Bug/MapAtRuntime/Entity21.cs | 4 +--- src/UnitTests/Bug/MapAtRuntime/Entity22.cs | 8 +------- src/UnitTests/Bug/MapAtRuntime/Entity23.cs | 8 +------- src/UnitTests/Bug/MapAtRuntime/Entity24.cs | 8 +------- src/UnitTests/Bug/MapAtRuntime/Entity25.cs | 9 +-------- src/UnitTests/Bug/MapAtRuntime/Entity26.cs | 8 +------- src/UnitTests/Bug/MapAtRuntime/Entity3.cs | 8 +------- src/UnitTests/Bug/MapAtRuntime/Entity4.cs | 8 +------- src/UnitTests/Bug/MapAtRuntime/Entity5.cs | 8 +------- src/UnitTests/Bug/MapAtRuntime/Entity6.cs | 8 +------- src/UnitTests/Bug/MapAtRuntime/Entity7.cs | 4 +--- src/UnitTests/Bug/MapAtRuntime/Entity8.cs | 8 +------- src/UnitTests/Bug/MapAtRuntime/Entity9.cs | 4 +--- src/UnitTests/Bug/MapAtRuntime/EntityDTO1.cs | 8 +------- src/UnitTests/Bug/MapAtRuntime/EntityDTO10.cs | 4 +--- src/UnitTests/Bug/MapAtRuntime/EntityDTO11.cs | 8 +------- src/UnitTests/Bug/MapAtRuntime/EntityDTO12.cs | 8 +------- src/UnitTests/Bug/MapAtRuntime/EntityDTO13.cs | 8 +------- src/UnitTests/Bug/MapAtRuntime/EntityDTO14.cs | 9 +-------- src/UnitTests/Bug/MapAtRuntime/EntityDTO15.cs | 8 +------- src/UnitTests/Bug/MapAtRuntime/EntityDTO16.cs | 8 +------- src/UnitTests/Bug/MapAtRuntime/EntityDTO17.cs | 8 +------- src/UnitTests/Bug/MapAtRuntime/EntityDTO18.cs | 4 +--- src/UnitTests/Bug/MapAtRuntime/EntityDTO19.cs | 4 +--- src/UnitTests/Bug/MapAtRuntime/EntityDTO2.cs | 4 +--- src/UnitTests/Bug/MapAtRuntime/EntityDTO20.cs | 8 +------- src/UnitTests/Bug/MapAtRuntime/EntityDTO21.cs | 4 +--- src/UnitTests/Bug/MapAtRuntime/EntityDTO22.cs | 8 +------- src/UnitTests/Bug/MapAtRuntime/EntityDTO23.cs | 8 +------- src/UnitTests/Bug/MapAtRuntime/EntityDTO24.cs | 8 +------- src/UnitTests/Bug/MapAtRuntime/EntityDTO25.cs | 9 +-------- src/UnitTests/Bug/MapAtRuntime/EntityDTO26.cs | 8 +------- src/UnitTests/Bug/MapAtRuntime/EntityDTO3.cs | 8 +------- src/UnitTests/Bug/MapAtRuntime/EntityDTO4.cs | 8 +------- src/UnitTests/Bug/MapAtRuntime/EntityDTO5.cs | 8 +------- src/UnitTests/Bug/MapAtRuntime/EntityDTO6.cs | 8 +------- src/UnitTests/Bug/MapAtRuntime/EntityDTO7.cs | 4 +--- src/UnitTests/Bug/MapAtRuntime/EntityDTO8.cs | 8 +------- src/UnitTests/Bug/MapAtRuntime/EntityDTO9.cs | 4 +--- src/UnitTests/Bug/MapAtRuntime/MapAtRuntime.cs | 5 +---- .../MapAtRuntimeWithCollections/BaseEntity.cs | 8 +------- .../MapAtRuntimeWithCollections/BaseEntityDTO.cs | 8 +------- .../Bug/MapAtRuntimeWithCollections/Entity1.cs | 8 +------- .../Bug/MapAtRuntimeWithCollections/Entity10.cs | 4 +--- .../Bug/MapAtRuntimeWithCollections/Entity11.cs | 8 +------- .../Bug/MapAtRuntimeWithCollections/Entity12.cs | 8 +------- .../Bug/MapAtRuntimeWithCollections/Entity13.cs | 8 +------- .../Bug/MapAtRuntimeWithCollections/Entity14.cs | 9 +-------- .../Bug/MapAtRuntimeWithCollections/Entity15.cs | 8 +------- .../Bug/MapAtRuntimeWithCollections/Entity16.cs | 8 +------- .../Bug/MapAtRuntimeWithCollections/Entity17.cs | 8 +------- .../Bug/MapAtRuntimeWithCollections/Entity18.cs | 4 +--- .../Bug/MapAtRuntimeWithCollections/Entity19.cs | 4 +--- .../Bug/MapAtRuntimeWithCollections/Entity2.cs | 4 +--- .../Bug/MapAtRuntimeWithCollections/Entity20.cs | 8 +------- .../Bug/MapAtRuntimeWithCollections/Entity21.cs | 4 +--- .../Bug/MapAtRuntimeWithCollections/Entity22.cs | 8 +------- .../Bug/MapAtRuntimeWithCollections/Entity23.cs | 8 +------- .../Bug/MapAtRuntimeWithCollections/Entity24.cs | 8 +------- .../Bug/MapAtRuntimeWithCollections/Entity25.cs | 9 +-------- .../Bug/MapAtRuntimeWithCollections/Entity26.cs | 8 +------- .../Bug/MapAtRuntimeWithCollections/Entity3.cs | 8 +------- .../Bug/MapAtRuntimeWithCollections/Entity4.cs | 8 +------- .../Bug/MapAtRuntimeWithCollections/Entity5.cs | 8 +------- .../Bug/MapAtRuntimeWithCollections/Entity6.cs | 8 +------- .../Bug/MapAtRuntimeWithCollections/Entity7.cs | 4 +--- .../Bug/MapAtRuntimeWithCollections/Entity8.cs | 8 +------- .../Bug/MapAtRuntimeWithCollections/Entity9.cs | 4 +--- .../MapAtRuntimeWithCollections/EntityDTO1.cs | 8 +------- .../MapAtRuntimeWithCollections/EntityDTO10.cs | 4 +--- .../MapAtRuntimeWithCollections/EntityDTO11.cs | 8 +------- .../MapAtRuntimeWithCollections/EntityDTO12.cs | 8 +------- .../MapAtRuntimeWithCollections/EntityDTO13.cs | 8 +------- .../MapAtRuntimeWithCollections/EntityDTO14.cs | 9 +-------- .../MapAtRuntimeWithCollections/EntityDTO15.cs | 8 +------- .../MapAtRuntimeWithCollections/EntityDTO16.cs | 8 +------- .../MapAtRuntimeWithCollections/EntityDTO17.cs | 8 +------- .../MapAtRuntimeWithCollections/EntityDTO18.cs | 4 +--- .../MapAtRuntimeWithCollections/EntityDTO19.cs | 4 +--- .../MapAtRuntimeWithCollections/EntityDTO2.cs | 4 +--- .../MapAtRuntimeWithCollections/EntityDTO20.cs | 8 +------- .../MapAtRuntimeWithCollections/EntityDTO21.cs | 4 +--- .../MapAtRuntimeWithCollections/EntityDTO22.cs | 8 +------- .../MapAtRuntimeWithCollections/EntityDTO23.cs | 8 +------- .../MapAtRuntimeWithCollections/EntityDTO24.cs | 8 +------- .../MapAtRuntimeWithCollections/EntityDTO25.cs | 9 +-------- .../MapAtRuntimeWithCollections/EntityDTO26.cs | 8 +------- .../MapAtRuntimeWithCollections/EntityDTO3.cs | 8 +------- .../MapAtRuntimeWithCollections/EntityDTO4.cs | 8 +------- .../MapAtRuntimeWithCollections/EntityDTO5.cs | 8 +------- .../MapAtRuntimeWithCollections/EntityDTO6.cs | 8 +------- .../MapAtRuntimeWithCollections/EntityDTO7.cs | 4 +--- .../MapAtRuntimeWithCollections/EntityDTO8.cs | 8 +------- .../MapAtRuntimeWithCollections/EntityDTO9.cs | 4 +--- .../MapAtRuntimeWithCollections.cs | 6 +----- src/UnitTests/Bug/MapExpandoObjectProperty.cs | 1 - src/UnitTests/Bug/MapFromClosureBug.cs | 5 ----- src/UnitTests/Bug/MapOverloadsWithDynamic.cs | 5 +---- src/UnitTests/Bug/MappingInheritance.cs | 7 +------ .../Bug/MappingToAReadOnlyCollection.cs | 5 ----- src/UnitTests/Bug/MemberListSourceAndForPath.cs | 5 +---- src/UnitTests/Bug/MemberNamedTypeBug.cs | 8 +------- src/UnitTests/Bug/MissingMapping.cs | 7 ------- src/UnitTests/Bug/MultiThreadingIssues.cs | 14 +------------- src/UnitTests/Bug/MultidimensionalArrays.cs | 7 +------ .../Bug/MultipleInterfaceInheritance.cs | 3 --- .../Bug/MultipleTypeConverterInterfaces.cs | 5 +---- src/UnitTests/Bug/NamingConventions.cs | 8 -------- .../NestedMappingProjectionsExplicitExpanding.cs | 8 +------- src/UnitTests/Bug/NonExistingProperty.cs | 6 +----- src/UnitTests/Bug/NullArrayBug.cs | 4 ---- .../Bug/NullConstructorParameterName.cs | 5 +---- src/UnitTests/Bug/NullSubstituteInnerClass.cs | 6 +----- src/UnitTests/Bug/NullSubstituteType.cs | 6 +----- src/UnitTests/Bug/NullToString.cs | 6 +----- src/UnitTests/Bug/NullableBytesAndEnums.cs | 3 --- src/UnitTests/Bug/NullableConverterBug.cs | 8 +------- src/UnitTests/Bug/NullableDateTime.cs | 8 +------- .../Bug/NullableEnumToNullableValueType.cs | 5 +---- src/UnitTests/Bug/NullableEnums.cs | 5 +---- .../Bug/NullableIntToNullableDecimal.cs | 6 +----- src/UnitTests/Bug/NullableIntToNullableEnum.cs | 7 +------ src/UnitTests/Bug/NullablePropertiesBug.cs | 5 +---- src/UnitTests/Bug/NullableResolveUsing.cs | 6 +----- src/UnitTests/Bug/NullableToInvalid.cs | 4 ---- src/UnitTests/Bug/NullableUntypedMapFrom.cs | 5 +---- src/UnitTests/Bug/ObjectEnumToObjectEnum.cs | 7 +------ src/UnitTests/Bug/ObjectTypeMapFailure.cs | 5 +---- ...hMultipleDestinationsAndPreserveReferences.cs | 5 +---- ...OneSourceWithMultipleDestinationsWithoutPR.cs | 5 +---- src/UnitTests/Bug/ParentChildResolversBug.cs | 3 --- .../Bug/PreserveReferencesSameDestination.cs | 8 +------- src/UnitTests/Bug/ProjectCollectionsBug.cs | 7 ------- .../Bug/ProjectConstructorParameters.cs | 7 +------ .../Bug/ProjectUsingTheQueriedEntity.cs | 8 +------- src/UnitTests/Bug/PropertyNamedType.cs | 6 +----- .../Bug/ReadOnlyCollectionMappingBug.cs | 7 +------ src/UnitTests/Bug/ReadOnlyFieldMappingBug.cs | 5 +---- .../Bug/RecognizeDestinationPostfixes.cs | 6 +----- src/UnitTests/Bug/RecognizeIxesBug.cs | 3 --- src/UnitTests/Bug/RemovePrefixes.cs | 7 +------ .../Bug/RepeatedMappingConfigurationTest.cs | 2 -- src/UnitTests/Bug/ReportMissingInclude.cs | 6 +----- src/UnitTests/Bug/ReverseMapReplaceMemberName.cs | 6 +----- .../Bug/SelectiveConfigurationValidation.cs | 4 ---- .../Bug/SequenceContainsNoElementsTest.cs | 8 -------- src/UnitTests/Bug/SetterOnlyBug.cs | 3 --- src/UnitTests/Bug/StructMapping.cs | 6 +----- src/UnitTests/Bug/SubclassMappings.cs | 4 +--- src/UnitTests/Bug/TargetISet.cs | 7 +------ src/UnitTests/Bug/TypeMapIncludeBaseTypes.cs | 7 +------ src/UnitTests/Bug/UseDestinationValue.cs | 7 +------ .../WithoutPreserveReferencesSameDestination.cs | 8 +------- src/UnitTests/BuildExecutionPlan.cs | 6 +----- src/UnitTests/CollectionMapping.cs | 8 -------- src/UnitTests/ConditionalMapping.cs | 6 ------ src/UnitTests/ConfigCompilation.cs | 5 ----- src/UnitTests/ConfigurationFeatureTest.cs | 4 ---- src/UnitTests/ConfigurationRules.cs | 8 +------- src/UnitTests/ConfigurationValidation.cs | 6 ------ src/UnitTests/Constructors.cs | 8 +------- src/UnitTests/ContextItems.cs | 9 +-------- src/UnitTests/CustomCollectionTester.cs | 6 +----- src/UnitTests/CustomMapping.cs | 7 ------- src/UnitTests/CustomValidations.cs | 5 ----- src/UnitTests/Dictionaries.cs | 8 -------- src/UnitTests/EnumToNullableEnum.cs | 5 +---- src/UnitTests/Enumerations.cs | 3 --- src/UnitTests/ExplicitMapperCreation.cs | 4 +--- src/UnitTests/ExpressionBridge.cs | 8 -------- src/UnitTests/ExtensionMethods.cs | 7 ------- src/UnitTests/FillingExistingDestination.cs | 5 ----- src/UnitTests/ForAllMaps.cs | 6 +----- src/UnitTests/ForAllMembers.cs | 8 +------- src/UnitTests/ForPath.cs | 9 +-------- src/UnitTests/General.cs | 6 ------ src/UnitTests/IMappingExpression/ForCtorParam.cs | 8 +------- .../IMappingExpression/IncludeMembers.cs | 11 +---------- .../NonGenericConstructorTests.cs | 8 -------- .../NonGenericProjectEnumTest.cs | 10 +--------- .../IMappingExpression/NonGenericResolveUsing.cs | 4 ---- .../NonGenericReverseMapping.cs | 7 ------- ...AllPropertiesWithAnInaccessibleSetterTests.cs | 4 +--- src/UnitTests/IgnoreAllTests.cs | 5 ----- src/UnitTests/Indexers.cs | 4 ---- src/UnitTests/InterfaceMapping.cs | 6 ------ src/UnitTests/Internal/CreateProxyThreading.cs | 6 +----- src/UnitTests/Internal/GenerateSimilarType.cs | 7 +------ src/UnitTests/Internal/MapperTests.cs | 3 --- src/UnitTests/Internal/ObjectFactoryTests.cs | 4 ---- .../Internal/PrimitiveExtensionsTester.cs | 6 ------ src/UnitTests/Internal/TypeMapFactorySpecs.cs | 8 -------- src/UnitTests/Internationalization.cs | 3 --- src/UnitTests/MapToAttributeTest.cs | 10 +--------- src/UnitTests/Mappers/ConstructorMapperTests.cs | 4 +--- src/UnitTests/Mappers/ConversionOperators.cs | 4 ---- src/UnitTests/Mappers/ConvertMapperTests.cs | 6 +----- src/UnitTests/Mappers/CustomMapperTests.cs | 9 +-------- src/UnitTests/Mappers/DynamicMapperTests.cs | 6 +----- .../Mappers/NameValueCollectionMapperTests.cs | 6 +----- .../Mappers/ReadOnlyCollectionMapperTests.cs | 10 +--------- .../Mappers/ReadOnlyDictionaryMapperTests.cs | 7 +------ .../Mappers/StringDictionaryMapperTests.cs | 9 +-------- src/UnitTests/Mappers/TypeHelperTests.cs | 7 ------- src/UnitTests/MappingExceptions.cs | 5 ----- .../MappingExpressionFeatureWithReverseTest.cs | 6 ------ ...MappingExpressionFeatureWithoutReverseTest.cs | 5 ----- .../ApplyIncludeBaseRecursively.cs | 7 +------ ...nventionMappedCollectionShouldMapBaseTypes.cs | 9 +-------- .../IgnoreShouldBeInherited.cs | 6 +----- ...noreShouldBeInheritedIfConventionCannotMap.cs | 8 +------- .../MappingInheritance/IncludeAllDerived.cs | 5 +---- .../MappingInheritance/IncludeBaseBug.cs | 4 ---- .../IncludeBaseShouldNotCreateMaps.cs | 5 +---- .../IncludeBaseShouldValidateTypes.cs | 6 +----- .../IncludeBaseWithNonGenericUsage.cs | 4 ---- ...cludedBaseMappingShouldInheritBaseMappings.cs | 9 +-------- .../IncludedMappingShouldInheritBaseMappings.cs | 7 +------ .../InheritanceWithoutIncludeShouldWork.cs | 4 ---- .../MappingInheritance/MapToBaseClass.cs | 4 ---- ...ltipleInheritedBaseMappingsOfSameTypeFails.cs | 4 +--- .../OpenGenericsWithInheritance.cs | 10 +--------- .../MappingInheritance/OverrideIgnore.cs | 5 +---- .../PreserveReferencesWithInheritance.cs | 6 +----- ...ertyOnMappingShouldResolveMostSpecificType.cs | 6 +----- .../MappingInheritance/ReverseMapWithInclude.cs | 5 ----- .../ShouldInheritBeforeAndAfterMap.cs | 7 +------ ...ouldSupportOnlyDestinationTypeBeingDerived.cs | 6 +----- .../SourceValidationWithInheritance.cs | 5 +---- src/UnitTests/MappingOrder.cs | 4 ---- src/UnitTests/MaxDepthTests.cs | 8 +------- src/UnitTests/MaxExecutionPlanDepth.cs | 9 +-------- src/UnitTests/MemberNameReplacers.cs | 8 +------- src/UnitTests/MemberResolution.cs | 4 ---- src/UnitTests/NestedContainers.cs | 4 ---- src/UnitTests/NullBehavior.cs | 8 -------- src/UnitTests/OpenGenerics.cs | 8 +------- src/UnitTests/Profiles.cs | 4 ---- src/UnitTests/Projection/ConstructorTests.cs | 8 +------- src/UnitTests/Projection/ExplicitExpansion.cs | 6 ------ .../ExplicitExpansionWithInheritance.cs | 10 +--------- src/UnitTests/Projection/ExplicitValues.cs | 7 ------- src/UnitTests/Projection/GenericsTests.cs | 6 ------ src/UnitTests/Projection/InheritedMaps.cs | 5 ----- src/UnitTests/Projection/MapFromTest.cs | 12 +----------- .../Projection/MoreExplanatoryExceptionTests.cs | 10 +--------- src/UnitTests/Projection/NestedAndArraysTests.cs | 6 ------ .../Projection/NestedExpressionsMapFromTests.cs | 6 ------ .../Projection/NonGenericQueryableTests.cs | 7 ------- src/UnitTests/Projection/NullSubstitutes.cs | 7 ------- .../Projection/ParameterizedQueriesTests.cs | 9 --------- src/UnitTests/Projection/PrimitiveArraysTest.cs | 12 +----------- .../ProjectCollectionEnumerableTest.cs | 11 +---------- .../Projection/ProjectCollectionListTest.cs | 14 +------------- src/UnitTests/Projection/ProjectEnumTest.cs | 10 +--------- .../Projection/ProjectEnumerableToArrayTest.cs | 12 +----------- .../Projection/ProjectIReadOnlyCollection.cs | 12 +----------- src/UnitTests/Projection/ProjectTest.cs | 13 +------------ src/UnitTests/Projection/ProjectionMappers.cs | 16 ++-------------- src/UnitTests/Projection/ProjectionTests.cs | 9 +-------- src/UnitTests/Projection/RecursiveQuery.cs | 11 +---------- src/UnitTests/Projection/ToStringTests.cs | 6 ------ src/UnitTests/Regression.cs | 8 -------- .../ReverseMapWithPreserveReferences.cs | 7 +------ .../ReverseMapWithoutPreserveReferences.cs | 7 +------ src/UnitTests/ReverseMapping.cs | 6 ------ src/UnitTests/SeparateConfiguration.cs | 5 ----- src/UnitTests/ShouldMapMethod.cs | 6 +----- src/UnitTests/ShouldUseConstructor.cs | 6 +----- src/UnitTests/TesterExtensions.cs | 4 ---- src/UnitTests/TypeConverters.cs | 8 ++------ src/UnitTests/TypeExtensionsTests.cs | 4 ---- src/UnitTests/UsingEngineInsideMap.cs | 4 ---- src/UnitTests/ValueConverters.cs | 6 +----- src/UnitTests/ValueTransformers.cs | 5 +---- src/UnitTests/ValueTypes.cs | 9 ++------- 482 files changed, 372 insertions(+), 2962 deletions(-) diff --git a/.editorconfig b/.editorconfig index 129050fb9c..74089b2787 100644 --- a/.editorconfig +++ b/.editorconfig @@ -68,7 +68,6 @@ dotnet_style_prefer_auto_properties = true:silent csharp_using_directive_placement = outside_namespace:silent csharp_prefer_simple_using_statement = true:suggestion csharp_prefer_braces = true:silent -csharp_style_namespace_declarations = block_scoped:silent csharp_style_prefer_method_group_conversion = true:silent csharp_style_prefer_top_level_statements = true:silent csharp_style_expression_bodied_methods = false:silent @@ -80,6 +79,7 @@ csharp_style_expression_bodied_accessors = true:silent csharp_style_expression_bodied_lambdas = true:silent csharp_style_expression_bodied_local_functions = false:silent dotnet_style_object_initializer = true:suggestion +csharp_style_namespace_declarations = file_scoped:suggestion dotnet_style_namespace_match_folder = true:silent dotnet_style_explicit_tuple_names = true:suggestion dotnet_style_prefer_inferred_tuple_names = true:suggestion diff --git a/Directory.Build.props b/Directory.Build.props index a585cc8acf..52fa6c08a1 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -6,6 +6,15 @@ $(NoWarn);CS1701;CS1702;CS1591 true strict + enable + + + + + + + + diff --git a/src/AutoMapper/AssemblyInfo.cs b/src/AutoMapper/AssemblyInfo.cs index 0f468a9a17..922c8e4e0c 100644 --- a/src/AutoMapper/AssemblyInfo.cs +++ b/src/AutoMapper/AssemblyInfo.cs @@ -1,5 +1,4 @@ -using System; -using System.Resources; +using System.Resources; using System.Runtime.InteropServices; [assembly: CLSCompliant(true)] diff --git a/src/AutoMapper/AutoMapper.csproj b/src/AutoMapper/AutoMapper.csproj index 97045c73a6..1172b2f71f 100644 --- a/src/AutoMapper/AutoMapper.csproj +++ b/src/AutoMapper/AutoMapper.csproj @@ -47,5 +47,10 @@ - - + + + + + + + \ No newline at end of file diff --git a/src/AutoMapper/AutoMapperMappingException.cs b/src/AutoMapper/AutoMapperMappingException.cs index 9a0b262310..55afd1ed74 100644 --- a/src/AutoMapper/AutoMapperMappingException.cs +++ b/src/AutoMapper/AutoMapperMappingException.cs @@ -1,7 +1,4 @@ -using System; using System.Text; -using System.Linq; -using AutoMapper.Internal; namespace AutoMapper; diff --git a/src/AutoMapper/Configuration/Annotations/AutoMapAttribute.cs b/src/AutoMapper/Configuration/Annotations/AutoMapAttribute.cs index 325a52789a..903867d05f 100644 --- a/src/AutoMapper/Configuration/Annotations/AutoMapAttribute.cs +++ b/src/AutoMapper/Configuration/Annotations/AutoMapAttribute.cs @@ -1,6 +1,4 @@ -using System; - -namespace AutoMapper; +namespace AutoMapper; /// /// Auto map to this destination type from the specified source type. diff --git a/src/AutoMapper/Configuration/Annotations/IgnoreAttribute.cs b/src/AutoMapper/Configuration/Annotations/IgnoreAttribute.cs index 79c8e78d99..cba7a708a2 100644 --- a/src/AutoMapper/Configuration/Annotations/IgnoreAttribute.cs +++ b/src/AutoMapper/Configuration/Annotations/IgnoreAttribute.cs @@ -1,6 +1,4 @@ -using System; - -namespace AutoMapper.Configuration.Annotations; +namespace AutoMapper.Configuration.Annotations; /// /// Ignore this member for configuration validation and skip during mapping. diff --git a/src/AutoMapper/Configuration/Annotations/MapAtRuntimeAttribute.cs b/src/AutoMapper/Configuration/Annotations/MapAtRuntimeAttribute.cs index 1bc23fe0fa..8f89a78983 100644 --- a/src/AutoMapper/Configuration/Annotations/MapAtRuntimeAttribute.cs +++ b/src/AutoMapper/Configuration/Annotations/MapAtRuntimeAttribute.cs @@ -1,6 +1,4 @@ -using System; - -namespace AutoMapper.Configuration.Annotations; +namespace AutoMapper.Configuration.Annotations; /// /// Do not precompute the execution plan for this member, just map it at runtime. diff --git a/src/AutoMapper/Configuration/Annotations/MappingOrderAttribute.cs b/src/AutoMapper/Configuration/Annotations/MappingOrderAttribute.cs index e80e6db64f..d028b1e906 100644 --- a/src/AutoMapper/Configuration/Annotations/MappingOrderAttribute.cs +++ b/src/AutoMapper/Configuration/Annotations/MappingOrderAttribute.cs @@ -1,6 +1,4 @@ -using System; - -namespace AutoMapper.Configuration.Annotations; +namespace AutoMapper.Configuration.Annotations; /// /// Supply a custom mapping order instead of what the .NET runtime returns diff --git a/src/AutoMapper/Configuration/Annotations/NullSubstituteAttribute.cs b/src/AutoMapper/Configuration/Annotations/NullSubstituteAttribute.cs index a6b69a46e1..9de69f389c 100644 --- a/src/AutoMapper/Configuration/Annotations/NullSubstituteAttribute.cs +++ b/src/AutoMapper/Configuration/Annotations/NullSubstituteAttribute.cs @@ -1,6 +1,4 @@ -using System; - -namespace AutoMapper.Configuration.Annotations; +namespace AutoMapper.Configuration.Annotations; /// /// Substitute a custom value when the source member resolves as null diff --git a/src/AutoMapper/Configuration/Annotations/SourceMemberAttribute.cs b/src/AutoMapper/Configuration/Annotations/SourceMemberAttribute.cs index 03d9ce31aa..a73ac3756a 100644 --- a/src/AutoMapper/Configuration/Annotations/SourceMemberAttribute.cs +++ b/src/AutoMapper/Configuration/Annotations/SourceMemberAttribute.cs @@ -1,8 +1,4 @@ -using AutoMapper.Internal; -using System; -using System.Reflection; - -namespace AutoMapper.Configuration.Annotations; +namespace AutoMapper.Configuration.Annotations; /// /// Specify the source member to map from. Can only reference a member on the type diff --git a/src/AutoMapper/Configuration/Annotations/UseExistingValueAttribute.cs b/src/AutoMapper/Configuration/Annotations/UseExistingValueAttribute.cs index b822bf5bf0..b6c93f7c60 100644 --- a/src/AutoMapper/Configuration/Annotations/UseExistingValueAttribute.cs +++ b/src/AutoMapper/Configuration/Annotations/UseExistingValueAttribute.cs @@ -1,6 +1,4 @@ -using System; - -namespace AutoMapper.Configuration.Annotations; +namespace AutoMapper.Configuration.Annotations; /// /// Use the destination value instead of mapping from the source value or creating a new instance diff --git a/src/AutoMapper/Configuration/Annotations/ValueConverterAttribute.cs b/src/AutoMapper/Configuration/Annotations/ValueConverterAttribute.cs index 2c02e92600..bf0a87e552 100644 --- a/src/AutoMapper/Configuration/Annotations/ValueConverterAttribute.cs +++ b/src/AutoMapper/Configuration/Annotations/ValueConverterAttribute.cs @@ -1,7 +1,4 @@ -using System; -using System.Reflection; - -namespace AutoMapper.Configuration.Annotations; +namespace AutoMapper.Configuration.Annotations; /// /// Specify a value converter type to convert from the matching source member to the destination member diff --git a/src/AutoMapper/Configuration/Annotations/ValueResolverAttribute.cs b/src/AutoMapper/Configuration/Annotations/ValueResolverAttribute.cs index 8748d6bed4..dea7196d35 100644 --- a/src/AutoMapper/Configuration/Annotations/ValueResolverAttribute.cs +++ b/src/AutoMapper/Configuration/Annotations/ValueResolverAttribute.cs @@ -1,7 +1,4 @@ -using System; -using System.Reflection; - -namespace AutoMapper.Configuration.Annotations; +namespace AutoMapper.Configuration.Annotations; /// /// Map destination member using a custom value resolver. diff --git a/src/AutoMapper/Configuration/ConfigurationValidator.cs b/src/AutoMapper/Configuration/ConfigurationValidator.cs index 5b399f5a3a..613b2fb395 100644 --- a/src/AutoMapper/Configuration/ConfigurationValidator.cs +++ b/src/AutoMapper/Configuration/ConfigurationValidator.cs @@ -1,8 +1,3 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; -using AutoMapper.Internal; using AutoMapper.Internal.Mappers; namespace AutoMapper.Configuration; diff --git a/src/AutoMapper/Configuration/Conventions.cs b/src/AutoMapper/Configuration/Conventions.cs index deb94dcfee..b24bb55f0c 100644 --- a/src/AutoMapper/Configuration/Conventions.cs +++ b/src/AutoMapper/Configuration/Conventions.cs @@ -1,9 +1,3 @@ -using AutoMapper.Internal; -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; -using System.Reflection; namespace AutoMapper.Configuration.Conventions; public interface ISourceToDestinationNameMapper diff --git a/src/AutoMapper/Configuration/CtorParamConfigurationExpression.cs b/src/AutoMapper/Configuration/CtorParamConfigurationExpression.cs index 4daca5bef6..cd56698835 100644 --- a/src/AutoMapper/Configuration/CtorParamConfigurationExpression.cs +++ b/src/AutoMapper/Configuration/CtorParamConfigurationExpression.cs @@ -1,11 +1,4 @@ -using AutoMapper.Execution; -using AutoMapper.Internal; -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq.Expressions; -using System.Reflection; -using System.Runtime.CompilerServices; +using System.Runtime.CompilerServices; namespace AutoMapper.Configuration; public interface ICtorParamConfigurationExpression diff --git a/src/AutoMapper/Configuration/IMappingExpression.cs b/src/AutoMapper/Configuration/IMappingExpression.cs index f5a17d3c98..c21663d6eb 100644 --- a/src/AutoMapper/Configuration/IMappingExpression.cs +++ b/src/AutoMapper/Configuration/IMappingExpression.cs @@ -1,9 +1,4 @@ -using AutoMapper.Configuration; -using System; -using System.Linq.Expressions; - namespace AutoMapper; - /// /// Mapping configuration options for non-generic maps /// diff --git a/src/AutoMapper/Configuration/IMappingExpressionBase.cs b/src/AutoMapper/Configuration/IMappingExpressionBase.cs index 8362126667..5be54f1a0d 100644 --- a/src/AutoMapper/Configuration/IMappingExpressionBase.cs +++ b/src/AutoMapper/Configuration/IMappingExpressionBase.cs @@ -1,7 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Linq.Expressions; -using AutoMapper.Configuration; using AutoMapper.Features; namespace AutoMapper; diff --git a/src/AutoMapper/Configuration/IMappingOperationOptions.cs b/src/AutoMapper/Configuration/IMappingOperationOptions.cs index 9371278b21..f78e85d587 100644 --- a/src/AutoMapper/Configuration/IMappingOperationOptions.cs +++ b/src/AutoMapper/Configuration/IMappingOperationOptions.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; - -namespace AutoMapper; +namespace AutoMapper; using StringDictionary = Dictionary; /// diff --git a/src/AutoMapper/Configuration/IMemberConfigurationExpression.cs b/src/AutoMapper/Configuration/IMemberConfigurationExpression.cs index 6a0951ec70..5d52a81442 100644 --- a/src/AutoMapper/Configuration/IMemberConfigurationExpression.cs +++ b/src/AutoMapper/Configuration/IMemberConfigurationExpression.cs @@ -1,7 +1,3 @@ -using System; -using System.Linq.Expressions; -using System.Reflection; - namespace AutoMapper; /// diff --git a/src/AutoMapper/Configuration/INamingConvention.cs b/src/AutoMapper/Configuration/INamingConvention.cs index c17894d7cd..4059b9a12a 100644 --- a/src/AutoMapper/Configuration/INamingConvention.cs +++ b/src/AutoMapper/Configuration/INamingConvention.cs @@ -1,5 +1,3 @@ -using System; -using System.Collections.Generic; namespace AutoMapper; /// diff --git a/src/AutoMapper/Configuration/IProfileExpression.cs b/src/AutoMapper/Configuration/IProfileExpression.cs index 185b967551..667abea871 100644 --- a/src/AutoMapper/Configuration/IProfileExpression.cs +++ b/src/AutoMapper/Configuration/IProfileExpression.cs @@ -1,6 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Reflection; namespace AutoMapper; /// diff --git a/src/AutoMapper/Configuration/MapperConfiguration.cs b/src/AutoMapper/Configuration/MapperConfiguration.cs index 5b7128a90c..6e8aaf444c 100644 --- a/src/AutoMapper/Configuration/MapperConfiguration.cs +++ b/src/AutoMapper/Configuration/MapperConfiguration.cs @@ -1,17 +1,7 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; namespace AutoMapper; -using Configuration; -using Execution; using Features; -using Internal; using Internal.Mappers; using QueryableExtensions.Impl; -using static Expression; -using static Execution.ExpressionBuilder; public interface IConfigurationProvider { /// diff --git a/src/AutoMapper/Configuration/MapperConfigurationExpression.cs b/src/AutoMapper/Configuration/MapperConfigurationExpression.cs index fbc076f1c6..010053059b 100644 --- a/src/AutoMapper/Configuration/MapperConfigurationExpression.cs +++ b/src/AutoMapper/Configuration/MapperConfigurationExpression.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using AutoMapper.Configuration; using AutoMapper.Features; -using AutoMapper.Internal; using AutoMapper.Internal.Mappers; using AutoMapper.QueryableExtensions.Impl; namespace AutoMapper; diff --git a/src/AutoMapper/Configuration/MappingExpression.cs b/src/AutoMapper/Configuration/MappingExpression.cs index 1ba9a1634d..4728c67da6 100644 --- a/src/AutoMapper/Configuration/MappingExpression.cs +++ b/src/AutoMapper/Configuration/MappingExpression.cs @@ -1,11 +1,4 @@ -using System; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; -using AutoMapper.Internal; namespace AutoMapper.Configuration; - -using Execution; public class MappingExpression : MappingExpressionBase, IMappingExpression { public MappingExpression(TypePair types, MemberList memberList) : base(memberList, types){} diff --git a/src/AutoMapper/Configuration/MemberConfigurationExpression.cs b/src/AutoMapper/Configuration/MemberConfigurationExpression.cs index ef892baa62..ec42a88b97 100644 --- a/src/AutoMapper/Configuration/MemberConfigurationExpression.cs +++ b/src/AutoMapper/Configuration/MemberConfigurationExpression.cs @@ -1,13 +1,4 @@ -using AutoMapper.Internal; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; namespace AutoMapper.Configuration; - -using Execution; -using static AutoMapper.Execution.ExpressionBuilder; public interface IPropertyMapConfiguration { void Configure(TypeMap typeMap); diff --git a/src/AutoMapper/Configuration/PathConfigurationExpression.cs b/src/AutoMapper/Configuration/PathConfigurationExpression.cs index d55d8a1af5..ecd2e46783 100644 --- a/src/AutoMapper/Configuration/PathConfigurationExpression.cs +++ b/src/AutoMapper/Configuration/PathConfigurationExpression.cs @@ -1,11 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq.Expressions; -using System.Reflection; -using AutoMapper.Internal; -namespace AutoMapper.Configuration; - -using Execution; +namespace AutoMapper.Configuration; /// /// Member configuration options /// diff --git a/src/AutoMapper/Configuration/Profile.cs b/src/AutoMapper/Configuration/Profile.cs index d17db3c9b0..adf0a32f00 100644 --- a/src/AutoMapper/Configuration/Profile.cs +++ b/src/AutoMapper/Configuration/Profile.cs @@ -1,14 +1,6 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; using System.Runtime.CompilerServices; -using AutoMapper.Configuration; using AutoMapper.Configuration.Conventions; -using AutoMapper.Internal; namespace AutoMapper; - -using static Execution.ExpressionBuilder; public interface IProfileConfiguration { bool? FieldMappingEnabled { get; } diff --git a/src/AutoMapper/Configuration/SourceMappingExpression.cs b/src/AutoMapper/Configuration/SourceMappingExpression.cs index 0253840f39..80d63ed664 100644 --- a/src/AutoMapper/Configuration/SourceMappingExpression.cs +++ b/src/AutoMapper/Configuration/SourceMappingExpression.cs @@ -1,7 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Reflection; - namespace AutoMapper.Configuration; public interface ISourceMemberConfiguration diff --git a/src/AutoMapper/Configuration/TypeMapConfiguration.cs b/src/AutoMapper/Configuration/TypeMapConfiguration.cs index 99cc6c4ae3..fca220cfac 100644 --- a/src/AutoMapper/Configuration/TypeMapConfiguration.cs +++ b/src/AutoMapper/Configuration/TypeMapConfiguration.cs @@ -1,15 +1,5 @@ -using System; -using System.ComponentModel; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; using AutoMapper.Features; -using AutoMapper.Internal; namespace AutoMapper.Configuration; - -using static Expression; -using Execution; [EditorBrowsable(EditorBrowsableState.Never)] public abstract class TypeMapConfiguration { @@ -346,7 +336,7 @@ public void ConvertUsing(Type typeConverterType) } public void ConvertUsing(Func mappingFunction) => ConvertUsingCore((src, dest, ctxt) => mappingFunction(src, dest)); private void ConvertUsingCore(Expression> expr) => SetTypeConverter(new LambdaTypeConverter(expr)); - private void SetTypeConverter(TypeConverter typeConverter) + private void SetTypeConverter(Execution.TypeConverter typeConverter) { HasTypeConverter = true; TypeMapActions.Add(tm => tm.TypeConverter = typeConverter); diff --git a/src/AutoMapper/ConstructorMap.cs b/src/AutoMapper/ConstructorMap.cs index bb0928377b..619cfa6a5d 100644 --- a/src/AutoMapper/ConstructorMap.cs +++ b/src/AutoMapper/ConstructorMap.cs @@ -1,13 +1,4 @@ -using AutoMapper.Internal; -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; -namespace AutoMapper; - -using Execution; +namespace AutoMapper; [EditorBrowsable(EditorBrowsableState.Never)] public class ConstructorMap { diff --git a/src/AutoMapper/Execution/ExpressionBuilder.cs b/src/AutoMapper/Execution/ExpressionBuilder.cs index aee4e7f484..60826491fd 100644 --- a/src/AutoMapper/Execution/ExpressionBuilder.cs +++ b/src/AutoMapper/Execution/ExpressionBuilder.cs @@ -1,16 +1,7 @@ -using System; using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; -using System.ComponentModel; using System.Runtime.CompilerServices; using System.Collections.ObjectModel; namespace AutoMapper.Execution; - -using Internal; -using static Expression; using static Internal.ReflectionHelper; [EditorBrowsable(EditorBrowsableState.Never)] public static class ExpressionBuilder diff --git a/src/AutoMapper/Execution/ObjectFactory.cs b/src/AutoMapper/Execution/ObjectFactory.cs index b9a0f71ac8..a43dbbe9d4 100644 --- a/src/AutoMapper/Execution/ObjectFactory.cs +++ b/src/AutoMapper/Execution/ObjectFactory.cs @@ -1,14 +1,5 @@ -using System; -using System.Collections.Generic; using System.Collections.ObjectModel; -using System.ComponentModel; -using System.Linq; -using System.Linq.Expressions; -using AutoMapper.Internal; namespace AutoMapper.Execution; - -using static Expression; -using static ExpressionBuilder; [EditorBrowsable(EditorBrowsableState.Never)] public static class ObjectFactory { diff --git a/src/AutoMapper/Execution/ProxyGenerator.cs b/src/AutoMapper/Execution/ProxyGenerator.cs index df72e38203..9b793db086 100644 --- a/src/AutoMapper/Execution/ProxyGenerator.cs +++ b/src/AutoMapper/Execution/ProxyGenerator.cs @@ -1,10 +1,3 @@ -using AutoMapper.Internal; -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Diagnostics; -using System.Linq; -using System.Reflection; using System.Reflection.Emit; namespace AutoMapper.Execution; diff --git a/src/AutoMapper/Execution/TypeMapPlanBuilder.cs b/src/AutoMapper/Execution/TypeMapPlanBuilder.cs index a48ebedf80..1c1235fecc 100644 --- a/src/AutoMapper/Execution/TypeMapPlanBuilder.cs +++ b/src/AutoMapper/Execution/TypeMapPlanBuilder.cs @@ -1,15 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using System.Diagnostics; -using System.Reflection; namespace AutoMapper.Execution; - -using static Expression; -using static ExpressionBuilder; -using Internal; -using Configuration; public struct TypeMapPlanBuilder { private static readonly MethodInfo MappingError = typeof(TypeMapPlanBuilder).GetStaticMethod(nameof(MemberMappingError)); diff --git a/src/AutoMapper/Features.cs b/src/AutoMapper/Features.cs index 8e00dc655b..a154ff0dd1 100644 --- a/src/AutoMapper/Features.cs +++ b/src/AutoMapper/Features.cs @@ -1,10 +1,5 @@ -using AutoMapper.Internal; -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; +using System.Collections; namespace AutoMapper.Features; - public interface IGlobalFeature { void Configure(IGlobalConfiguration configuration); diff --git a/src/AutoMapper/Internal/InternalApi.cs b/src/AutoMapper/Internal/InternalApi.cs index ec1600110e..5be71f4b05 100644 --- a/src/AutoMapper/Internal/InternalApi.cs +++ b/src/AutoMapper/Internal/InternalApi.cs @@ -1,11 +1,4 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq.Expressions; -using System.Reflection; -using AutoMapper.Configuration; -using AutoMapper.Configuration.Conventions; -using AutoMapper.Execution; +using AutoMapper.Configuration.Conventions; using AutoMapper.Features; using AutoMapper.Internal.Mappers; using AutoMapper.QueryableExtensions.Impl; diff --git a/src/AutoMapper/Internal/LockingConcurrentDictionary.cs b/src/AutoMapper/Internal/LockingConcurrentDictionary.cs index 65e7b3abc3..e38b5a0f0c 100644 --- a/src/AutoMapper/Internal/LockingConcurrentDictionary.cs +++ b/src/AutoMapper/Internal/LockingConcurrentDictionary.cs @@ -1,4 +1,3 @@ -using System; using System.Collections.Concurrent; namespace AutoMapper.Internal; diff --git a/src/AutoMapper/Internal/MemberPath.cs b/src/AutoMapper/Internal/MemberPath.cs index 07c1499680..5c87b3c43c 100644 --- a/src/AutoMapper/Internal/MemberPath.cs +++ b/src/AutoMapper/Internal/MemberPath.cs @@ -1,11 +1,4 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; -using System.Reflection; -namespace AutoMapper.Internal; - -using Execution; +namespace AutoMapper.Internal; [EditorBrowsable(EditorBrowsableState.Never)] public readonly record struct MemberPath(MemberInfo[] Members) { diff --git a/src/AutoMapper/Internal/PrimitiveHelper.cs b/src/AutoMapper/Internal/PrimitiveHelper.cs index b2f8f1185d..a524173f0b 100644 --- a/src/AutoMapper/Internal/PrimitiveHelper.cs +++ b/src/AutoMapper/Internal/PrimitiveHelper.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.ComponentModel; -using System.Linq; -using System.Linq.Expressions; +using System.Collections.ObjectModel; using System.Runtime.CompilerServices; namespace AutoMapper.Internal; diff --git a/src/AutoMapper/Internal/ReflectionHelper.cs b/src/AutoMapper/Internal/ReflectionHelper.cs index bedb9cd821..e2e81d9dd1 100644 --- a/src/AutoMapper/Internal/ReflectionHelper.cs +++ b/src/AutoMapper/Internal/ReflectionHelper.cs @@ -1,11 +1,4 @@ -using System; -using System.ComponentModel; -using System.Linq.Expressions; -using System.Reflection; namespace AutoMapper.Internal; - -using static Expression; -using static Execution.ExpressionBuilder; [EditorBrowsable(EditorBrowsableState.Never)] public static class ReflectionHelper { diff --git a/src/AutoMapper/Internal/TypeDetails.cs b/src/AutoMapper/Internal/TypeDetails.cs index 5be436b0c7..309f6d33a9 100644 --- a/src/AutoMapper/Internal/TypeDetails.cs +++ b/src/AutoMapper/Internal/TypeDetails.cs @@ -1,10 +1,3 @@ -using AutoMapper.Execution; -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Diagnostics; -using System.Linq; -using System.Reflection; namespace AutoMapper.Internal; /// diff --git a/src/AutoMapper/Internal/TypeExtensions.cs b/src/AutoMapper/Internal/TypeExtensions.cs index d919027b0d..6d4ea7705a 100644 --- a/src/AutoMapper/Internal/TypeExtensions.cs +++ b/src/AutoMapper/Internal/TypeExtensions.cs @@ -1,9 +1,5 @@ -using System; using System.Collections; -using System.Collections.Generic; using System.Dynamic; -using System.Linq; -using System.Reflection; namespace AutoMapper.Internal; public static class TypeExtensions diff --git a/src/AutoMapper/Internal/TypePair.cs b/src/AutoMapper/Internal/TypePair.cs index 27a3f10789..039ebb78a5 100644 --- a/src/AutoMapper/Internal/TypePair.cs +++ b/src/AutoMapper/Internal/TypePair.cs @@ -1,5 +1,3 @@ -using System; -using System.Diagnostics; namespace AutoMapper.Internal; [DebuggerDisplay("{RequestedTypes.SourceType.Name}, {RequestedTypes.DestinationType.Name} : {RuntimeTypes.SourceType.Name}, {RuntimeTypes.DestinationType.Name}")] diff --git a/src/AutoMapper/Mapper.cs b/src/AutoMapper/Mapper.cs index 9c043c2f14..960f4f78f5 100644 --- a/src/AutoMapper/Mapper.cs +++ b/src/AutoMapper/Mapper.cs @@ -1,13 +1,7 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; namespace AutoMapper; -using QueryableExtensions; using IObjectMappingOperationOptions = IMappingOperationOptions; using Factory = Func; -using Internal; public interface IMapperBase { /// diff --git a/src/AutoMapper/Mappers/AssignableMapper.cs b/src/AutoMapper/Mappers/AssignableMapper.cs index d47d58b1ba..855a832cf0 100644 --- a/src/AutoMapper/Mappers/AssignableMapper.cs +++ b/src/AutoMapper/Mappers/AssignableMapper.cs @@ -1,4 +1,3 @@ -using System.Linq.Expressions; namespace AutoMapper.Internal.Mappers; public class AssignableMapper : IObjectMapper diff --git a/src/AutoMapper/Mappers/CollectionMapper.cs b/src/AutoMapper/Mappers/CollectionMapper.cs index 029c56f089..368a14452f 100644 --- a/src/AutoMapper/Mappers/CollectionMapper.cs +++ b/src/AutoMapper/Mappers/CollectionMapper.cs @@ -1,16 +1,7 @@ -using System; using System.Collections; -using System.Collections.Generic; using System.Collections.ObjectModel; -using System.Linq.Expressions; -using System.Reflection; using System.Collections.Specialized; -using System.Linq; namespace AutoMapper.Internal.Mappers; - -using Execution; -using static Execution.ExpressionBuilder; -using static Expression; using static ReflectionHelper; public class CollectionMapper : IObjectMapper { diff --git a/src/AutoMapper/Mappers/ConstructorMapper.cs b/src/AutoMapper/Mappers/ConstructorMapper.cs index e913226132..96dda2e20f 100644 --- a/src/AutoMapper/Mappers/ConstructorMapper.cs +++ b/src/AutoMapper/Mappers/ConstructorMapper.cs @@ -1,9 +1,4 @@ -using System; -using System.Linq.Expressions; -using System.Reflection; -namespace AutoMapper.Internal.Mappers; - -using static Execution.ExpressionBuilder; +namespace AutoMapper.Internal.Mappers; public class ConstructorMapper : IObjectMapper { public bool IsMatch(TypePair context) => GetConstructor(context.SourceType, context.DestinationType) != null; diff --git a/src/AutoMapper/Mappers/ConversionOperatorMapper.cs b/src/AutoMapper/Mappers/ConversionOperatorMapper.cs index 87ca3036cc..a13496e1d7 100644 --- a/src/AutoMapper/Mappers/ConversionOperatorMapper.cs +++ b/src/AutoMapper/Mappers/ConversionOperatorMapper.cs @@ -1,9 +1,4 @@ -using System; -using System.Linq.Expressions; -using System.Reflection; namespace AutoMapper.Internal.Mappers; - -using static Execution.ExpressionBuilder; public class ConversionOperatorMapper : IObjectMapper { private readonly string _operatorName; diff --git a/src/AutoMapper/Mappers/ConvertMapper.cs b/src/AutoMapper/Mappers/ConvertMapper.cs index ccbf1e9379..1c3536e0d2 100644 --- a/src/AutoMapper/Mappers/ConvertMapper.cs +++ b/src/AutoMapper/Mappers/ConvertMapper.cs @@ -1,8 +1,4 @@ -using System; -using System.Linq.Expressions; -namespace AutoMapper.Internal.Mappers; - -using static Expression; +namespace AutoMapper.Internal.Mappers; public class ConvertMapper : IObjectMapper { public static bool IsPrimitive(Type type) => type.IsPrimitive || type == typeof(string) || type == typeof(decimal); diff --git a/src/AutoMapper/Mappers/EnumToEnumMapper.cs b/src/AutoMapper/Mappers/EnumToEnumMapper.cs index a23acae838..9eba8acac9 100644 --- a/src/AutoMapper/Mappers/EnumToEnumMapper.cs +++ b/src/AutoMapper/Mappers/EnumToEnumMapper.cs @@ -1,10 +1,4 @@ -using System; -using System.Linq.Expressions; -using System.Reflection; namespace AutoMapper.Internal.Mappers; - -using static Expression; -using static Execution.ExpressionBuilder; public class EnumToEnumMapper : IObjectMapper { private static readonly MethodInfo TryParseMethod = typeof(Enum).StaticGenericMethod("TryParse", parametersCount: 3); diff --git a/src/AutoMapper/Mappers/FromDynamicMapper.cs b/src/AutoMapper/Mappers/FromDynamicMapper.cs index 706a167060..b4056bb6ce 100644 --- a/src/AutoMapper/Mappers/FromDynamicMapper.cs +++ b/src/AutoMapper/Mappers/FromDynamicMapper.cs @@ -1,14 +1,7 @@ -using System; -using System.Linq.Expressions; -using System.Reflection; using System.Runtime.CompilerServices; -using AutoMapper.Execution; using Microsoft.CSharp.RuntimeBinder; using Binder = Microsoft.CSharp.RuntimeBinder.Binder; namespace AutoMapper.Internal.Mappers; - -using static Expression; -using static ExpressionBuilder; public class FromDynamicMapper : IObjectMapper { private static readonly MethodInfo MapMethodInfo = typeof(FromDynamicMapper).GetStaticMethod(nameof(Map)); diff --git a/src/AutoMapper/Mappers/FromStringDictionaryMapper.cs b/src/AutoMapper/Mappers/FromStringDictionaryMapper.cs index 03ee47b68e..333d652de0 100644 --- a/src/AutoMapper/Mappers/FromStringDictionaryMapper.cs +++ b/src/AutoMapper/Mappers/FromStringDictionaryMapper.cs @@ -1,13 +1,5 @@ -using System; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; -using AutoMapper.Execution; -using StringDictionary = System.Collections.Generic.IDictionary; +using StringDictionary = System.Collections.Generic.IDictionary; namespace AutoMapper.Internal.Mappers; - -using static Expression; -using static ExpressionBuilder; public class FromStringDictionaryMapper : IObjectMapper { private static readonly MethodInfo MapDynamicMethod = typeof(FromStringDictionaryMapper).GetStaticMethod(nameof(MapDynamic)); diff --git a/src/AutoMapper/Mappers/IObjectMapper.cs b/src/AutoMapper/Mappers/IObjectMapper.cs index 4fbad3cf55..93a241a7ba 100644 --- a/src/AutoMapper/Mappers/IObjectMapper.cs +++ b/src/AutoMapper/Mappers/IObjectMapper.cs @@ -1,10 +1,4 @@ -using System; -using System.Linq.Expressions; -using System.Reflection; namespace AutoMapper.Internal.Mappers; - -using static Expression; -using static Execution.ExpressionBuilder; /// /// Mapping execution strategy, as a chain of responsibility /// diff --git a/src/AutoMapper/Mappers/KeyValueMapper.cs b/src/AutoMapper/Mappers/KeyValueMapper.cs index e7c2379e4c..dd77be0dfb 100644 --- a/src/AutoMapper/Mappers/KeyValueMapper.cs +++ b/src/AutoMapper/Mappers/KeyValueMapper.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq.Expressions; -namespace AutoMapper.Internal.Mappers; - -using Execution; +namespace AutoMapper.Internal.Mappers; public class KeyValueMapper : IObjectMapper { public bool IsMatch(TypePair context) => IsKeyValue(context.SourceType) && IsKeyValue(context.DestinationType); diff --git a/src/AutoMapper/Mappers/MapperRegistry.cs b/src/AutoMapper/Mappers/MapperRegistry.cs index c2637b65e3..876dffd3a7 100644 --- a/src/AutoMapper/Mappers/MapperRegistry.cs +++ b/src/AutoMapper/Mappers/MapperRegistry.cs @@ -1,4 +1,3 @@ -using System.Collections.Generic; namespace AutoMapper.Internal.Mappers; internal static class MapperRegistry diff --git a/src/AutoMapper/Mappers/NullableDestinationMapper.cs b/src/AutoMapper/Mappers/NullableDestinationMapper.cs index fd019ce7bc..04ffbf2cda 100644 --- a/src/AutoMapper/Mappers/NullableDestinationMapper.cs +++ b/src/AutoMapper/Mappers/NullableDestinationMapper.cs @@ -1,6 +1,3 @@ -using System; -using System.Linq.Expressions; -using AutoMapper.Execution; namespace AutoMapper.Internal.Mappers; public class NullableDestinationMapper : IObjectMapper diff --git a/src/AutoMapper/Mappers/NullableSourceMapper.cs b/src/AutoMapper/Mappers/NullableSourceMapper.cs index 469373534f..7f574b7621 100644 --- a/src/AutoMapper/Mappers/NullableSourceMapper.cs +++ b/src/AutoMapper/Mappers/NullableSourceMapper.cs @@ -1,6 +1,3 @@ -using System; -using System.Linq.Expressions; -using AutoMapper.Execution; namespace AutoMapper.Internal.Mappers; public class NullableSourceMapper : IObjectMapper diff --git a/src/AutoMapper/Mappers/ParseStringMapper.cs b/src/AutoMapper/Mappers/ParseStringMapper.cs index de4bcef80d..8a0aac0f2a 100644 --- a/src/AutoMapper/Mappers/ParseStringMapper.cs +++ b/src/AutoMapper/Mappers/ParseStringMapper.cs @@ -1,6 +1,4 @@ -using System; -using System.Linq.Expressions; -namespace AutoMapper.Internal.Mappers; +namespace AutoMapper.Internal.Mappers; public class ParseStringMapper : IObjectMapper { diff --git a/src/AutoMapper/Mappers/StringToEnumMapper.cs b/src/AutoMapper/Mappers/StringToEnumMapper.cs index 1ef176718c..4b13286e56 100644 --- a/src/AutoMapper/Mappers/StringToEnumMapper.cs +++ b/src/AutoMapper/Mappers/StringToEnumMapper.cs @@ -1,12 +1,5 @@ -using System; -using System.Collections.Generic; -using System.Linq.Expressions; -using System.Reflection; using System.Runtime.Serialization; namespace AutoMapper.Internal.Mappers; - -using static Execution.ExpressionBuilder; -using static Expression; public class StringToEnumMapper : IObjectMapper { private static readonly MethodInfo EqualsMethod = typeof(StringToEnumMapper).GetMethod(nameof(StringCompareOrdinalIgnoreCase)); diff --git a/src/AutoMapper/Mappers/ToDynamicMapper.cs b/src/AutoMapper/Mappers/ToDynamicMapper.cs index 7cad4dec81..4fdae9eeba 100644 --- a/src/AutoMapper/Mappers/ToDynamicMapper.cs +++ b/src/AutoMapper/Mappers/ToDynamicMapper.cs @@ -1,14 +1,7 @@ -using System; -using System.Linq.Expressions; -using System.Reflection; using System.Runtime.CompilerServices; -using AutoMapper.Execution; using Microsoft.CSharp.RuntimeBinder; using Binder = Microsoft.CSharp.RuntimeBinder.Binder; namespace AutoMapper.Internal.Mappers; - -using static Expression; -using static ExpressionBuilder; public class ToDynamicMapper : IObjectMapper { private static readonly MethodInfo MapMethodInfo = typeof(ToDynamicMapper).GetStaticMethod(nameof(Map)); diff --git a/src/AutoMapper/Mappers/ToStringDictionaryMapper.cs b/src/AutoMapper/Mappers/ToStringDictionaryMapper.cs index 2ba980dc4f..21d4400f3f 100644 --- a/src/AutoMapper/Mappers/ToStringDictionaryMapper.cs +++ b/src/AutoMapper/Mappers/ToStringDictionaryMapper.cs @@ -1,11 +1,4 @@ -using AutoMapper.Execution; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; -namespace AutoMapper.Internal.Mappers; - -using static Expression; +namespace AutoMapper.Internal.Mappers; public class ToStringDictionaryMapper : IObjectMapper { private static readonly MethodInfo MembersDictionaryMethodInfo = typeof(ToStringDictionaryMapper).GetStaticMethod(nameof(MembersDictionary)); diff --git a/src/AutoMapper/Mappers/ToStringMapper.cs b/src/AutoMapper/Mappers/ToStringMapper.cs index 1fe28e4750..97a8767c34 100644 --- a/src/AutoMapper/Mappers/ToStringMapper.cs +++ b/src/AutoMapper/Mappers/ToStringMapper.cs @@ -1,8 +1,4 @@ -using AutoMapper.Execution; -using System.Linq.Expressions; -namespace AutoMapper.Internal.Mappers; - -using static Expression; +namespace AutoMapper.Internal.Mappers; public class ToStringMapper : IObjectMapper { public bool IsMatch(TypePair context) => context.DestinationType == typeof(string); diff --git a/src/AutoMapper/Mappers/UnderlyingEnumTypeMapper.cs b/src/AutoMapper/Mappers/UnderlyingEnumTypeMapper.cs index e2981f3eab..388abc8571 100644 --- a/src/AutoMapper/Mappers/UnderlyingEnumTypeMapper.cs +++ b/src/AutoMapper/Mappers/UnderlyingEnumTypeMapper.cs @@ -1,4 +1,3 @@ -using System.Linq.Expressions; namespace AutoMapper.Internal.Mappers; public class UnderlyingTypeEnumMapper : IObjectMapper diff --git a/src/AutoMapper/MemberMap.cs b/src/AutoMapper/MemberMap.cs index 09bc37690f..040f6a5b9c 100644 --- a/src/AutoMapper/MemberMap.cs +++ b/src/AutoMapper/MemberMap.cs @@ -1,15 +1,4 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq.Expressions; -using System.Reflection; namespace AutoMapper; - -using static Expression; -using Execution; -using Internal; -using System.Diagnostics; - /// /// The base class for member maps (property, constructor and path maps). /// diff --git a/src/AutoMapper/PathMap.cs b/src/AutoMapper/PathMap.cs index 67eaf9d5b9..7c9d29ecae 100644 --- a/src/AutoMapper/PathMap.cs +++ b/src/AutoMapper/PathMap.cs @@ -1,12 +1,4 @@ -using System; -using System.Diagnostics; -using System.Linq.Expressions; - -namespace AutoMapper; - -using Internal; -using System.ComponentModel; - +namespace AutoMapper; [DebuggerDisplay("{DestinationExpression}")] [EditorBrowsable(EditorBrowsableState.Never)] public class PathMap : MemberMap diff --git a/src/AutoMapper/ProfileMap.cs b/src/AutoMapper/ProfileMap.cs index 38c06009fc..bfe1ddb398 100644 --- a/src/AutoMapper/ProfileMap.cs +++ b/src/AutoMapper/ProfileMap.cs @@ -1,18 +1,5 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Diagnostics; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; -using AutoMapper.Configuration; using AutoMapper.Configuration.Conventions; -using AutoMapper.Execution; -using AutoMapper.Internal; - namespace AutoMapper; - -using static Expression; [DebuggerDisplay("{Name}")] [EditorBrowsable(EditorBrowsableState.Never)] public class ProfileMap diff --git a/src/AutoMapper/PropertyMap.cs b/src/AutoMapper/PropertyMap.cs index e65e5ad9d3..0e6ac2bbf2 100644 --- a/src/AutoMapper/PropertyMap.cs +++ b/src/AutoMapper/PropertyMap.cs @@ -1,10 +1,3 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Diagnostics; -using System.Linq.Expressions; -using System.Reflection; -using AutoMapper.Internal; namespace AutoMapper; [DebuggerDisplay("{DestinationMember.Name}")] diff --git a/src/AutoMapper/QueryableExtensions/Extensions.cs b/src/AutoMapper/QueryableExtensions/Extensions.cs index 94488e7aee..41d55ad326 100644 --- a/src/AutoMapper/QueryableExtensions/Extensions.cs +++ b/src/AutoMapper/QueryableExtensions/Extensions.cs @@ -1,10 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; -using AutoMapper.Execution; -using AutoMapper.Internal; namespace AutoMapper.QueryableExtensions; using MemberPaths = IEnumerable; diff --git a/src/AutoMapper/QueryableExtensions/NullsafeQueryRewriter.cs b/src/AutoMapper/QueryableExtensions/NullsafeQueryRewriter.cs index f86d314c40..556584fe26 100644 --- a/src/AutoMapper/QueryableExtensions/NullsafeQueryRewriter.cs +++ b/src/AutoMapper/QueryableExtensions/NullsafeQueryRewriter.cs @@ -21,11 +21,6 @@ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -using AutoMapper.Internal; -using System; -using System.Collections.Generic; -using System.Linq.Expressions; -using System.Reflection; using System.Runtime.CompilerServices; namespace AutoMapper.QueryableExtensions; diff --git a/src/AutoMapper/QueryableExtensions/ProjectionBuilder.cs b/src/AutoMapper/QueryableExtensions/ProjectionBuilder.cs index d593fe054f..6730889cf4 100644 --- a/src/AutoMapper/QueryableExtensions/ProjectionBuilder.cs +++ b/src/AutoMapper/QueryableExtensions/ProjectionBuilder.cs @@ -1,17 +1,5 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Diagnostics; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; -using System.Runtime.CompilerServices; -using AutoMapper.Execution; -using AutoMapper.Internal; +using System.Runtime.CompilerServices; namespace AutoMapper.QueryableExtensions.Impl; - -using static Expression; -using static ExpressionBuilder; using ParameterBag = IDictionary; using TypePairCount = Dictionary; [EditorBrowsable(EditorBrowsableState.Never)] diff --git a/src/AutoMapper/QueryableExtensions/ProjectionMappers/AssignableProjectionMapper.cs b/src/AutoMapper/QueryableExtensions/ProjectionMappers/AssignableProjectionMapper.cs index 9193e1b0d9..b95f8ba903 100644 --- a/src/AutoMapper/QueryableExtensions/ProjectionMappers/AssignableProjectionMapper.cs +++ b/src/AutoMapper/QueryableExtensions/ProjectionMappers/AssignableProjectionMapper.cs @@ -1,8 +1,3 @@ -using AutoMapper.Execution; -using AutoMapper.Internal; -using System.ComponentModel; -using System.Linq.Expressions; - namespace AutoMapper.QueryableExtensions.Impl; [EditorBrowsable(EditorBrowsableState.Never)] diff --git a/src/AutoMapper/QueryableExtensions/ProjectionMappers/EnumProjectionMapper.cs b/src/AutoMapper/QueryableExtensions/ProjectionMappers/EnumProjectionMapper.cs index a472b0523b..f2524549d7 100644 --- a/src/AutoMapper/QueryableExtensions/ProjectionMappers/EnumProjectionMapper.cs +++ b/src/AutoMapper/QueryableExtensions/ProjectionMappers/EnumProjectionMapper.cs @@ -1,10 +1,4 @@ -using AutoMapper.Internal; -using System.ComponentModel; -using System.Linq.Expressions; - -namespace AutoMapper.QueryableExtensions.Impl; - -using static Expression; +namespace AutoMapper.QueryableExtensions.Impl; [EditorBrowsable(EditorBrowsableState.Never)] public class EnumProjectionMapper : IProjectionMapper { diff --git a/src/AutoMapper/QueryableExtensions/ProjectionMappers/EnumerableProjectionMapper.cs b/src/AutoMapper/QueryableExtensions/ProjectionMappers/EnumerableProjectionMapper.cs index b341d02de1..16b9a3ed6e 100644 --- a/src/AutoMapper/QueryableExtensions/ProjectionMappers/EnumerableProjectionMapper.cs +++ b/src/AutoMapper/QueryableExtensions/ProjectionMappers/EnumerableProjectionMapper.cs @@ -1,14 +1,4 @@ -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; -using AutoMapper.Internal; - namespace AutoMapper.QueryableExtensions.Impl; - -using static Expression; -using static Execution.ExpressionBuilder; using static ReflectionHelper; [EditorBrowsable(EditorBrowsableState.Never)] public class EnumerableProjectionMapper : IProjectionMapper diff --git a/src/AutoMapper/QueryableExtensions/ProjectionMappers/NullableSourceProjectionMapper.cs b/src/AutoMapper/QueryableExtensions/ProjectionMappers/NullableSourceProjectionMapper.cs index 0c0030d423..f3b7f77e66 100644 --- a/src/AutoMapper/QueryableExtensions/ProjectionMappers/NullableSourceProjectionMapper.cs +++ b/src/AutoMapper/QueryableExtensions/ProjectionMappers/NullableSourceProjectionMapper.cs @@ -1,8 +1,4 @@ -using System.Linq.Expressions; -using AutoMapper.Internal; -namespace AutoMapper.QueryableExtensions.Impl; - -using static Expression; +namespace AutoMapper.QueryableExtensions.Impl; internal class NullableSourceProjectionMapper : IProjectionMapper { public Expression Project(IGlobalConfiguration configuration, in ProjectionRequest request, Expression resolvedSource, LetPropertyMaps letPropertyMaps) => diff --git a/src/AutoMapper/QueryableExtensions/ProjectionMappers/StringProjectionMapper.cs b/src/AutoMapper/QueryableExtensions/ProjectionMappers/StringProjectionMapper.cs index 754407c354..42f1ea58f8 100644 --- a/src/AutoMapper/QueryableExtensions/ProjectionMappers/StringProjectionMapper.cs +++ b/src/AutoMapper/QueryableExtensions/ProjectionMappers/StringProjectionMapper.cs @@ -1,7 +1,3 @@ -using AutoMapper.Execution; -using AutoMapper.Internal; -using System.ComponentModel; -using System.Linq.Expressions; namespace AutoMapper.QueryableExtensions.Impl; [EditorBrowsable(EditorBrowsableState.Never)] diff --git a/src/AutoMapper/ResolutionContext.cs b/src/AutoMapper/ResolutionContext.cs index ff4525d72b..05aa6db08a 100644 --- a/src/AutoMapper/ResolutionContext.cs +++ b/src/AutoMapper/ResolutionContext.cs @@ -1,6 +1,3 @@ -using AutoMapper.Internal; -using System; -using System.Collections.Generic; namespace AutoMapper; /// diff --git a/src/AutoMapper/TypeMap.cs b/src/AutoMapper/TypeMap.cs index b5985682c8..f22018e546 100644 --- a/src/AutoMapper/TypeMap.cs +++ b/src/AutoMapper/TypeMap.cs @@ -1,18 +1,5 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; -using System.ComponentModel; namespace AutoMapper; - -using Execution; -using static Expression; -using static Execution.ExpressionBuilder; -using Configuration; using Features; -using Internal; /// /// Main configuration object holding all mapping configuration for a source and destination type /// @@ -128,7 +115,7 @@ public IEnumerable MemberMaps public bool ConstructorMapping => ConstructorMap is { CanResolve: true }; public bool CustomConstruction => CustomCtorFunction != null; public bool HasTypeConverter => TypeConverter != null; - public TypeConverter TypeConverter { get; set; } + public Execution.TypeConverter TypeConverter { get; set; } public bool ShouldCheckForValid => ConfiguredMemberList != MemberList.None && !HasTypeConverter; public LambdaExpression[] IncludedMembers { get => _details?.IncludedMembers ?? Array.Empty(); set => Details.IncludedMembers = value; } public string[] IncludedMembersNames { get => _details?.IncludedMembersNames ?? Array.Empty(); set => Details.IncludedMembersNames = value; } diff --git a/src/Benchmark/BenchEngine.cs b/src/Benchmark/BenchEngine.cs index bf8d2b49b2..7cc527f21f 100644 --- a/src/Benchmark/BenchEngine.cs +++ b/src/Benchmark/BenchEngine.cs @@ -1,6 +1,3 @@ -using System; -using System.Diagnostics; - namespace Benchmark; public class BenchEngine diff --git a/src/Benchmark/FlatteningMapper.cs b/src/Benchmark/FlatteningMapper.cs index c940974e19..b43760d5b4 100644 --- a/src/Benchmark/FlatteningMapper.cs +++ b/src/Benchmark/FlatteningMapper.cs @@ -1,7 +1,4 @@ -using System; using AutoMapper; -using System.Collections.Generic; -using System.Linq; namespace Benchmark.Flattening; static class Config diff --git a/src/Benchmark/HiPerfTimer.cs b/src/Benchmark/HiPerfTimer.cs index 976163f732..7fad1b12f1 100644 --- a/src/Benchmark/HiPerfTimer.cs +++ b/src/Benchmark/HiPerfTimer.cs @@ -1,6 +1,4 @@ -using System.ComponentModel; using System.Runtime.InteropServices; -using System.Threading; namespace Benchmark; diff --git a/src/Benchmark/IObjectToObjectMapper.cs b/src/Benchmark/IObjectToObjectMapper.cs index ec6041349c..0a1104c932 100644 --- a/src/Benchmark/IObjectToObjectMapper.cs +++ b/src/Benchmark/IObjectToObjectMapper.cs @@ -1,5 +1,3 @@ -using System; - namespace Benchmark; public interface IObjectToObjectMapper diff --git a/src/Benchmark/Program.cs b/src/Benchmark/Program.cs index df2b635547..fd1d9f7037 100644 --- a/src/Benchmark/Program.cs +++ b/src/Benchmark/Program.cs @@ -1,6 +1,4 @@ -using System; -using System.Collections.Generic; -using Benchmark.Flattening; +using Benchmark.Flattening; namespace Benchmark; diff --git a/src/IntegrationTests/AutoMapper.IntegrationTests.csproj b/src/IntegrationTests/AutoMapper.IntegrationTests.csproj index 2fc9fa80f5..1be2af918e 100644 --- a/src/IntegrationTests/AutoMapper.IntegrationTests.csproj +++ b/src/IntegrationTests/AutoMapper.IntegrationTests.csproj @@ -14,5 +14,14 @@ - + + + + + + + + + + \ No newline at end of file diff --git a/src/IntegrationTests/BuiltInTypes/ByteArray.cs b/src/IntegrationTests/BuiltInTypes/ByteArray.cs index 7d37b6ecd4..2fbe292b10 100644 --- a/src/IntegrationTests/BuiltInTypes/ByteArray.cs +++ b/src/IntegrationTests/BuiltInTypes/ByteArray.cs @@ -1,12 +1,4 @@ -using System.ComponentModel.DataAnnotations; -using System.Linq; -using System.Threading.Tasks; -using AutoMapper.UnitTests; -using Microsoft.EntityFrameworkCore; -using Shouldly; -using Xunit; - -namespace AutoMapper.IntegrationTests.BuiltInTypes; +namespace AutoMapper.IntegrationTests.BuiltInTypes; public class ByteArrayColumns : IntegrationTest { diff --git a/src/IntegrationTests/BuiltInTypes/ConvertUsing.cs b/src/IntegrationTests/BuiltInTypes/ConvertUsing.cs index ce5bc172c6..2e6aa15799 100644 --- a/src/IntegrationTests/BuiltInTypes/ConvertUsing.cs +++ b/src/IntegrationTests/BuiltInTypes/ConvertUsing.cs @@ -1,11 +1,4 @@ -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Linq; -using Microsoft.EntityFrameworkCore; -using Shouldly; -using Xunit; - -namespace AutoMapper.IntegrationTests.BuiltInTypes; +namespace AutoMapper.IntegrationTests.BuiltInTypes; public class ConvertUsingWithNullables : IntegrationTest { diff --git a/src/IntegrationTests/BuiltInTypes/DateTimeToNullableDateTime.cs b/src/IntegrationTests/BuiltInTypes/DateTimeToNullableDateTime.cs index e78c2831ec..6372859839 100644 --- a/src/IntegrationTests/BuiltInTypes/DateTimeToNullableDateTime.cs +++ b/src/IntegrationTests/BuiltInTypes/DateTimeToNullableDateTime.cs @@ -1,12 +1,4 @@ -using System; -using System.Linq; -using System.Threading.Tasks; -using AutoMapper.UnitTests; -using Microsoft.EntityFrameworkCore; -using Shouldly; -using Xunit; - -namespace AutoMapper.IntegrationTests.BuiltInTypes; +namespace AutoMapper.IntegrationTests.BuiltInTypes; public class DateTimeToNullableDateTime : IntegrationTest { diff --git a/src/IntegrationTests/BuiltInTypes/Enums.cs b/src/IntegrationTests/BuiltInTypes/Enums.cs index 6a14a77e6b..5f7064fd3b 100644 --- a/src/IntegrationTests/BuiltInTypes/Enums.cs +++ b/src/IntegrationTests/BuiltInTypes/Enums.cs @@ -1,12 +1,4 @@ -using System; -using System.Linq; -using System.Threading.Tasks; -using AutoMapper.UnitTests; -using Microsoft.EntityFrameworkCore; -using Shouldly; -using Xunit; - -namespace AutoMapper.IntegrationTests.BuiltInTypes; +namespace AutoMapper.IntegrationTests.BuiltInTypes; public class EnumToUnderlyingType : IntegrationTest { diff --git a/src/IntegrationTests/BuiltInTypes/NullableToNonNullable.cs b/src/IntegrationTests/BuiltInTypes/NullableToNonNullable.cs index ee0d0fdd85..346e0f2dcb 100644 --- a/src/IntegrationTests/BuiltInTypes/NullableToNonNullable.cs +++ b/src/IntegrationTests/BuiltInTypes/NullableToNonNullable.cs @@ -1,12 +1,4 @@ -using System.ComponentModel.DataAnnotations; -using System.Linq; -using System.Threading.Tasks; -using AutoMapper.UnitTests; -using Microsoft.EntityFrameworkCore; -using Shouldly; -using Xunit; - -namespace AutoMapper.IntegrationTests.BuiltInTypes; +namespace AutoMapper.IntegrationTests.BuiltInTypes; public class NullableLongToLong : IntegrationTest { diff --git a/src/IntegrationTests/BuiltInTypes/ProjectEnumerableOfIntToHashSet.cs b/src/IntegrationTests/BuiltInTypes/ProjectEnumerableOfIntToHashSet.cs index 4fc1f4142b..bc26d9c5fa 100644 --- a/src/IntegrationTests/BuiltInTypes/ProjectEnumerableOfIntToHashSet.cs +++ b/src/IntegrationTests/BuiltInTypes/ProjectEnumerableOfIntToHashSet.cs @@ -1,11 +1,4 @@ -using Microsoft.EntityFrameworkCore; -using Shouldly; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Linq; -using Xunit; - -namespace AutoMapper.IntegrationTests.BuiltInTypes; +namespace AutoMapper.IntegrationTests.BuiltInTypes; public class ProjectEnumerableOfIntToHashSet : IntegrationTest { diff --git a/src/IntegrationTests/BuiltInTypes/ProjectEnumerableOfIntToList.cs b/src/IntegrationTests/BuiltInTypes/ProjectEnumerableOfIntToList.cs index 2c5e0804bf..e8a4a0dfc4 100644 --- a/src/IntegrationTests/BuiltInTypes/ProjectEnumerableOfIntToList.cs +++ b/src/IntegrationTests/BuiltInTypes/ProjectEnumerableOfIntToList.cs @@ -1,13 +1,4 @@ -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Linq; -using System.Threading.Tasks; -using AutoMapper.UnitTests; -using Microsoft.EntityFrameworkCore; -using Shouldly; -using Xunit; - -namespace AutoMapper.IntegrationTests.BuiltInTypes; +namespace AutoMapper.IntegrationTests.BuiltInTypes; public class ProjectEnumerableOfIntToList : IntegrationTest { diff --git a/src/IntegrationTests/ChildClassTests.cs b/src/IntegrationTests/ChildClassTests.cs index c55e0e1cfe..b83ed2d058 100644 --- a/src/IntegrationTests/ChildClassTests.cs +++ b/src/IntegrationTests/ChildClassTests.cs @@ -1,13 +1,4 @@ -using System; -using System.ComponentModel.DataAnnotations; -using System.Linq; -using System.Threading.Tasks; -using AutoMapper.UnitTests; -using Microsoft.EntityFrameworkCore; -using Shouldly; -using Xunit; - -namespace AutoMapper.IntegrationTests +namespace AutoMapper.IntegrationTests { namespace ChildClassTests { diff --git a/src/IntegrationTests/ConstructorDefaultValue.cs b/src/IntegrationTests/ConstructorDefaultValue.cs index 303d93e88d..c580d8346a 100644 --- a/src/IntegrationTests/ConstructorDefaultValue.cs +++ b/src/IntegrationTests/ConstructorDefaultValue.cs @@ -1,8 +1,4 @@ -using Microsoft.EntityFrameworkCore; -using Shouldly; -using System.Linq; -using Xunit; -namespace AutoMapper.IntegrationTests; +namespace AutoMapper.IntegrationTests; public class ConstructorDefaultValue : IntegrationTest { public class Customer diff --git a/src/IntegrationTests/CustomMapFrom/CustomMapFromTest.cs b/src/IntegrationTests/CustomMapFrom/CustomMapFromTest.cs index cf9dea3547..0f14e239c3 100644 --- a/src/IntegrationTests/CustomMapFrom/CustomMapFromTest.cs +++ b/src/IntegrationTests/CustomMapFrom/CustomMapFromTest.cs @@ -1,10 +1,4 @@ -using System.ComponentModel.DataAnnotations; -using System.Linq; -using Microsoft.EntityFrameworkCore; -using Shouldly; -using Xunit; - -namespace AutoMapper.IntegrationTests.CustomMapFrom; +namespace AutoMapper.IntegrationTests.CustomMapFrom; public class CustomMapFromTest : IntegrationTest { diff --git a/src/IntegrationTests/CustomMapFrom/MapObjectPropertyFromSubQuery.cs b/src/IntegrationTests/CustomMapFrom/MapObjectPropertyFromSubQuery.cs index 737a39ce14..0e2d5d7280 100644 --- a/src/IntegrationTests/CustomMapFrom/MapObjectPropertyFromSubQuery.cs +++ b/src/IntegrationTests/CustomMapFrom/MapObjectPropertyFromSubQuery.cs @@ -1,15 +1,4 @@ -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using System.Linq; -using System.Linq.Expressions; -using System.Threading.Tasks; -using AutoMapper.UnitTests; -using Microsoft.EntityFrameworkCore; -using Shouldly; -using Xunit; - -namespace AutoMapper.IntegrationTests.CustomMapFrom; +namespace AutoMapper.IntegrationTests.CustomMapFrom; public class MemberWithSubQueryProjections : IntegrationTest { diff --git a/src/IntegrationTests/CustomProjection.cs b/src/IntegrationTests/CustomProjection.cs index d1e4170911..2cce4cb637 100644 --- a/src/IntegrationTests/CustomProjection.cs +++ b/src/IntegrationTests/CustomProjection.cs @@ -1,11 +1,4 @@ -using System.Linq; -using System.Threading.Tasks; -using AutoMapper.UnitTests; -using Microsoft.EntityFrameworkCore; -using Shouldly; -using Xunit; - -namespace AutoMapper.IntegrationTests; +namespace AutoMapper.IntegrationTests; public class CustomProjectionStringToString : IntegrationTest { diff --git a/src/IntegrationTests/ExplicitExpansion/ExpandCollections.cs b/src/IntegrationTests/ExplicitExpansion/ExpandCollections.cs index 7ebf44e3ea..715fe25711 100644 --- a/src/IntegrationTests/ExplicitExpansion/ExpandCollections.cs +++ b/src/IntegrationTests/ExplicitExpansion/ExpandCollections.cs @@ -1,14 +1,4 @@ -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Diagnostics; -using System.Linq; -using System.Threading.Tasks; -using AutoMapper.UnitTests; -using Microsoft.EntityFrameworkCore; -using Shouldly; -using Xunit; - -namespace AutoMapper.IntegrationTests.ExplicitExpansion; +namespace AutoMapper.IntegrationTests.ExplicitExpansion; public class ExpandCollections : IntegrationTest { diff --git a/src/IntegrationTests/ExplicitExpansion/ExpandCollectionsWithStrings.cs b/src/IntegrationTests/ExplicitExpansion/ExpandCollectionsWithStrings.cs index c071c35fec..059340dda0 100644 --- a/src/IntegrationTests/ExplicitExpansion/ExpandCollectionsWithStrings.cs +++ b/src/IntegrationTests/ExplicitExpansion/ExpandCollectionsWithStrings.cs @@ -1,14 +1,4 @@ -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Diagnostics; -using System.Linq; -using System.Threading.Tasks; -using AutoMapper.UnitTests; -using Microsoft.EntityFrameworkCore; -using Shouldly; -using Xunit; - -namespace AutoMapper.IntegrationTests.ExplicitExpansion; +namespace AutoMapper.IntegrationTests.ExplicitExpansion; public class ExpandCollectionsWithStrings : IntegrationTest { diff --git a/src/IntegrationTests/ExplicitExpansion/ExpandMembersPath.cs b/src/IntegrationTests/ExplicitExpansion/ExpandMembersPath.cs index 9f36925040..98bdf9715f 100644 --- a/src/IntegrationTests/ExplicitExpansion/ExpandMembersPath.cs +++ b/src/IntegrationTests/ExplicitExpansion/ExpandMembersPath.cs @@ -1,14 +1,4 @@ -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using System.Diagnostics; -using System.Linq; -using System.Threading.Tasks; -using AutoMapper.UnitTests; -using Microsoft.EntityFrameworkCore; -using Shouldly; -using Xunit; - -namespace AutoMapper.IntegrationTests.ExplicitExpansion; +namespace AutoMapper.IntegrationTests.ExplicitExpansion; public class ExpandMembersPath : IntegrationTest { diff --git a/src/IntegrationTests/ExplicitExpansion/ExplicitlyExpandCollectionsAndChildReferences.cs b/src/IntegrationTests/ExplicitExpansion/ExplicitlyExpandCollectionsAndChildReferences.cs index 28220a127a..8faa2be65b 100644 --- a/src/IntegrationTests/ExplicitExpansion/ExplicitlyExpandCollectionsAndChildReferences.cs +++ b/src/IntegrationTests/ExplicitExpansion/ExplicitlyExpandCollectionsAndChildReferences.cs @@ -1,14 +1,4 @@ -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Diagnostics; -using System.Linq; -using System.Threading.Tasks; -using AutoMapper.UnitTests; -using Microsoft.EntityFrameworkCore; -using Shouldly; -using Xunit; - -namespace AutoMapper.IntegrationTests.ExplicitExpansion; +namespace AutoMapper.IntegrationTests.ExplicitExpansion; public class ExplicitlyExpandCollectionsAndChildReferences : IntegrationTest { diff --git a/src/IntegrationTests/ExplicitExpansion/MembersToExpandExpressions.cs b/src/IntegrationTests/ExplicitExpansion/MembersToExpandExpressions.cs index 4e1eed4969..9f2a1e868e 100644 --- a/src/IntegrationTests/ExplicitExpansion/MembersToExpandExpressions.cs +++ b/src/IntegrationTests/ExplicitExpansion/MembersToExpandExpressions.cs @@ -1,11 +1,4 @@ -using System.Linq; -using System.Threading.Tasks; -using AutoMapper.UnitTests; -using Microsoft.EntityFrameworkCore; -using Shouldly; -using Xunit; - -namespace AutoMapper.IntegrationTests.ExplicitExpansion; +namespace AutoMapper.IntegrationTests.ExplicitExpansion; public class MembersToExpandExpressions : AutoMapperSpecBase, IAsyncLifetime { diff --git a/src/IntegrationTests/ExplicitExpansion/NestedExplicitExpand.cs b/src/IntegrationTests/ExplicitExpansion/NestedExplicitExpand.cs index 7654776718..91ede3f5e1 100644 --- a/src/IntegrationTests/ExplicitExpansion/NestedExplicitExpand.cs +++ b/src/IntegrationTests/ExplicitExpansion/NestedExplicitExpand.cs @@ -1,12 +1,4 @@ -using System.Diagnostics; -using System.Linq; -using System.Threading.Tasks; -using AutoMapper.UnitTests; -using Microsoft.EntityFrameworkCore; -using Shouldly; -using Xunit; - -namespace AutoMapper.IntegrationTests.ExplicitExpansion; +namespace AutoMapper.IntegrationTests.ExplicitExpansion; public class NestedExplicitExpand : IntegrationTest { diff --git a/src/IntegrationTests/ExplicitExpansion/NestedExplicitExpandWithFields.cs b/src/IntegrationTests/ExplicitExpansion/NestedExplicitExpandWithFields.cs index f54d529ac9..b237c34f9f 100644 --- a/src/IntegrationTests/ExplicitExpansion/NestedExplicitExpandWithFields.cs +++ b/src/IntegrationTests/ExplicitExpansion/NestedExplicitExpandWithFields.cs @@ -1,12 +1,4 @@ -using System.Diagnostics; -using System.Linq; -using System.Threading.Tasks; -using AutoMapper.UnitTests; -using Microsoft.EntityFrameworkCore; -using Shouldly; -using Xunit; - -namespace AutoMapper.IntegrationTests.ExplicitExpansion; +namespace AutoMapper.IntegrationTests.ExplicitExpansion; public class NestedExplicitExpandWithFields : IntegrationTest { diff --git a/src/IntegrationTests/ExplicitExpansion/ProjectAndAllowNullCollections.cs b/src/IntegrationTests/ExplicitExpansion/ProjectAndAllowNullCollections.cs index a29e878d1f..a5909cfa69 100644 --- a/src/IntegrationTests/ExplicitExpansion/ProjectAndAllowNullCollections.cs +++ b/src/IntegrationTests/ExplicitExpansion/ProjectAndAllowNullCollections.cs @@ -1,11 +1,4 @@ -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using AutoMapper.UnitTests; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Builders; -using Shouldly; -using Xunit; +using Microsoft.EntityFrameworkCore.Metadata.Builders; namespace AutoMapper.IntegrationTests.ExplicitExpansion; diff --git a/src/IntegrationTests/ExplicitExpansion/ProjectionWithExplicitExpansion.cs b/src/IntegrationTests/ExplicitExpansion/ProjectionWithExplicitExpansion.cs index b71a5bfbd4..cfcb7964c6 100644 --- a/src/IntegrationTests/ExplicitExpansion/ProjectionWithExplicitExpansion.cs +++ b/src/IntegrationTests/ExplicitExpansion/ProjectionWithExplicitExpansion.cs @@ -1,15 +1,4 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using System.Linq; -using System.Text.RegularExpressions; -using System.Threading.Tasks; -using AutoMapper.QueryableExtensions; -using AutoMapper.UnitTests; -using Microsoft.EntityFrameworkCore; -using Shouldly; -using Xunit; +using System.Text.RegularExpressions; namespace AutoMapper.IntegrationTests.ExplicitExpansion; diff --git a/src/IntegrationTests/ICollectionAggregateProjections.cs b/src/IntegrationTests/ICollectionAggregateProjections.cs index e61d42e711..eda118b842 100644 --- a/src/IntegrationTests/ICollectionAggregateProjections.cs +++ b/src/IntegrationTests/ICollectionAggregateProjections.cs @@ -1,16 +1,4 @@ -using System.ComponentModel.DataAnnotations; -using Microsoft.EntityFrameworkCore; -using System.Linq; -using System.Threading.Tasks; -using Shouldly; -using Xunit; - -namespace AutoMapper.IntegrationTests; - -using UnitTests; -using QueryableExtensions; -using System.Collections.Generic; - +namespace AutoMapper.IntegrationTests; public class ICollectionAggregateProjections : IntegrationTest { public class Customer diff --git a/src/IntegrationTests/IEnumerableAggregateProjections.cs b/src/IntegrationTests/IEnumerableAggregateProjections.cs index ad3ac23559..595e119b3b 100644 --- a/src/IntegrationTests/IEnumerableAggregateProjections.cs +++ b/src/IntegrationTests/IEnumerableAggregateProjections.cs @@ -1,16 +1,4 @@ -using System.ComponentModel.DataAnnotations; -using Microsoft.EntityFrameworkCore; -using System.Linq; -using System.Threading.Tasks; -using Shouldly; -using Xunit; - -namespace AutoMapper.IntegrationTests; - -using UnitTests; -using QueryableExtensions; -using System.Collections.Generic; - +namespace AutoMapper.IntegrationTests; public class IEnumerableAggregateProjections : IntegrationTest { public class Customer diff --git a/src/IntegrationTests/IEnumerableMemberProjections.cs b/src/IntegrationTests/IEnumerableMemberProjections.cs index 07f0b2673a..e6de82c28a 100644 --- a/src/IntegrationTests/IEnumerableMemberProjections.cs +++ b/src/IntegrationTests/IEnumerableMemberProjections.cs @@ -1,16 +1,4 @@ -using System.ComponentModel.DataAnnotations; -using Microsoft.EntityFrameworkCore; -using System.Linq; -using System.Threading.Tasks; -using Shouldly; -using Xunit; - -namespace AutoMapper.IntegrationTests; - -using UnitTests; -using QueryableExtensions; -using System.Collections.Generic; - +namespace AutoMapper.IntegrationTests; public class IEnumerableMemberProjections : IntegrationTest { public class Customer diff --git a/src/IntegrationTests/IncludeMembers.cs b/src/IntegrationTests/IncludeMembers.cs index f55eec94cd..a1474dc9f5 100644 --- a/src/IntegrationTests/IncludeMembers.cs +++ b/src/IntegrationTests/IncludeMembers.cs @@ -1,14 +1,4 @@ -using System; -using System.Collections.Generic; -using Microsoft.EntityFrameworkCore; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using AutoMapper.UnitTests; -using Shouldly; -using Xunit; - -namespace AutoMapper.IntegrationTests; +namespace AutoMapper.IntegrationTests; public class IncludeMembers : IntegrationTest { diff --git a/src/IntegrationTests/Inheritance/DerivedComplexTypes.cs b/src/IntegrationTests/Inheritance/DerivedComplexTypes.cs index c9c63bc08a..6997e1f153 100644 --- a/src/IntegrationTests/Inheritance/DerivedComplexTypes.cs +++ b/src/IntegrationTests/Inheritance/DerivedComplexTypes.cs @@ -1,13 +1,4 @@ -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using System.Linq; -using System.Threading.Tasks; -using AutoMapper.UnitTests; -using Microsoft.EntityFrameworkCore; -using Shouldly; -using Xunit; - -namespace AutoMapper.IntegrationTests.Inheritance; +namespace AutoMapper.IntegrationTests.Inheritance; public class DerivedComplexTypes : IntegrationTest { diff --git a/src/IntegrationTests/Inheritance/OverrideDestinationMappingsTest.cs b/src/IntegrationTests/Inheritance/OverrideDestinationMappingsTest.cs index 93bfcfe223..7c632c7015 100644 --- a/src/IntegrationTests/Inheritance/OverrideDestinationMappingsTest.cs +++ b/src/IntegrationTests/Inheritance/OverrideDestinationMappingsTest.cs @@ -1,11 +1,4 @@ -using System.Linq; -using System.Threading.Tasks; -using AutoMapper.UnitTests; -using Microsoft.EntityFrameworkCore; -using Shouldly; -using Xunit; - -namespace AutoMapper.IntegrationTests.Inheritance; +namespace AutoMapper.IntegrationTests.Inheritance; public class OverrideDestinationMappingsTest : IntegrationTest { diff --git a/src/IntegrationTests/Inheritance/ProjectToAbstractType.cs b/src/IntegrationTests/Inheritance/ProjectToAbstractType.cs index 23c4d80024..ed85ddcee6 100644 --- a/src/IntegrationTests/Inheritance/ProjectToAbstractType.cs +++ b/src/IntegrationTests/Inheritance/ProjectToAbstractType.cs @@ -1,12 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; -using System.Threading.Tasks; -using AutoMapper.UnitTests; -using Microsoft.EntityFrameworkCore; -using Shouldly; -using Xunit; +using System.Collections.ObjectModel; namespace AutoMapper.IntegrationTests.Inheritance; diff --git a/src/IntegrationTests/Inheritance/ProxyTests.cs b/src/IntegrationTests/Inheritance/ProxyTests.cs index 3eb35328e0..706a60340e 100644 --- a/src/IntegrationTests/Inheritance/ProxyTests.cs +++ b/src/IntegrationTests/Inheritance/ProxyTests.cs @@ -1,12 +1,4 @@ -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Linq; -using System.Threading.Tasks; -using AutoMapper.UnitTests; -using Microsoft.EntityFrameworkCore; -using Xunit; - -namespace AutoMapper.IntegrationTests.Inheritance; +namespace AutoMapper.IntegrationTests.Inheritance; public class ProxyTests : IAsyncLifetime { diff --git a/src/IntegrationTests/Inheritance/QueryableInterfaceInheritanceIssue.cs b/src/IntegrationTests/Inheritance/QueryableInterfaceInheritanceIssue.cs index 7e6e131674..bc76a5215b 100644 --- a/src/IntegrationTests/Inheritance/QueryableInterfaceInheritanceIssue.cs +++ b/src/IntegrationTests/Inheritance/QueryableInterfaceInheritanceIssue.cs @@ -1,11 +1,4 @@ -using System.Linq; -using System.Threading.Tasks; -using AutoMapper.UnitTests; -using Microsoft.EntityFrameworkCore; -using Shouldly; -using Xunit; - -namespace AutoMapper.IntegrationTests.Inheritance; +namespace AutoMapper.IntegrationTests.Inheritance; public class QueryableInterfaceInheritanceIssue : IntegrationTest { diff --git a/src/IntegrationTests/IntegrationTest.cs b/src/IntegrationTests/IntegrationTest.cs index f9507df4ec..2739c3c515 100644 --- a/src/IntegrationTests/IntegrationTest.cs +++ b/src/IntegrationTests/IntegrationTest.cs @@ -1,9 +1,4 @@ -using System.Threading.Tasks; -using AutoMapper.UnitTests; -using Microsoft.EntityFrameworkCore; -using Xunit; - -namespace AutoMapper.IntegrationTests; +namespace AutoMapper.IntegrationTests; public abstract class IntegrationTest : AutoMapperSpecBase, IAsyncLifetime where TInitializer : IInitializer, new() { diff --git a/src/IntegrationTests/LocalDbContext.cs b/src/IntegrationTests/LocalDbContext.cs index 7508762669..66fb48d50b 100644 --- a/src/IntegrationTests/LocalDbContext.cs +++ b/src/IntegrationTests/LocalDbContext.cs @@ -1,6 +1,4 @@ -using Microsoft.EntityFrameworkCore; - -namespace AutoMapper.IntegrationTests; +namespace AutoMapper.IntegrationTests; public abstract class LocalDbContext : DbContext { diff --git a/src/IntegrationTests/MaxDepth/MaxDepthWithCollections.cs b/src/IntegrationTests/MaxDepth/MaxDepthWithCollections.cs index feff83633e..33539009d6 100644 --- a/src/IntegrationTests/MaxDepth/MaxDepthWithCollections.cs +++ b/src/IntegrationTests/MaxDepth/MaxDepthWithCollections.cs @@ -1,13 +1,4 @@ -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Linq; -using System.Threading.Tasks; -using AutoMapper.UnitTests; -using Microsoft.EntityFrameworkCore; -using Shouldly; -using Xunit; - -namespace AutoMapper.IntegrationTests.MaxDepth; +namespace AutoMapper.IntegrationTests.MaxDepth; public class MaxDepthWithCollections : IntegrationTest { diff --git a/src/IntegrationTests/MaxDepth/NavigationPropertySO.cs b/src/IntegrationTests/MaxDepth/NavigationPropertySO.cs index 1f31761161..b04f534fdd 100644 --- a/src/IntegrationTests/MaxDepth/NavigationPropertySO.cs +++ b/src/IntegrationTests/MaxDepth/NavigationPropertySO.cs @@ -1,14 +1,4 @@ -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using System.Linq; -using System.Threading.Tasks; -using AutoMapper.UnitTests; -using Microsoft.EntityFrameworkCore; -using Shouldly; -using Xunit; - -namespace AutoMapper.IntegrationTests.MaxDepth; +namespace AutoMapper.IntegrationTests.MaxDepth; public class NavigationPropertySO : IntegrationTest { diff --git a/src/IntegrationTests/MaxDepth/NestedDtos.cs b/src/IntegrationTests/MaxDepth/NestedDtos.cs index cf64683f3f..09ea40301a 100644 --- a/src/IntegrationTests/MaxDepth/NestedDtos.cs +++ b/src/IntegrationTests/MaxDepth/NestedDtos.cs @@ -1,14 +1,4 @@ -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using System.Linq; -using System.Threading.Tasks; -using AutoMapper.UnitTests; -using Microsoft.EntityFrameworkCore; -using Shouldly; -using Xunit; - -namespace AutoMapper.IntegrationTests.MaxDepth; +namespace AutoMapper.IntegrationTests.MaxDepth; public class NestedDtos : IntegrationTest { diff --git a/src/IntegrationTests/NullCheckCollections.cs b/src/IntegrationTests/NullCheckCollections.cs index aabbbb7d56..9ca40cabae 100644 --- a/src/IntegrationTests/NullCheckCollections.cs +++ b/src/IntegrationTests/NullCheckCollections.cs @@ -1,16 +1,4 @@ -using System.ComponentModel.DataAnnotations; -using Microsoft.EntityFrameworkCore; -using System.Linq; -using Shouldly; -using Xunit; -using System.ComponentModel.DataAnnotations.Schema; -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace AutoMapper.IntegrationTests; - -using System; -using UnitTests; +namespace AutoMapper.IntegrationTests; public class NullCheckCollectionsFirstOrDefault : IntegrationTest { public class SourceType diff --git a/src/IntegrationTests/NullSubstitute.cs b/src/IntegrationTests/NullSubstitute.cs index 92a08a080f..747f625d2a 100644 --- a/src/IntegrationTests/NullSubstitute.cs +++ b/src/IntegrationTests/NullSubstitute.cs @@ -1,14 +1,5 @@ -using System.ComponentModel.DataAnnotations; -using Microsoft.EntityFrameworkCore; -using System.Linq; -using System.Threading.Tasks; -using Shouldly; -using Xunit; +namespace AutoMapper.IntegrationTests; -namespace AutoMapper.IntegrationTests; - -using UnitTests; - public class NullSubstitute : IntegrationTest { public class Customer diff --git a/src/IntegrationTests/ParameterizedQueries.cs b/src/IntegrationTests/ParameterizedQueries.cs index caf10efbcc..35d6deffb5 100644 --- a/src/IntegrationTests/ParameterizedQueries.cs +++ b/src/IntegrationTests/ParameterizedQueries.cs @@ -1,13 +1,4 @@ -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using System.Threading.Tasks; -using AutoMapper.UnitTests; -using Microsoft.EntityFrameworkCore; -using Shouldly; -using Xunit; - -namespace AutoMapper.IntegrationTests; +namespace AutoMapper.IntegrationTests; public class ParameterizedQueries : IntegrationTest { diff --git a/src/IntegrationTests/ProjectionAdvanced.cs b/src/IntegrationTests/ProjectionAdvanced.cs index 5c3d0c060b..1d66f33403 100644 --- a/src/IntegrationTests/ProjectionAdvanced.cs +++ b/src/IntegrationTests/ProjectionAdvanced.cs @@ -1,9 +1,4 @@ -using AutoMapper.UnitTests; -using Microsoft.EntityFrameworkCore; -using Shouldly; -using System.Linq; -using Xunit; -namespace AutoMapper.IntegrationTests; +namespace AutoMapper.IntegrationTests; public class ProjectionAdvanced : IntegrationTest { protected override MapperConfiguration CreateConfiguration() => new(c => c.CreateProjection().Advanced().ForAllMembers(o=>o.Ignore())); diff --git a/src/IntegrationTests/ProjectionOrderTest.cs b/src/IntegrationTests/ProjectionOrderTest.cs index 8b32e50d0e..82dd1cb951 100644 --- a/src/IntegrationTests/ProjectionOrderTest.cs +++ b/src/IntegrationTests/ProjectionOrderTest.cs @@ -1,12 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using AutoMapper.UnitTests; -using Microsoft.EntityFrameworkCore; -using Xunit; - -namespace AutoMapper.IntegrationTests; +namespace AutoMapper.IntegrationTests; public class ProjectionOrderTest : IntegrationTest { diff --git a/src/IntegrationTests/ValueTransformerTests.cs b/src/IntegrationTests/ValueTransformerTests.cs index d026c5e88c..74409fc82a 100644 --- a/src/IntegrationTests/ValueTransformerTests.cs +++ b/src/IntegrationTests/ValueTransformerTests.cs @@ -1,11 +1,4 @@ -using System.ComponentModel.DataAnnotations; -using System.Threading.Tasks; -using AutoMapper.UnitTests; -using Microsoft.EntityFrameworkCore; -using Shouldly; -using Xunit; - -namespace AutoMapper.IntegrationTests +namespace AutoMapper.IntegrationTests { namespace ValueTransformerTests { diff --git a/src/UnitTests/AddProfiles.cs b/src/UnitTests/AddProfiles.cs index d972c762e9..9e947541da 100644 --- a/src/UnitTests/AddProfiles.cs +++ b/src/UnitTests/AddProfiles.cs @@ -1,8 +1,4 @@ -using System.Linq; -using Shouldly; -using Xunit; - -namespace AutoMapper.UnitTests; +namespace AutoMapper.UnitTests; public class AddProfiles : AutoMapperSpecBase { diff --git a/src/UnitTests/ArraysAndLists.cs b/src/UnitTests/ArraysAndLists.cs index bc7e4c8326..394a45bba0 100644 --- a/src/UnitTests/ArraysAndLists.cs +++ b/src/UnitTests/ArraysAndLists.cs @@ -1,13 +1,4 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using Xunit; -using Shouldly; -using System.Linq; using System.Dynamic; -using System.Linq.Expressions; -using AutoMapper.Internal; using AutoMapper.Internal.Mappers; namespace AutoMapper.UnitTests.ArraysAndLists; diff --git a/src/UnitTests/AssemblyScanning.cs b/src/UnitTests/AssemblyScanning.cs index 3932b802d2..5782f3d398 100644 --- a/src/UnitTests/AssemblyScanning.cs +++ b/src/UnitTests/AssemblyScanning.cs @@ -1,10 +1,4 @@ -using System.Linq; -using Shouldly; -using System; -using System.Reflection; -using Xunit; - -namespace AutoMapper.UnitTests +namespace AutoMapper.UnitTests { namespace AssemblyScanning { diff --git a/src/UnitTests/AssertionExtensions.cs b/src/UnitTests/AssertionExtensions.cs index 680236fa89..91c8a591f9 100644 --- a/src/UnitTests/AssertionExtensions.cs +++ b/src/UnitTests/AssertionExtensions.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections; -using System.Linq; -using Shouldly; - -namespace AutoMapper.UnitTests; +namespace AutoMapper.UnitTests; public static class AssertionExtensions { diff --git a/src/UnitTests/AttributeBasedMaps.cs b/src/UnitTests/AttributeBasedMaps.cs index 68c081a962..1b42aec683 100644 --- a/src/UnitTests/AttributeBasedMaps.cs +++ b/src/UnitTests/AttributeBasedMaps.cs @@ -1,8 +1,4 @@ using AutoMapper.Configuration.Annotations; -using Shouldly; -using System.Collections.Generic; -using System.Linq; -using Xunit; namespace AutoMapper.UnitTests { diff --git a/src/UnitTests/AutoMapper.UnitTests.csproj b/src/UnitTests/AutoMapper.UnitTests.csproj index 9df7afc7b6..717022baa4 100644 --- a/src/UnitTests/AutoMapper.UnitTests.csproj +++ b/src/UnitTests/AutoMapper.UnitTests.csproj @@ -12,5 +12,10 @@ - + + + + + + \ No newline at end of file diff --git a/src/UnitTests/AutoMapperSpecBase.cs b/src/UnitTests/AutoMapperSpecBase.cs index edb4554a93..8bf15109cc 100644 --- a/src/UnitTests/AutoMapperSpecBase.cs +++ b/src/UnitTests/AutoMapperSpecBase.cs @@ -1,9 +1,3 @@ -using System; -using AutoMapper.Internal; -using Shouldly; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; namespace AutoMapper.UnitTests; public abstract class AutoMapperSpecBase : NonValidatingSpecBase { diff --git a/src/UnitTests/AutoMapperTester.cs b/src/UnitTests/AutoMapperTester.cs index f1c4130c37..b06d73920f 100644 --- a/src/UnitTests/AutoMapperTester.cs +++ b/src/UnitTests/AutoMapperTester.cs @@ -1,7 +1,3 @@ -using System; -using Shouldly; -using Xunit; - namespace AutoMapper.UnitTests; public class AutoMapperTester : IDisposable diff --git a/src/UnitTests/BasicFlattening.cs b/src/UnitTests/BasicFlattening.cs index 167292563a..225691faa7 100644 --- a/src/UnitTests/BasicFlattening.cs +++ b/src/UnitTests/BasicFlattening.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using Xunit; -using Shouldly; -using System.Linq; - -namespace AutoMapper.UnitTests; +namespace AutoMapper.UnitTests; public class BasicFlattening : AutoMapperSpecBase { diff --git a/src/UnitTests/BeforeAfterMapping.cs b/src/UnitTests/BeforeAfterMapping.cs index e37d45f8fa..10a1a02e90 100644 --- a/src/UnitTests/BeforeAfterMapping.cs +++ b/src/UnitTests/BeforeAfterMapping.cs @@ -1,11 +1,4 @@ -using System; -using Shouldly; -using Xunit; - namespace AutoMapper.UnitTests.BeforeAfterMapping; - -using Bug; - public class When_configuring_before_and_after_methods { public class Source diff --git a/src/UnitTests/BidirectionalRelationships.cs b/src/UnitTests/BidirectionalRelationships.cs index 075e04d197..90bc34ad22 100644 --- a/src/UnitTests/BidirectionalRelationships.cs +++ b/src/UnitTests/BidirectionalRelationships.cs @@ -1,12 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -using Shouldly; - -using Xunit; - -namespace AutoMapper.UnitTests. BidirectionalRelationships; +namespace AutoMapper.UnitTests.BidirectionalRelationships; public class RecursiveMappingWithStruct : AutoMapperSpecBase { diff --git a/src/UnitTests/BidirectionalRelationshipsWithoutPR.cs b/src/UnitTests/BidirectionalRelationshipsWithoutPR.cs index 81296a4a2e..302032c1cd 100644 --- a/src/UnitTests/BidirectionalRelationshipsWithoutPR.cs +++ b/src/UnitTests/BidirectionalRelationshipsWithoutPR.cs @@ -1,10 +1,3 @@ -using System; -using System.CodeDom; -using System.Collections.Generic; -using System.Linq; -using Shouldly; -using Xunit; - namespace AutoMapper.UnitTests; public class CyclesWithInheritance : AutoMapperSpecBase diff --git a/src/UnitTests/Bug/AddingConfigurationForNonMatchingDestinationMemberBug.cs b/src/UnitTests/Bug/AddingConfigurationForNonMatchingDestinationMemberBug.cs index 277a138591..d4dfada141 100644 --- a/src/UnitTests/Bug/AddingConfigurationForNonMatchingDestinationMemberBug.cs +++ b/src/UnitTests/Bug/AddingConfigurationForNonMatchingDestinationMemberBug.cs @@ -1,7 +1,3 @@ -using System; -using Shouldly; -using Xunit; - namespace AutoMapper.UnitTests.Bug { namespace AddingConfigurationForNonMatchingDestinationMember diff --git a/src/UnitTests/Bug/AfterMapNestedObjects.cs b/src/UnitTests/Bug/AfterMapNestedObjects.cs index 15855bab19..69461a3fce 100644 --- a/src/UnitTests/Bug/AfterMapNestedObjects.cs +++ b/src/UnitTests/Bug/AfterMapNestedObjects.cs @@ -1,7 +1,4 @@ -using Shouldly; -using Xunit; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class AfterMapNestedObjects : AutoMapperSpecBase { diff --git a/src/UnitTests/Bug/AllowNullCollectionsAssignableArray.cs b/src/UnitTests/Bug/AllowNullCollectionsAssignableArray.cs index 48ea1cb8ca..2c37e98a5e 100644 --- a/src/UnitTests/Bug/AllowNullCollectionsAssignableArray.cs +++ b/src/UnitTests/Bug/AllowNullCollectionsAssignableArray.cs @@ -1,9 +1,4 @@ -using Xunit; -using Shouldly; -using System; -using System.Collections.Generic; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class AllowNullCollectionsAssignableArray : AutoMapperSpecBase { diff --git a/src/UnitTests/Bug/AllowNullDestinationValuesBugs.cs b/src/UnitTests/Bug/AllowNullDestinationValuesBugs.cs index fa62aba12d..b823aaacc9 100644 --- a/src/UnitTests/Bug/AllowNullDestinationValuesBugs.cs +++ b/src/UnitTests/Bug/AllowNullDestinationValuesBugs.cs @@ -1,6 +1,3 @@ -using Xunit; -using Shouldly; - namespace AutoMapper.UnitTests.Bug; public class When_mapping_to_an_assignable_object_with_nullable_off : AutoMapperSpecBase diff --git a/src/UnitTests/Bug/AssertConfigurationIsValidNullables.cs b/src/UnitTests/Bug/AssertConfigurationIsValidNullables.cs index 7485d7a7d4..1d5cd6c44c 100644 --- a/src/UnitTests/Bug/AssertConfigurationIsValidNullables.cs +++ b/src/UnitTests/Bug/AssertConfigurationIsValidNullables.cs @@ -1,8 +1,4 @@ -using Xunit; -using Shouldly; -using System; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class AssertConfigurationIsValidNullables : AutoMapperSpecBase { diff --git a/src/UnitTests/Bug/AssignableCollectionBug.cs b/src/UnitTests/Bug/AssignableCollectionBug.cs index 2c567595d6..9a77ecf583 100644 --- a/src/UnitTests/Bug/AssignableCollectionBug.cs +++ b/src/UnitTests/Bug/AssignableCollectionBug.cs @@ -1,7 +1,3 @@ -using System.Collections.Generic; -using Xunit; -using Shouldly; - namespace AutoMapper.UnitTests.Bug { namespace ByteArrayBug diff --git a/src/UnitTests/Bug/AutoMapperInheritanceProblemDemo.cs b/src/UnitTests/Bug/AutoMapperInheritanceProblemDemo.cs index 3fe38ccddb..652b8ec857 100644 --- a/src/UnitTests/Bug/AutoMapperInheritanceProblemDemo.cs +++ b/src/UnitTests/Bug/AutoMapperInheritanceProblemDemo.cs @@ -1,7 +1,4 @@ -using Xunit; -using Shouldly; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class SettersInBaseClasses : AutoMapperSpecBase { diff --git a/src/UnitTests/Bug/BaseMapWithIncludesAndUnincludedMappings.cs b/src/UnitTests/Bug/BaseMapWithIncludesAndUnincludedMappings.cs index c9a9859fdf..03057955a9 100644 --- a/src/UnitTests/Bug/BaseMapWithIncludesAndUnincludedMappings.cs +++ b/src/UnitTests/Bug/BaseMapWithIncludesAndUnincludedMappings.cs @@ -1,6 +1,4 @@ -using Xunit; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class BaseMapWithIncludesAndUnincludedMappings { diff --git a/src/UnitTests/Bug/CannotConvertEnumToNullable.cs b/src/UnitTests/Bug/CannotConvertEnumToNullable.cs index b8a366a752..fbc64b47ac 100644 --- a/src/UnitTests/Bug/CannotConvertEnumToNullable.cs +++ b/src/UnitTests/Bug/CannotConvertEnumToNullable.cs @@ -1,7 +1,4 @@ -using Shouldly; -using Xunit; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class CannotConvertEnumToNullable { diff --git a/src/UnitTests/Bug/CannotMapICollectionToAggregateSumDestination.cs b/src/UnitTests/Bug/CannotMapICollectionToAggregateSumDestination.cs index deda64617e..2971ec79b6 100644 --- a/src/UnitTests/Bug/CannotMapICollectionToAggregateSumDestination.cs +++ b/src/UnitTests/Bug/CannotMapICollectionToAggregateSumDestination.cs @@ -1,10 +1,4 @@ -using Shouldly; -using Xunit; -using System.Linq; -using AutoMapper.QueryableExtensions; -using System.Collections.Generic; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class CannotMapICollectionToAggregateSumDestination { diff --git a/src/UnitTests/Bug/CannotProjectIEnumerableToAggregateDestinations.cs b/src/UnitTests/Bug/CannotProjectIEnumerableToAggregateDestinations.cs index b715448352..c5b04c106e 100644 --- a/src/UnitTests/Bug/CannotProjectIEnumerableToAggregateDestinations.cs +++ b/src/UnitTests/Bug/CannotProjectIEnumerableToAggregateDestinations.cs @@ -1,10 +1,4 @@ -using Shouldly; -using Xunit; -using System.Linq; -using AutoMapper.QueryableExtensions; -using System.Collections.Generic; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class CannotProjectIEnumerableToAggregateDestinations { diff --git a/src/UnitTests/Bug/CannotProjectStringToNullableEnum.cs b/src/UnitTests/Bug/CannotProjectStringToNullableEnum.cs index d080c8710d..f2a7d4337b 100644 --- a/src/UnitTests/Bug/CannotProjectStringToNullableEnum.cs +++ b/src/UnitTests/Bug/CannotProjectStringToNullableEnum.cs @@ -1,10 +1,4 @@ -using Shouldly; -using Xunit; -using System.Linq; -using AutoMapper; -using AutoMapper.QueryableExtensions; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class CannotProjectStringToNullableEnum { diff --git a/src/UnitTests/Bug/CaseSensitivityBug.cs b/src/UnitTests/Bug/CaseSensitivityBug.cs index 4dc42d645b..667a5e7867 100644 --- a/src/UnitTests/Bug/CaseSensitivityBug.cs +++ b/src/UnitTests/Bug/CaseSensitivityBug.cs @@ -1,7 +1,4 @@ namespace AutoMapper.UnitTests.Bug; - -using Xunit; - public class CaseSensitivityBug : AutoMapperSpecBase { protected override MapperConfiguration CreateConfiguration() => new(cfg => diff --git a/src/UnitTests/Bug/CollectionBaseClassGetConvention.cs b/src/UnitTests/Bug/CollectionBaseClassGetConvention.cs index c52dc4a304..3fdb1cdbad 100644 --- a/src/UnitTests/Bug/CollectionBaseClassGetConvention.cs +++ b/src/UnitTests/Bug/CollectionBaseClassGetConvention.cs @@ -1,11 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Shouldly; -using AutoMapper; -using Xunit; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class CollectionBaseClassGetConvention : AutoMapperSpecBase { diff --git a/src/UnitTests/Bug/CollectionMapperMapsISetIncorrectly.cs b/src/UnitTests/Bug/CollectionMapperMapsISetIncorrectly.cs index 8e594d57c5..e44e1b4f74 100644 --- a/src/UnitTests/Bug/CollectionMapperMapsISetIncorrectly.cs +++ b/src/UnitTests/Bug/CollectionMapperMapsISetIncorrectly.cs @@ -1,9 +1,4 @@ -using System.Collections.Generic; -using System.Linq; -using AutoMapper.Internal.Mappers; -using Xunit; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class CollectionMapperMapsIEnumerableToISetIncorrectly { diff --git a/src/UnitTests/Bug/CollectionWhere.cs b/src/UnitTests/Bug/CollectionWhere.cs index b507d2e53f..ec9a4c54a8 100644 --- a/src/UnitTests/Bug/CollectionWhere.cs +++ b/src/UnitTests/Bug/CollectionWhere.cs @@ -1,10 +1,4 @@ -using Xunit; -using Shouldly; -using System; -using System.Linq; -using System.Collections.Generic; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class CollectionWhere : AutoMapperSpecBase { diff --git a/src/UnitTests/Bug/CollectionsNullability.cs b/src/UnitTests/Bug/CollectionsNullability.cs index e8009d651c..7e6a297601 100644 --- a/src/UnitTests/Bug/CollectionsNullability.cs +++ b/src/UnitTests/Bug/CollectionsNullability.cs @@ -1,9 +1,4 @@ -using Xunit; -using Shouldly; -using System; -using System.Collections.Generic; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class CollectionsNullability : AutoMapperSpecBase { diff --git a/src/UnitTests/Bug/ConditionBug.cs b/src/UnitTests/Bug/ConditionBug.cs index 8a260322f1..e249102cd4 100644 --- a/src/UnitTests/Bug/ConditionBug.cs +++ b/src/UnitTests/Bug/ConditionBug.cs @@ -2,10 +2,6 @@ { namespace ConditionBug { - using System.Collections.Generic; - using Shouldly; - using Xunit; - public class Example : AutoMapperSpecBase { public class SubSource @@ -93,10 +89,6 @@ public void Should_skip_when_condition_not_met() namespace ConditionPropertyBug { - using System; - using Shouldly; - using Xunit; - public class Example : AutoMapperSpecBase { public class Source @@ -157,9 +149,6 @@ public void Should_execute_the_mapping_when_the_condition_property_is_true() namespace SourceValueConditionPropertyBug { - using Shouldly; - using Xunit; - public class Source { public int Value { get; set; } @@ -198,11 +187,6 @@ public void Should_not_map_value_when_not_null() namespace SourceValueExceptionConditionPropertyBug { - using System; - using System.Collections.Generic; - using Shouldly; - using Xunit; - public enum Property { Value1 = 0, diff --git a/src/UnitTests/Bug/ConstructUsingReturnsNull.cs b/src/UnitTests/Bug/ConstructUsingReturnsNull.cs index 8392d5e683..4e843c9545 100644 --- a/src/UnitTests/Bug/ConstructUsingReturnsNull.cs +++ b/src/UnitTests/Bug/ConstructUsingReturnsNull.cs @@ -1,8 +1,4 @@ -using Xunit; -using Shouldly; -using System; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class ConstructUsingReturnsNull : AutoMapperSpecBase { diff --git a/src/UnitTests/Bug/ConstructorParameterNamedType.cs b/src/UnitTests/Bug/ConstructorParameterNamedType.cs index ad3fcfde1f..d393406e26 100644 --- a/src/UnitTests/Bug/ConstructorParameterNamedType.cs +++ b/src/UnitTests/Bug/ConstructorParameterNamedType.cs @@ -1,8 +1,4 @@ -using System; -using Shouldly; -using Xunit; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class ConstructorParameterNamedType { diff --git a/src/UnitTests/Bug/ContextValuesIncorrect.cs b/src/UnitTests/Bug/ContextValuesIncorrect.cs index 7cc4a8fea0..bd313a2b2f 100644 --- a/src/UnitTests/Bug/ContextValuesIncorrect.cs +++ b/src/UnitTests/Bug/ContextValuesIncorrect.cs @@ -1,7 +1,4 @@ -using Xunit; -using Shouldly; - -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug { namespace ContextValuesIncorrect { diff --git a/src/UnitTests/Bug/ConvertMapperThreading.cs b/src/UnitTests/Bug/ConvertMapperThreading.cs index f82d14fd9a..4eb344703e 100644 --- a/src/UnitTests/Bug/ConvertMapperThreading.cs +++ b/src/UnitTests/Bug/ConvertMapperThreading.cs @@ -1,12 +1,4 @@ -using System; -using Xunit; -using AutoMapper; -using System.Linq; -using System.Threading.Tasks; -using System.Diagnostics; -using System.Runtime.ExceptionServices; - -namespace AutoMapper.UnitTests; +namespace AutoMapper.UnitTests; public class ConvertMapperThreading { diff --git a/src/UnitTests/Bug/CreateMapExpressionWithIgnoredPropertyBug.cs b/src/UnitTests/Bug/CreateMapExpressionWithIgnoredPropertyBug.cs index 527d295216..41e8d3410f 100644 --- a/src/UnitTests/Bug/CreateMapExpressionWithIgnoredPropertyBug.cs +++ b/src/UnitTests/Bug/CreateMapExpressionWithIgnoredPropertyBug.cs @@ -1,13 +1,4 @@ -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using Shouldly; -using Xunit; - -namespace AutoMapper.UnitTests.Bug; - -using QueryableExtensions; - +namespace AutoMapper.UnitTests.Bug; public class CreateMapExpressionWithIgnoredPropertyBug { [Fact] diff --git a/src/UnitTests/Bug/CustomConverters.cs b/src/UnitTests/Bug/CustomConverters.cs index 7dbedb6f3b..9bd72b2167 100644 --- a/src/UnitTests/Bug/CustomConverters.cs +++ b/src/UnitTests/Bug/CustomConverters.cs @@ -1,8 +1,4 @@ -using Xunit; -using Shouldly; -using System; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class NullableTypeConverter : AutoMapperSpecBase { diff --git a/src/UnitTests/Bug/CustomIEnumerableBug.cs b/src/UnitTests/Bug/CustomIEnumerableBug.cs index 807bdd431a..ddae3d8f37 100644 --- a/src/UnitTests/Bug/CustomIEnumerableBug.cs +++ b/src/UnitTests/Bug/CustomIEnumerableBug.cs @@ -1,11 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using AutoMapper; -using AutoMapper.Internal.Mappers; -using Shouldly; -using Xunit; - namespace AutoMapper.UnitTests.Bug; public class One diff --git a/src/UnitTests/Bug/DeepCloningBug.cs b/src/UnitTests/Bug/DeepCloningBug.cs index 14ff7f18f5..38fc92c052 100644 --- a/src/UnitTests/Bug/DeepCloningBug.cs +++ b/src/UnitTests/Bug/DeepCloningBug.cs @@ -1,9 +1,5 @@ namespace AutoMapper.UnitTests.Bug; -using System; -using Shouldly; -using Xunit; - public class DeepCloningBug : AutoMapperSpecBase { private Outer _source; diff --git a/src/UnitTests/Bug/DeepInheritanceIssue.cs b/src/UnitTests/Bug/DeepInheritanceIssue.cs index 1f1f4ba1a1..1496d52a7b 100644 --- a/src/UnitTests/Bug/DeepInheritanceIssue.cs +++ b/src/UnitTests/Bug/DeepInheritanceIssue.cs @@ -1,7 +1,4 @@ -using Shouldly; -using Xunit; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class DeepInheritanceIssue { diff --git a/src/UnitTests/Bug/DestinationCtorCalledTwice.cs b/src/UnitTests/Bug/DestinationCtorCalledTwice.cs index c43e4db696..74107b380f 100644 --- a/src/UnitTests/Bug/DestinationCtorCalledTwice.cs +++ b/src/UnitTests/Bug/DestinationCtorCalledTwice.cs @@ -1,7 +1,4 @@ -using Xunit; -using Shouldly; - -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug { namespace DestinationCtorCalledTwice { diff --git a/src/UnitTests/Bug/DestinationValueInitializedByCtorBug.cs b/src/UnitTests/Bug/DestinationValueInitializedByCtorBug.cs index 5454f7e8b2..3c9c903e6a 100644 --- a/src/UnitTests/Bug/DestinationValueInitializedByCtorBug.cs +++ b/src/UnitTests/Bug/DestinationValueInitializedByCtorBug.cs @@ -1,11 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using AutoMapper; -using AutoMapper.Internal.Mappers; -using Shouldly; -using Xunit; - namespace AutoMapper.UnitTests.Bug; public class DestinationValueInitializedByCtorBug : AutoMapperSpecBase diff --git a/src/UnitTests/Bug/DuplicateExtensionMethods.cs b/src/UnitTests/Bug/DuplicateExtensionMethods.cs index 052bf97ef5..77bf3c86d6 100644 --- a/src/UnitTests/Bug/DuplicateExtensionMethods.cs +++ b/src/UnitTests/Bug/DuplicateExtensionMethods.cs @@ -1,9 +1,4 @@ -using Xunit; -using Shouldly; -using System; -using System.Collections.Generic; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class DuplicateExtensionMethods : AutoMapperSpecBase { diff --git a/src/UnitTests/Bug/DuplicateValuesBug.cs b/src/UnitTests/Bug/DuplicateValuesBug.cs index cf009956b9..325a84e053 100644 --- a/src/UnitTests/Bug/DuplicateValuesBug.cs +++ b/src/UnitTests/Bug/DuplicateValuesBug.cs @@ -1,7 +1,3 @@ -using System.Collections.Generic; -using Xunit; -using Shouldly; - namespace AutoMapper.UnitTests.Bug { namespace DuplicateValuesBug diff --git a/src/UnitTests/Bug/DuplicateValuesBugWithoutPR.cs b/src/UnitTests/Bug/DuplicateValuesBugWithoutPR.cs index 64c42dbc3b..9f0fe19636 100644 --- a/src/UnitTests/Bug/DuplicateValuesBugWithoutPR.cs +++ b/src/UnitTests/Bug/DuplicateValuesBugWithoutPR.cs @@ -1,7 +1,3 @@ -using System.Collections.Generic; -using Xunit; -using Shouldly; - namespace AutoMapper.UnitTests.Bug; public class DuplicateValuesIssue diff --git a/src/UnitTests/Bug/EFCollections.cs b/src/UnitTests/Bug/EFCollections.cs index dda07596dc..589cad617d 100644 --- a/src/UnitTests/Bug/EFCollections.cs +++ b/src/UnitTests/Bug/EFCollections.cs @@ -1,10 +1,4 @@ -using System.Collections; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using Xunit; -using Shouldly; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class EFCollections : AutoMapperSpecBase { diff --git a/src/UnitTests/Bug/EmptyNullSubstituteBug.cs b/src/UnitTests/Bug/EmptyNullSubstituteBug.cs index bb96dab042..1172978525 100644 --- a/src/UnitTests/Bug/EmptyNullSubstituteBug.cs +++ b/src/UnitTests/Bug/EmptyNullSubstituteBug.cs @@ -1,8 +1,4 @@ namespace AutoMapper.UnitTests.Bug; - -using Shouldly; -using Xunit; - public class EmptyNullSubstituteBug : NonValidatingSpecBase { private Entity _destination; diff --git a/src/UnitTests/Bug/EnumCaseSensitivityBug.cs b/src/UnitTests/Bug/EnumCaseSensitivityBug.cs index 170f9fd09d..76aed3a4db 100644 --- a/src/UnitTests/Bug/EnumCaseSensitivityBug.cs +++ b/src/UnitTests/Bug/EnumCaseSensitivityBug.cs @@ -1,9 +1,4 @@ -using Shouldly; - -namespace AutoMapper.UnitTests.Bug; - -using Xunit; - +namespace AutoMapper.UnitTests.Bug; public class EnumCaseSensitivityBug : AutoMapperSpecBase { private SecondEnum _resultSecondEnum; diff --git a/src/UnitTests/Bug/EnumConditionsBug.cs b/src/UnitTests/Bug/EnumConditionsBug.cs index 64e3852249..a7eadc973d 100644 --- a/src/UnitTests/Bug/EnumConditionsBug.cs +++ b/src/UnitTests/Bug/EnumConditionsBug.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Shouldly; -using Xunit; - -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug { namespace EnumConditionsBug { diff --git a/src/UnitTests/Bug/EnumMatchingOnValue.cs b/src/UnitTests/Bug/EnumMatchingOnValue.cs index 8a3f9dff5a..f941fb69b2 100644 --- a/src/UnitTests/Bug/EnumMatchingOnValue.cs +++ b/src/UnitTests/Bug/EnumMatchingOnValue.cs @@ -1,6 +1,3 @@ -using Shouldly; -using Xunit; - namespace AutoMapper.UnitTests.Bug; public class EnumMatchingOnValue : AutoMapperSpecBase diff --git a/src/UnitTests/Bug/ExistingArrays.cs b/src/UnitTests/Bug/ExistingArrays.cs index 14d9620491..fcee4801b4 100644 --- a/src/UnitTests/Bug/ExistingArrays.cs +++ b/src/UnitTests/Bug/ExistingArrays.cs @@ -1,9 +1,4 @@ -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using Xunit; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class ExistingArrays : AutoMapperSpecBase { diff --git a/src/UnitTests/Bug/ForAllMembersAndDoNotUseDestinationValue.cs b/src/UnitTests/Bug/ForAllMembersAndDoNotUseDestinationValue.cs index 04897f3568..8110232eb4 100644 --- a/src/UnitTests/Bug/ForAllMembersAndDoNotUseDestinationValue.cs +++ b/src/UnitTests/Bug/ForAllMembersAndDoNotUseDestinationValue.cs @@ -1,8 +1,4 @@ -using Xunit; -using Shouldly; -using System; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class ForAllMembersAndResolveUsing : AutoMapperSpecBase { diff --git a/src/UnitTests/Bug/GenericCreateMapWithCircularReferences.cs b/src/UnitTests/Bug/GenericCreateMapWithCircularReferences.cs index e5c71a4899..8cf0bec394 100644 --- a/src/UnitTests/Bug/GenericCreateMapWithCircularReferences.cs +++ b/src/UnitTests/Bug/GenericCreateMapWithCircularReferences.cs @@ -1,8 +1,4 @@ -using System.Collections.Generic; -using AutoMapper.Internal.Mappers; -using Xunit; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class GenericCreateMapsWithCircularReference : AutoMapperSpecBase { diff --git a/src/UnitTests/Bug/GenericTypeConverter.cs b/src/UnitTests/Bug/GenericTypeConverter.cs index 2162f389a0..24bb91a9eb 100644 --- a/src/UnitTests/Bug/GenericTypeConverter.cs +++ b/src/UnitTests/Bug/GenericTypeConverter.cs @@ -1,11 +1,4 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using Shouldly; -using Xunit; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class GenericTypeConverterWithTwoArguments : AutoMapperSpecBase { diff --git a/src/UnitTests/Bug/GuidTryExpression.cs b/src/UnitTests/Bug/GuidTryExpression.cs index a9408e4454..12bc3f475e 100644 --- a/src/UnitTests/Bug/GuidTryExpression.cs +++ b/src/UnitTests/Bug/GuidTryExpression.cs @@ -1,8 +1,4 @@ -using Xunit; -using Shouldly; -using System; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class GuidTryExpression : AutoMapperSpecBase { diff --git a/src/UnitTests/Bug/IgnoreAll.cs b/src/UnitTests/Bug/IgnoreAll.cs index ea0d1ba266..c8fa47794a 100644 --- a/src/UnitTests/Bug/IgnoreAll.cs +++ b/src/UnitTests/Bug/IgnoreAll.cs @@ -1,9 +1,4 @@ -using Xunit; - namespace AutoMapper.UnitTests.Bug; - -using Shouldly; - public class When_configuring_all_members_and_some_do_not_match { public class ModelObjectNotMatching diff --git a/src/UnitTests/Bug/IncludeBaseInheritance.cs b/src/UnitTests/Bug/IncludeBaseInheritance.cs index a30bd56932..547c5f1af6 100644 --- a/src/UnitTests/Bug/IncludeBaseInheritance.cs +++ b/src/UnitTests/Bug/IncludeBaseInheritance.cs @@ -1,8 +1,4 @@ -using Xunit; -using Shouldly; -using System; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class IncludeBaseInheritance : AutoMapperSpecBase { diff --git a/src/UnitTests/Bug/IncludeInheritance.cs b/src/UnitTests/Bug/IncludeInheritance.cs index 0cd02c8774..4b50f659bd 100644 --- a/src/UnitTests/Bug/IncludeInheritance.cs +++ b/src/UnitTests/Bug/IncludeInheritance.cs @@ -1,8 +1,4 @@ -using Xunit; -using Shouldly; -using System; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class IncludeInheritance : AutoMapperSpecBase { diff --git a/src/UnitTests/Bug/InitializeNRE.cs b/src/UnitTests/Bug/InitializeNRE.cs index 524d286d32..45d8453a4d 100644 --- a/src/UnitTests/Bug/InitializeNRE.cs +++ b/src/UnitTests/Bug/InitializeNRE.cs @@ -1,9 +1,4 @@ -using Xunit; -using Shouldly; -using System; -using System.Collections.Generic; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class InitializeNRE2 : AutoMapperSpecBase { diff --git a/src/UnitTests/Bug/IntToNullableDecimal.cs b/src/UnitTests/Bug/IntToNullableDecimal.cs index d0f673df8e..cbe87ae149 100644 --- a/src/UnitTests/Bug/IntToNullableDecimal.cs +++ b/src/UnitTests/Bug/IntToNullableDecimal.cs @@ -1,8 +1,4 @@ -using Xunit; -using Shouldly; -using System; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class IntToNullableDecimal : AutoMapperSpecBase { diff --git a/src/UnitTests/Bug/InterfaceMultipleInheritance.cs b/src/UnitTests/Bug/InterfaceMultipleInheritance.cs index ddc4110b25..be5b4803ff 100644 --- a/src/UnitTests/Bug/InterfaceMultipleInheritance.cs +++ b/src/UnitTests/Bug/InterfaceMultipleInheritance.cs @@ -1,7 +1,3 @@ -using System; -using Shouldly; -using Xunit; - namespace AutoMapper.UnitTests.Bug { namespace InterfaceMultipleInheritance diff --git a/src/UnitTests/Bug/InterfaceSelfMappingBug.cs b/src/UnitTests/Bug/InterfaceSelfMappingBug.cs index c86733010d..6328358b2f 100644 --- a/src/UnitTests/Bug/InterfaceSelfMappingBug.cs +++ b/src/UnitTests/Bug/InterfaceSelfMappingBug.cs @@ -1,7 +1,4 @@ -using Xunit; -using Shouldly; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class InterfaceSelfMappingBug { diff --git a/src/UnitTests/Bug/InternalProperties.cs b/src/UnitTests/Bug/InternalProperties.cs index 728bd89457..b07109930b 100644 --- a/src/UnitTests/Bug/InternalProperties.cs +++ b/src/UnitTests/Bug/InternalProperties.cs @@ -1,8 +1,4 @@ -using Xunit; -using Shouldly; -using System; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class InternalProperties : AutoMapperSpecBase { diff --git a/src/UnitTests/Bug/JsonNet.cs b/src/UnitTests/Bug/JsonNet.cs index c5d1511891..b1c7606c5b 100644 --- a/src/UnitTests/Bug/JsonNet.cs +++ b/src/UnitTests/Bug/JsonNet.cs @@ -1,11 +1,4 @@ -using Xunit; -using Shouldly; -using System; -using System.Linq; -using System.Collections; -using System.Collections.Generic; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; using StringKeyValuePair = KeyValuePair; diff --git a/src/UnitTests/Bug/LazyCollectionMapping.cs b/src/UnitTests/Bug/LazyCollectionMapping.cs index 0d08cc5345..a48aa7ae75 100644 --- a/src/UnitTests/Bug/LazyCollectionMapping.cs +++ b/src/UnitTests/Bug/LazyCollectionMapping.cs @@ -1,11 +1,4 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using Shouldly; -using Xunit; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class LazyCollectionMapping { diff --git a/src/UnitTests/Bug/ListSourceMapperBug.cs b/src/UnitTests/Bug/ListSourceMapperBug.cs index d30f8f3adc..930cfd628b 100644 --- a/src/UnitTests/Bug/ListSourceMapperBug.cs +++ b/src/UnitTests/Bug/ListSourceMapperBug.cs @@ -1,13 +1,4 @@ namespace AutoMapper.UnitTests.Bug; - -using System; -using System.Collections; -using System.Collections.ObjectModel; -using System.ComponentModel; -using System.Linq; -using Shouldly; -using Xunit; - public class ListSourceMapperBug { public class CustomCollection : Collection, IListSource diff --git a/src/UnitTests/Bug/MapAtRuntime/BaseEntity.cs b/src/UnitTests/Bug/MapAtRuntime/BaseEntity.cs index 4645e62803..20fe76afbf 100644 --- a/src/UnitTests/Bug/MapAtRuntime/BaseEntity.cs +++ b/src/UnitTests/Bug/MapAtRuntime/BaseEntity.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDatabaseModel3; +namespace OmmitedDatabaseModel3; public class BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntime/BaseEntityDTO.cs b/src/UnitTests/Bug/MapAtRuntime/BaseEntityDTO.cs index 1c9ecc31d6..6d4b9d5959 100644 --- a/src/UnitTests/Bug/MapAtRuntime/BaseEntityDTO.cs +++ b/src/UnitTests/Bug/MapAtRuntime/BaseEntityDTO.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDTOModel3; +namespace OmmitedDTOModel3; public class BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntime/Entity1.cs b/src/UnitTests/Bug/MapAtRuntime/Entity1.cs index 246f0d30a2..c2311a643c 100644 --- a/src/UnitTests/Bug/MapAtRuntime/Entity1.cs +++ b/src/UnitTests/Bug/MapAtRuntime/Entity1.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDatabaseModel3; +namespace OmmitedDatabaseModel3; public class Entity1 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntime/Entity10.cs b/src/UnitTests/Bug/MapAtRuntime/Entity10.cs index 0c9a0a6105..42baa0a326 100644 --- a/src/UnitTests/Bug/MapAtRuntime/Entity10.cs +++ b/src/UnitTests/Bug/MapAtRuntime/Entity10.cs @@ -1,6 +1,4 @@ -using System.Collections.Generic; - -namespace OmmitedDatabaseModel3; +namespace OmmitedDatabaseModel3; public class Entity10 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntime/Entity11.cs b/src/UnitTests/Bug/MapAtRuntime/Entity11.cs index 194b6cb1fe..bbf5d2acef 100644 --- a/src/UnitTests/Bug/MapAtRuntime/Entity11.cs +++ b/src/UnitTests/Bug/MapAtRuntime/Entity11.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDatabaseModel3; +namespace OmmitedDatabaseModel3; public class Entity11 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntime/Entity12.cs b/src/UnitTests/Bug/MapAtRuntime/Entity12.cs index 76f357cb9b..6a1b461496 100644 --- a/src/UnitTests/Bug/MapAtRuntime/Entity12.cs +++ b/src/UnitTests/Bug/MapAtRuntime/Entity12.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDatabaseModel3; +namespace OmmitedDatabaseModel3; public class Entity12 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntime/Entity13.cs b/src/UnitTests/Bug/MapAtRuntime/Entity13.cs index 9f8bd9aaea..bbae3a964f 100644 --- a/src/UnitTests/Bug/MapAtRuntime/Entity13.cs +++ b/src/UnitTests/Bug/MapAtRuntime/Entity13.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDatabaseModel3; +namespace OmmitedDatabaseModel3; public class Entity13 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntime/Entity14.cs b/src/UnitTests/Bug/MapAtRuntime/Entity14.cs index e0644551de..074ec19f2c 100644 --- a/src/UnitTests/Bug/MapAtRuntime/Entity14.cs +++ b/src/UnitTests/Bug/MapAtRuntime/Entity14.cs @@ -1,11 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.Serialization; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDatabaseModel3; +namespace OmmitedDatabaseModel3; public class Entity14 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntime/Entity15.cs b/src/UnitTests/Bug/MapAtRuntime/Entity15.cs index 17ba3d94db..7a60ec7c12 100644 --- a/src/UnitTests/Bug/MapAtRuntime/Entity15.cs +++ b/src/UnitTests/Bug/MapAtRuntime/Entity15.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDatabaseModel3; +namespace OmmitedDatabaseModel3; public class Entity15 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntime/Entity16.cs b/src/UnitTests/Bug/MapAtRuntime/Entity16.cs index 5c42e375b1..7517e155d8 100644 --- a/src/UnitTests/Bug/MapAtRuntime/Entity16.cs +++ b/src/UnitTests/Bug/MapAtRuntime/Entity16.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDatabaseModel3; +namespace OmmitedDatabaseModel3; public class Entity16 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntime/Entity17.cs b/src/UnitTests/Bug/MapAtRuntime/Entity17.cs index 2e705582d2..3020940781 100644 --- a/src/UnitTests/Bug/MapAtRuntime/Entity17.cs +++ b/src/UnitTests/Bug/MapAtRuntime/Entity17.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDatabaseModel3; +namespace OmmitedDatabaseModel3; public class Entity17 :BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntime/Entity18.cs b/src/UnitTests/Bug/MapAtRuntime/Entity18.cs index b631d40505..e10eca5932 100644 --- a/src/UnitTests/Bug/MapAtRuntime/Entity18.cs +++ b/src/UnitTests/Bug/MapAtRuntime/Entity18.cs @@ -1,6 +1,4 @@ -using System; - -namespace OmmitedDatabaseModel3; +namespace OmmitedDatabaseModel3; public class Entity18 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntime/Entity19.cs b/src/UnitTests/Bug/MapAtRuntime/Entity19.cs index dd212257c1..3ca88a3f35 100644 --- a/src/UnitTests/Bug/MapAtRuntime/Entity19.cs +++ b/src/UnitTests/Bug/MapAtRuntime/Entity19.cs @@ -1,6 +1,4 @@ -using System; - -namespace OmmitedDatabaseModel3; +namespace OmmitedDatabaseModel3; public class Entity19 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntime/Entity2.cs b/src/UnitTests/Bug/MapAtRuntime/Entity2.cs index debd55e149..afa0ca73da 100644 --- a/src/UnitTests/Bug/MapAtRuntime/Entity2.cs +++ b/src/UnitTests/Bug/MapAtRuntime/Entity2.cs @@ -1,6 +1,4 @@ -using System; - -namespace OmmitedDatabaseModel3; +namespace OmmitedDatabaseModel3; public class Entity2 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntime/Entity20.cs b/src/UnitTests/Bug/MapAtRuntime/Entity20.cs index f309c0c208..048b9daa3e 100644 --- a/src/UnitTests/Bug/MapAtRuntime/Entity20.cs +++ b/src/UnitTests/Bug/MapAtRuntime/Entity20.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDatabaseModel3; +namespace OmmitedDatabaseModel3; public class Entity20 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntime/Entity21.cs b/src/UnitTests/Bug/MapAtRuntime/Entity21.cs index f612924518..41cde5c741 100644 --- a/src/UnitTests/Bug/MapAtRuntime/Entity21.cs +++ b/src/UnitTests/Bug/MapAtRuntime/Entity21.cs @@ -1,6 +1,4 @@ -using System; - -namespace OmmitedDatabaseModel3; +namespace OmmitedDatabaseModel3; public class Entity21 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntime/Entity22.cs b/src/UnitTests/Bug/MapAtRuntime/Entity22.cs index ea126f326b..ff14e00431 100644 --- a/src/UnitTests/Bug/MapAtRuntime/Entity22.cs +++ b/src/UnitTests/Bug/MapAtRuntime/Entity22.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDatabaseModel3; +namespace OmmitedDatabaseModel3; public class Entity22 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntime/Entity23.cs b/src/UnitTests/Bug/MapAtRuntime/Entity23.cs index 6f37dfe3a6..3ae615a698 100644 --- a/src/UnitTests/Bug/MapAtRuntime/Entity23.cs +++ b/src/UnitTests/Bug/MapAtRuntime/Entity23.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDatabaseModel3; +namespace OmmitedDatabaseModel3; public class Entity23 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntime/Entity24.cs b/src/UnitTests/Bug/MapAtRuntime/Entity24.cs index 3ff3b620e7..e6660019ad 100644 --- a/src/UnitTests/Bug/MapAtRuntime/Entity24.cs +++ b/src/UnitTests/Bug/MapAtRuntime/Entity24.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDatabaseModel3; +namespace OmmitedDatabaseModel3; public class Entity24 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntime/Entity25.cs b/src/UnitTests/Bug/MapAtRuntime/Entity25.cs index 13ec088fb6..cfc73ea2db 100644 --- a/src/UnitTests/Bug/MapAtRuntime/Entity25.cs +++ b/src/UnitTests/Bug/MapAtRuntime/Entity25.cs @@ -1,11 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.Serialization; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDatabaseModel3; +namespace OmmitedDatabaseModel3; public class Entity25 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntime/Entity26.cs b/src/UnitTests/Bug/MapAtRuntime/Entity26.cs index 3a3d62f2e4..3b6f34a266 100644 --- a/src/UnitTests/Bug/MapAtRuntime/Entity26.cs +++ b/src/UnitTests/Bug/MapAtRuntime/Entity26.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDatabaseModel3; +namespace OmmitedDatabaseModel3; public class Entity26 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntime/Entity3.cs b/src/UnitTests/Bug/MapAtRuntime/Entity3.cs index 7573f40f1e..27f487df79 100644 --- a/src/UnitTests/Bug/MapAtRuntime/Entity3.cs +++ b/src/UnitTests/Bug/MapAtRuntime/Entity3.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDatabaseModel3; +namespace OmmitedDatabaseModel3; public class Entity3 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntime/Entity4.cs b/src/UnitTests/Bug/MapAtRuntime/Entity4.cs index 66d71ff4fa..8b1d9fe96a 100644 --- a/src/UnitTests/Bug/MapAtRuntime/Entity4.cs +++ b/src/UnitTests/Bug/MapAtRuntime/Entity4.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDatabaseModel3; +namespace OmmitedDatabaseModel3; public class Entity4 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntime/Entity5.cs b/src/UnitTests/Bug/MapAtRuntime/Entity5.cs index 493febcdfb..5016c46099 100644 --- a/src/UnitTests/Bug/MapAtRuntime/Entity5.cs +++ b/src/UnitTests/Bug/MapAtRuntime/Entity5.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDatabaseModel3; +namespace OmmitedDatabaseModel3; public class Entity5 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntime/Entity6.cs b/src/UnitTests/Bug/MapAtRuntime/Entity6.cs index 4c4b383d52..fa43286c01 100644 --- a/src/UnitTests/Bug/MapAtRuntime/Entity6.cs +++ b/src/UnitTests/Bug/MapAtRuntime/Entity6.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDatabaseModel3; +namespace OmmitedDatabaseModel3; public class Entity6 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntime/Entity7.cs b/src/UnitTests/Bug/MapAtRuntime/Entity7.cs index 208f3627ba..eb5b8f2542 100644 --- a/src/UnitTests/Bug/MapAtRuntime/Entity7.cs +++ b/src/UnitTests/Bug/MapAtRuntime/Entity7.cs @@ -1,6 +1,4 @@ -using System; - -namespace OmmitedDatabaseModel3; +namespace OmmitedDatabaseModel3; public class Entity7 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntime/Entity8.cs b/src/UnitTests/Bug/MapAtRuntime/Entity8.cs index dab0b27ce2..8a114cb12c 100644 --- a/src/UnitTests/Bug/MapAtRuntime/Entity8.cs +++ b/src/UnitTests/Bug/MapAtRuntime/Entity8.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDatabaseModel3; +namespace OmmitedDatabaseModel3; public class Entity8 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntime/Entity9.cs b/src/UnitTests/Bug/MapAtRuntime/Entity9.cs index ed5f9d7c93..dd5ad31600 100644 --- a/src/UnitTests/Bug/MapAtRuntime/Entity9.cs +++ b/src/UnitTests/Bug/MapAtRuntime/Entity9.cs @@ -1,6 +1,4 @@ -using System; - -namespace OmmitedDatabaseModel3; +namespace OmmitedDatabaseModel3; public class Entity9 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntime/EntityDTO1.cs b/src/UnitTests/Bug/MapAtRuntime/EntityDTO1.cs index 5dae37ac76..8ee6b4d01d 100644 --- a/src/UnitTests/Bug/MapAtRuntime/EntityDTO1.cs +++ b/src/UnitTests/Bug/MapAtRuntime/EntityDTO1.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDTOModel3; +namespace OmmitedDTOModel3; public class EntityDTO1 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntime/EntityDTO10.cs b/src/UnitTests/Bug/MapAtRuntime/EntityDTO10.cs index b16c61e597..e796772b2f 100644 --- a/src/UnitTests/Bug/MapAtRuntime/EntityDTO10.cs +++ b/src/UnitTests/Bug/MapAtRuntime/EntityDTO10.cs @@ -1,6 +1,4 @@ -using System.Collections.Generic; - -namespace OmmitedDTOModel3; +namespace OmmitedDTOModel3; public class EntityDTO10 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntime/EntityDTO11.cs b/src/UnitTests/Bug/MapAtRuntime/EntityDTO11.cs index 8073590d7b..2fb78c7294 100644 --- a/src/UnitTests/Bug/MapAtRuntime/EntityDTO11.cs +++ b/src/UnitTests/Bug/MapAtRuntime/EntityDTO11.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDTOModel3; +namespace OmmitedDTOModel3; public class EntityDTO11 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntime/EntityDTO12.cs b/src/UnitTests/Bug/MapAtRuntime/EntityDTO12.cs index 6d9b1f72e5..984ced7f47 100644 --- a/src/UnitTests/Bug/MapAtRuntime/EntityDTO12.cs +++ b/src/UnitTests/Bug/MapAtRuntime/EntityDTO12.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDTOModel3; +namespace OmmitedDTOModel3; public class EntityDTO12 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntime/EntityDTO13.cs b/src/UnitTests/Bug/MapAtRuntime/EntityDTO13.cs index e97f1cc60d..0f2bd62e24 100644 --- a/src/UnitTests/Bug/MapAtRuntime/EntityDTO13.cs +++ b/src/UnitTests/Bug/MapAtRuntime/EntityDTO13.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDTOModel3; +namespace OmmitedDTOModel3; public class EntityDTO13 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntime/EntityDTO14.cs b/src/UnitTests/Bug/MapAtRuntime/EntityDTO14.cs index 2c784e5cf2..21fe03c5a2 100644 --- a/src/UnitTests/Bug/MapAtRuntime/EntityDTO14.cs +++ b/src/UnitTests/Bug/MapAtRuntime/EntityDTO14.cs @@ -1,11 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.Serialization; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDTOModel3; +namespace OmmitedDTOModel3; public class EntityDTO14 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntime/EntityDTO15.cs b/src/UnitTests/Bug/MapAtRuntime/EntityDTO15.cs index ee2f109b3e..13082e03df 100644 --- a/src/UnitTests/Bug/MapAtRuntime/EntityDTO15.cs +++ b/src/UnitTests/Bug/MapAtRuntime/EntityDTO15.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDTOModel3; +namespace OmmitedDTOModel3; public class EntityDTO15 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntime/EntityDTO16.cs b/src/UnitTests/Bug/MapAtRuntime/EntityDTO16.cs index d25960ce7d..66ea63dc4e 100644 --- a/src/UnitTests/Bug/MapAtRuntime/EntityDTO16.cs +++ b/src/UnitTests/Bug/MapAtRuntime/EntityDTO16.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDTOModel3; +namespace OmmitedDTOModel3; public class EntityDTO16 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntime/EntityDTO17.cs b/src/UnitTests/Bug/MapAtRuntime/EntityDTO17.cs index 71b2d663c7..8d0546ccaf 100644 --- a/src/UnitTests/Bug/MapAtRuntime/EntityDTO17.cs +++ b/src/UnitTests/Bug/MapAtRuntime/EntityDTO17.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDTOModel3; +namespace OmmitedDTOModel3; public class EntityDTO17 :BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntime/EntityDTO18.cs b/src/UnitTests/Bug/MapAtRuntime/EntityDTO18.cs index 8f46d2c99e..8fba309a11 100644 --- a/src/UnitTests/Bug/MapAtRuntime/EntityDTO18.cs +++ b/src/UnitTests/Bug/MapAtRuntime/EntityDTO18.cs @@ -1,6 +1,4 @@ -using System; - -namespace OmmitedDTOModel3; +namespace OmmitedDTOModel3; public class EntityDTO18 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntime/EntityDTO19.cs b/src/UnitTests/Bug/MapAtRuntime/EntityDTO19.cs index 0d6ad28b33..37f5325136 100644 --- a/src/UnitTests/Bug/MapAtRuntime/EntityDTO19.cs +++ b/src/UnitTests/Bug/MapAtRuntime/EntityDTO19.cs @@ -1,6 +1,4 @@ -using System; - -namespace OmmitedDTOModel3; +namespace OmmitedDTOModel3; public class EntityDTO19 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntime/EntityDTO2.cs b/src/UnitTests/Bug/MapAtRuntime/EntityDTO2.cs index 792edf2ced..4bfcd5f0ca 100644 --- a/src/UnitTests/Bug/MapAtRuntime/EntityDTO2.cs +++ b/src/UnitTests/Bug/MapAtRuntime/EntityDTO2.cs @@ -1,6 +1,4 @@ -using System; - -namespace OmmitedDTOModel3; +namespace OmmitedDTOModel3; public class EntityDTO2 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntime/EntityDTO20.cs b/src/UnitTests/Bug/MapAtRuntime/EntityDTO20.cs index 73c780841f..18cdb3d49f 100644 --- a/src/UnitTests/Bug/MapAtRuntime/EntityDTO20.cs +++ b/src/UnitTests/Bug/MapAtRuntime/EntityDTO20.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDTOModel3; +namespace OmmitedDTOModel3; public class EntityDTO20 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntime/EntityDTO21.cs b/src/UnitTests/Bug/MapAtRuntime/EntityDTO21.cs index 64adb09fcb..ca4834968d 100644 --- a/src/UnitTests/Bug/MapAtRuntime/EntityDTO21.cs +++ b/src/UnitTests/Bug/MapAtRuntime/EntityDTO21.cs @@ -1,6 +1,4 @@ -using System; - -namespace OmmitedDTOModel3; +namespace OmmitedDTOModel3; public class EntityDTO21 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntime/EntityDTO22.cs b/src/UnitTests/Bug/MapAtRuntime/EntityDTO22.cs index dfda959791..6102dc392b 100644 --- a/src/UnitTests/Bug/MapAtRuntime/EntityDTO22.cs +++ b/src/UnitTests/Bug/MapAtRuntime/EntityDTO22.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDTOModel3; +namespace OmmitedDTOModel3; public class EntityDTO22 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntime/EntityDTO23.cs b/src/UnitTests/Bug/MapAtRuntime/EntityDTO23.cs index e0a267aba7..dd8ea22d27 100644 --- a/src/UnitTests/Bug/MapAtRuntime/EntityDTO23.cs +++ b/src/UnitTests/Bug/MapAtRuntime/EntityDTO23.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDTOModel3; +namespace OmmitedDTOModel3; public class EntityDTO23 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntime/EntityDTO24.cs b/src/UnitTests/Bug/MapAtRuntime/EntityDTO24.cs index f2eb19c33b..388967b0ac 100644 --- a/src/UnitTests/Bug/MapAtRuntime/EntityDTO24.cs +++ b/src/UnitTests/Bug/MapAtRuntime/EntityDTO24.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDTOModel3; +namespace OmmitedDTOModel3; public class EntityDTO24 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntime/EntityDTO25.cs b/src/UnitTests/Bug/MapAtRuntime/EntityDTO25.cs index 93f33568f1..9fed991c1c 100644 --- a/src/UnitTests/Bug/MapAtRuntime/EntityDTO25.cs +++ b/src/UnitTests/Bug/MapAtRuntime/EntityDTO25.cs @@ -1,11 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.Serialization; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDTOModel3; +namespace OmmitedDTOModel3; public class EntityDTO25 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntime/EntityDTO26.cs b/src/UnitTests/Bug/MapAtRuntime/EntityDTO26.cs index de5284b4e6..e489cafb4b 100644 --- a/src/UnitTests/Bug/MapAtRuntime/EntityDTO26.cs +++ b/src/UnitTests/Bug/MapAtRuntime/EntityDTO26.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDTOModel3; +namespace OmmitedDTOModel3; public class EntityDTO26 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntime/EntityDTO3.cs b/src/UnitTests/Bug/MapAtRuntime/EntityDTO3.cs index 4b454d1b97..036b9fbe7d 100644 --- a/src/UnitTests/Bug/MapAtRuntime/EntityDTO3.cs +++ b/src/UnitTests/Bug/MapAtRuntime/EntityDTO3.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDTOModel3; +namespace OmmitedDTOModel3; public class EntityDTO3 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntime/EntityDTO4.cs b/src/UnitTests/Bug/MapAtRuntime/EntityDTO4.cs index 3e94ad513c..3e00fe5078 100644 --- a/src/UnitTests/Bug/MapAtRuntime/EntityDTO4.cs +++ b/src/UnitTests/Bug/MapAtRuntime/EntityDTO4.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDTOModel3; +namespace OmmitedDTOModel3; public class EntityDTO4 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntime/EntityDTO5.cs b/src/UnitTests/Bug/MapAtRuntime/EntityDTO5.cs index 719de1c67a..0aa826f31a 100644 --- a/src/UnitTests/Bug/MapAtRuntime/EntityDTO5.cs +++ b/src/UnitTests/Bug/MapAtRuntime/EntityDTO5.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDTOModel3; +namespace OmmitedDTOModel3; public class EntityDTO5 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntime/EntityDTO6.cs b/src/UnitTests/Bug/MapAtRuntime/EntityDTO6.cs index 9f9f5c8917..20b3c265f5 100644 --- a/src/UnitTests/Bug/MapAtRuntime/EntityDTO6.cs +++ b/src/UnitTests/Bug/MapAtRuntime/EntityDTO6.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDTOModel3; +namespace OmmitedDTOModel3; public class EntityDTO6 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntime/EntityDTO7.cs b/src/UnitTests/Bug/MapAtRuntime/EntityDTO7.cs index 05b32e4af8..173da90ad1 100644 --- a/src/UnitTests/Bug/MapAtRuntime/EntityDTO7.cs +++ b/src/UnitTests/Bug/MapAtRuntime/EntityDTO7.cs @@ -1,6 +1,4 @@ -using System; - -namespace OmmitedDTOModel3; +namespace OmmitedDTOModel3; public class EntityDTO7 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntime/EntityDTO8.cs b/src/UnitTests/Bug/MapAtRuntime/EntityDTO8.cs index 0bafd01b31..e13bac4ca6 100644 --- a/src/UnitTests/Bug/MapAtRuntime/EntityDTO8.cs +++ b/src/UnitTests/Bug/MapAtRuntime/EntityDTO8.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDTOModel3; +namespace OmmitedDTOModel3; public class EntityDTO8 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntime/EntityDTO9.cs b/src/UnitTests/Bug/MapAtRuntime/EntityDTO9.cs index 804aa77754..d4b94e863f 100644 --- a/src/UnitTests/Bug/MapAtRuntime/EntityDTO9.cs +++ b/src/UnitTests/Bug/MapAtRuntime/EntityDTO9.cs @@ -1,6 +1,4 @@ -using System; - -namespace OmmitedDTOModel3; +namespace OmmitedDTOModel3; public class EntityDTO9 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntime/MapAtRuntime.cs b/src/UnitTests/Bug/MapAtRuntime/MapAtRuntime.cs index 9371e1ce46..519e7688e2 100644 --- a/src/UnitTests/Bug/MapAtRuntime/MapAtRuntime.cs +++ b/src/UnitTests/Bug/MapAtRuntime/MapAtRuntime.cs @@ -1,8 +1,5 @@ -using System; -using System.Collections.Generic; -using OmmitedDatabaseModel3; +using OmmitedDatabaseModel3; using OmmitedDTOModel3; -using Xunit; namespace AutoMapper.UnitTests; diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/BaseEntity.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/BaseEntity.cs index c8336aa155..5d0cc97394 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/BaseEntity.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/BaseEntity.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDatabaseModel3WithCollections; +namespace OmmitedDatabaseModel3WithCollections; public class BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/BaseEntityDTO.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/BaseEntityDTO.cs index 1d66765d10..5d083c0e29 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/BaseEntityDTO.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/BaseEntityDTO.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDTOModel3WithCollections; +namespace OmmitedDTOModel3WithCollections; public class BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity1.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity1.cs index b0324ddb29..1a189d24d6 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity1.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity1.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDatabaseModel3WithCollections; +namespace OmmitedDatabaseModel3WithCollections; public class Entity1 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity10.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity10.cs index 6f864c6521..4e1d7785c0 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity10.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity10.cs @@ -1,6 +1,4 @@ -using System.Collections.Generic; - -namespace OmmitedDatabaseModel3WithCollections; +namespace OmmitedDatabaseModel3WithCollections; public class Entity10 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity11.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity11.cs index 390512ff61..bf97e0f8e3 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity11.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity11.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDatabaseModel3WithCollections; +namespace OmmitedDatabaseModel3WithCollections; public class Entity11 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity12.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity12.cs index d490c80c3c..df67370706 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity12.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity12.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDatabaseModel3WithCollections; +namespace OmmitedDatabaseModel3WithCollections; public class Entity12 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity13.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity13.cs index 6843010126..e53804dcfb 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity13.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity13.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDatabaseModel3WithCollections; +namespace OmmitedDatabaseModel3WithCollections; public class Entity13 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity14.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity14.cs index 34404f3ac8..2432ffb8a1 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity14.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity14.cs @@ -1,11 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.Serialization; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDatabaseModel3WithCollections; +namespace OmmitedDatabaseModel3WithCollections; public class Entity14 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity15.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity15.cs index 853f0aae06..607b5d39c1 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity15.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity15.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDatabaseModel3WithCollections; +namespace OmmitedDatabaseModel3WithCollections; public class Entity15 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity16.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity16.cs index f4a7ae97c5..8365d07b38 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity16.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity16.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDatabaseModel3WithCollections; +namespace OmmitedDatabaseModel3WithCollections; public class Entity16 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity17.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity17.cs index a1fdd87b27..b8de38a5bd 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity17.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity17.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDatabaseModel3WithCollections; +namespace OmmitedDatabaseModel3WithCollections; public class Entity17 :BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity18.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity18.cs index 457b4864cb..3376eee43c 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity18.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity18.cs @@ -1,6 +1,4 @@ -using System; - -namespace OmmitedDatabaseModel3WithCollections; +namespace OmmitedDatabaseModel3WithCollections; public class Entity18 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity19.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity19.cs index 77a91678f0..d431011b3a 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity19.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity19.cs @@ -1,6 +1,4 @@ -using System; - -namespace OmmitedDatabaseModel3WithCollections; +namespace OmmitedDatabaseModel3WithCollections; public class Entity19 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity2.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity2.cs index 4f613d2685..8b27ff0fea 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity2.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity2.cs @@ -1,6 +1,4 @@ -using System; - -namespace OmmitedDatabaseModel3WithCollections; +namespace OmmitedDatabaseModel3WithCollections; public class Entity2 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity20.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity20.cs index 5d75810f16..0347d0f7be 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity20.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity20.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDatabaseModel3WithCollections; +namespace OmmitedDatabaseModel3WithCollections; public class Entity20 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity21.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity21.cs index c014799a43..793b580115 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity21.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity21.cs @@ -1,6 +1,4 @@ -using System; - -namespace OmmitedDatabaseModel3WithCollections; +namespace OmmitedDatabaseModel3WithCollections; public class Entity21 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity22.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity22.cs index 8fa7ebe109..7f5a4aa13c 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity22.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity22.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDatabaseModel3WithCollections; +namespace OmmitedDatabaseModel3WithCollections; public class Entity22 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity23.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity23.cs index 0247fcda7f..989eaa7f25 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity23.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity23.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDatabaseModel3WithCollections; +namespace OmmitedDatabaseModel3WithCollections; public class Entity23 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity24.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity24.cs index 0450397785..b96f461aec 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity24.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity24.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDatabaseModel3WithCollections; +namespace OmmitedDatabaseModel3WithCollections; public class Entity24 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity25.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity25.cs index f14c91ec7a..3e574e3d3a 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity25.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity25.cs @@ -1,11 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.Serialization; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDatabaseModel3WithCollections; +namespace OmmitedDatabaseModel3WithCollections; public class Entity25 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity26.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity26.cs index 217d6a2ac4..d9c54d960b 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity26.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity26.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDatabaseModel3WithCollections; +namespace OmmitedDatabaseModel3WithCollections; public class Entity26 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity3.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity3.cs index 8928c7edcf..f88a5003fa 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity3.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity3.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDatabaseModel3WithCollections; +namespace OmmitedDatabaseModel3WithCollections; public class Entity3 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity4.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity4.cs index 4461c11380..778bb28a08 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity4.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity4.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDatabaseModel3WithCollections; +namespace OmmitedDatabaseModel3WithCollections; public class Entity4 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity5.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity5.cs index 61fb742a7a..affdd0722f 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity5.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity5.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDatabaseModel3WithCollections; +namespace OmmitedDatabaseModel3WithCollections; public class Entity5 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity6.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity6.cs index 2243e199a1..220f8ae7a0 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity6.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity6.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDatabaseModel3WithCollections; +namespace OmmitedDatabaseModel3WithCollections; public class Entity6 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity7.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity7.cs index b202c329a6..89fef7c117 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity7.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity7.cs @@ -1,6 +1,4 @@ -using System; - -namespace OmmitedDatabaseModel3WithCollections; +namespace OmmitedDatabaseModel3WithCollections; public class Entity7 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity8.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity8.cs index 7821a568e8..b03fb15363 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity8.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity8.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDatabaseModel3WithCollections; +namespace OmmitedDatabaseModel3WithCollections; public class Entity8 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity9.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity9.cs index dcae61ea4e..de67420a72 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity9.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/Entity9.cs @@ -1,6 +1,4 @@ -using System; - -namespace OmmitedDatabaseModel3WithCollections; +namespace OmmitedDatabaseModel3WithCollections; public class Entity9 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO1.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO1.cs index f09571b68e..01ba560fb6 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO1.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO1.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDTOModel3WithCollections; +namespace OmmitedDTOModel3WithCollections; public class EntityDTO1 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO10.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO10.cs index 44244cc43a..86e20b38a2 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO10.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO10.cs @@ -1,6 +1,4 @@ -using System.Collections.Generic; - -namespace OmmitedDTOModel3WithCollections; +namespace OmmitedDTOModel3WithCollections; public class EntityDTO10 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO11.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO11.cs index f6c5555bd9..2e3bbb18b7 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO11.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO11.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDTOModel3WithCollections; +namespace OmmitedDTOModel3WithCollections; public class EntityDTO11 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO12.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO12.cs index c246cd0e07..1e0f0856fa 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO12.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO12.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDTOModel3WithCollections; +namespace OmmitedDTOModel3WithCollections; public class EntityDTO12 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO13.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO13.cs index cbebb5abf6..abb0ab72af 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO13.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO13.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDTOModel3WithCollections; +namespace OmmitedDTOModel3WithCollections; public class EntityDTO13 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO14.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO14.cs index 6bfe3d4c18..a0c7b88761 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO14.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO14.cs @@ -1,11 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.Serialization; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDTOModel3WithCollections; +namespace OmmitedDTOModel3WithCollections; public class EntityDTO14 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO15.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO15.cs index 08df8bd252..ada9c09ef3 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO15.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO15.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDTOModel3WithCollections; +namespace OmmitedDTOModel3WithCollections; public class EntityDTO15 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO16.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO16.cs index c0b1329728..509441e4b9 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO16.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO16.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDTOModel3WithCollections; +namespace OmmitedDTOModel3WithCollections; public class EntityDTO16 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO17.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO17.cs index 2d4758121b..077040b725 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO17.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO17.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDTOModel3WithCollections; +namespace OmmitedDTOModel3WithCollections; public class EntityDTO17 :BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO18.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO18.cs index 9b2c875b1b..c033620ad8 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO18.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO18.cs @@ -1,6 +1,4 @@ -using System; - -namespace OmmitedDTOModel3WithCollections; +namespace OmmitedDTOModel3WithCollections; public class EntityDTO18 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO19.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO19.cs index 62452e666e..522a938318 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO19.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO19.cs @@ -1,6 +1,4 @@ -using System; - -namespace OmmitedDTOModel3WithCollections; +namespace OmmitedDTOModel3WithCollections; public class EntityDTO19 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO2.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO2.cs index c8353a33f7..f6f895d34f 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO2.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO2.cs @@ -1,6 +1,4 @@ -using System; - -namespace OmmitedDTOModel3WithCollections; +namespace OmmitedDTOModel3WithCollections; public class EntityDTO2 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO20.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO20.cs index e5f0989991..ff62f3e939 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO20.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO20.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDTOModel3WithCollections; +namespace OmmitedDTOModel3WithCollections; public class EntityDTO20 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO21.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO21.cs index 039b512cd8..1930b28130 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO21.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO21.cs @@ -1,6 +1,4 @@ -using System; - -namespace OmmitedDTOModel3WithCollections; +namespace OmmitedDTOModel3WithCollections; public class EntityDTO21 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO22.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO22.cs index 1864ae00fb..593998a83f 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO22.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO22.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDTOModel3WithCollections; +namespace OmmitedDTOModel3WithCollections; public class EntityDTO22 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO23.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO23.cs index 4747db899b..3334e7433b 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO23.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO23.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDTOModel3WithCollections; +namespace OmmitedDTOModel3WithCollections; public class EntityDTO23 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO24.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO24.cs index f890f92c28..f93581078d 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO24.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO24.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDTOModel3WithCollections; +namespace OmmitedDTOModel3WithCollections; public class EntityDTO24 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO25.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO25.cs index 01f1708fa2..cd976c7ffb 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO25.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO25.cs @@ -1,11 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.Serialization; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDTOModel3WithCollections; +namespace OmmitedDTOModel3WithCollections; public class EntityDTO25 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO26.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO26.cs index f96868a675..51db91ec9c 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO26.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO26.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDTOModel3WithCollections; +namespace OmmitedDTOModel3WithCollections; public class EntityDTO26 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO3.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO3.cs index dbb77257c9..eda82957bb 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO3.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO3.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDTOModel3WithCollections; +namespace OmmitedDTOModel3WithCollections; public class EntityDTO3 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO4.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO4.cs index 8fb3dc9a54..af0aa9c291 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO4.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO4.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDTOModel3WithCollections; +namespace OmmitedDTOModel3WithCollections; public class EntityDTO4 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO5.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO5.cs index 900004b725..b45d2d3a3d 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO5.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO5.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDTOModel3WithCollections; +namespace OmmitedDTOModel3WithCollections; public class EntityDTO5 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO6.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO6.cs index 7eb43f7d8f..64c7abc031 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO6.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO6.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDTOModel3WithCollections; +namespace OmmitedDTOModel3WithCollections; public class EntityDTO6 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO7.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO7.cs index 82b35bc0cc..1daf442718 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO7.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO7.cs @@ -1,6 +1,4 @@ -using System; - -namespace OmmitedDTOModel3WithCollections; +namespace OmmitedDTOModel3WithCollections; public class EntityDTO7 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO8.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO8.cs index 05f5249fa1..0f456a5e95 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO8.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO8.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace OmmitedDTOModel3WithCollections; +namespace OmmitedDTOModel3WithCollections; public class EntityDTO8 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO9.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO9.cs index 1d081bc0c5..47a0864f40 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO9.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/EntityDTO9.cs @@ -1,6 +1,4 @@ -using System; - -namespace OmmitedDTOModel3WithCollections; +namespace OmmitedDTOModel3WithCollections; public class EntityDTO9 : BaseEntity { diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/MapAtRuntimeWithCollections.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/MapAtRuntimeWithCollections.cs index 4facd6bf96..168e40d5a2 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/MapAtRuntimeWithCollections.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/MapAtRuntimeWithCollections.cs @@ -1,9 +1,5 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using OmmitedDatabaseModel3WithCollections; +using OmmitedDatabaseModel3WithCollections; using OmmitedDTOModel3WithCollections; -using Xunit; namespace AutoMapper.UnitTests; diff --git a/src/UnitTests/Bug/MapExpandoObjectProperty.cs b/src/UnitTests/Bug/MapExpandoObjectProperty.cs index e36abd119f..4349cd788a 100644 --- a/src/UnitTests/Bug/MapExpandoObjectProperty.cs +++ b/src/UnitTests/Bug/MapExpandoObjectProperty.cs @@ -1,5 +1,4 @@ using System.Dynamic; -using Xunit; namespace AutoMapper.UnitTests.Bug; diff --git a/src/UnitTests/Bug/MapFromClosureBug.cs b/src/UnitTests/Bug/MapFromClosureBug.cs index 51e3e34038..51e9d457e2 100644 --- a/src/UnitTests/Bug/MapFromClosureBug.cs +++ b/src/UnitTests/Bug/MapFromClosureBug.cs @@ -1,9 +1,4 @@ namespace AutoMapper.UnitTests.Bug; - -using System; -using Shouldly; -using Xunit; - public class MapFromClosureBug : NonValidatingSpecBase { private static readonly IDateProvider _dateProvider = new DateProvider(); diff --git a/src/UnitTests/Bug/MapOverloadsWithDynamic.cs b/src/UnitTests/Bug/MapOverloadsWithDynamic.cs index c37141b926..51f7bfe1a4 100644 --- a/src/UnitTests/Bug/MapOverloadsWithDynamic.cs +++ b/src/UnitTests/Bug/MapOverloadsWithDynamic.cs @@ -1,7 +1,4 @@ -using Xunit; -using Shouldly; -using System; -using System.Dynamic; +using System.Dynamic; namespace AutoMapper.UnitTests.Bug; diff --git a/src/UnitTests/Bug/MappingInheritance.cs b/src/UnitTests/Bug/MappingInheritance.cs index 4ef97ba558..3270923a8e 100644 --- a/src/UnitTests/Bug/MappingInheritance.cs +++ b/src/UnitTests/Bug/MappingInheritance.cs @@ -1,9 +1,4 @@ - -namespace AutoMapper.UnitTests.Bug; - -using Shouldly; -using Xunit; - +namespace AutoMapper.UnitTests.Bug; public class MappingInheritance : AutoMapperSpecBase { private Entity testEntity; diff --git a/src/UnitTests/Bug/MappingToAReadOnlyCollection.cs b/src/UnitTests/Bug/MappingToAReadOnlyCollection.cs index ade438a7b3..30f301cb4c 100644 --- a/src/UnitTests/Bug/MappingToAReadOnlyCollection.cs +++ b/src/UnitTests/Bug/MappingToAReadOnlyCollection.cs @@ -1,8 +1,3 @@ -using System; -using System.Collections.ObjectModel; -using Shouldly; -using Xunit; - namespace AutoMapper.UnitTests.Bug; public class MappingToAReadOnlyCollection : AutoMapperSpecBase diff --git a/src/UnitTests/Bug/MemberListSourceAndForPath.cs b/src/UnitTests/Bug/MemberListSourceAndForPath.cs index b55e1f2f01..966b172b37 100644 --- a/src/UnitTests/Bug/MemberListSourceAndForPath.cs +++ b/src/UnitTests/Bug/MemberListSourceAndForPath.cs @@ -1,7 +1,4 @@ -using Shouldly; -using Xunit; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class MemberListSourceAndForPath : AutoMapperSpecBase { diff --git a/src/UnitTests/Bug/MemberNamedTypeBug.cs b/src/UnitTests/Bug/MemberNamedTypeBug.cs index 6ea0173b3a..e074ae38cd 100644 --- a/src/UnitTests/Bug/MemberNamedTypeBug.cs +++ b/src/UnitTests/Bug/MemberNamedTypeBug.cs @@ -1,10 +1,4 @@ -using Xunit; - -namespace AutoMapper.UnitTests.Bug; - -using System; -using Shouldly; - +namespace AutoMapper.UnitTests.Bug; public class CorrectCtorIsPickedOnDestinationType : NonValidatingSpecBase { public class SourceClass { } diff --git a/src/UnitTests/Bug/MissingMapping.cs b/src/UnitTests/Bug/MissingMapping.cs index 2080cfaef0..8dbfb64fe7 100644 --- a/src/UnitTests/Bug/MissingMapping.cs +++ b/src/UnitTests/Bug/MissingMapping.cs @@ -1,11 +1,4 @@ namespace AutoMapper.UnitTests; - -using System.Linq; -using Shouldly; -using Xunit; -using QueryableExtensions; -using System; - public class MissingMapping : AutoMapperSpecBase { public class Source diff --git a/src/UnitTests/Bug/MultiThreadingIssues.cs b/src/UnitTests/Bug/MultiThreadingIssues.cs index ff9b735f36..98dd98bae0 100644 --- a/src/UnitTests/Bug/MultiThreadingIssues.cs +++ b/src/UnitTests/Bug/MultiThreadingIssues.cs @@ -1,16 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using AutoMapper.Internal.Mappers; -using Xunit; - -namespace AutoMapper.UnitTests.Bug; - -using Shouldly; - +namespace AutoMapper.UnitTests.Bug; public class MultiThreadingIssues { public class Type1 diff --git a/src/UnitTests/Bug/MultidimensionalArrays.cs b/src/UnitTests/Bug/MultidimensionalArrays.cs index 48599f34eb..d697d2e70a 100644 --- a/src/UnitTests/Bug/MultidimensionalArrays.cs +++ b/src/UnitTests/Bug/MultidimensionalArrays.cs @@ -1,9 +1,4 @@ -using Xunit; -using Shouldly; -using AutoMapper.Internal.Mappers; -using System.Collections.Generic; -using System; -using System.Linq; +using AutoMapper.Internal.Mappers; namespace AutoMapper.UnitTests.Bug; diff --git a/src/UnitTests/Bug/MultipleInterfaceInheritance.cs b/src/UnitTests/Bug/MultipleInterfaceInheritance.cs index a75bc73f3a..a41ae6fcd9 100644 --- a/src/UnitTests/Bug/MultipleInterfaceInheritance.cs +++ b/src/UnitTests/Bug/MultipleInterfaceInheritance.cs @@ -1,6 +1,3 @@ -using Shouldly; -using Xunit; - namespace AutoMapper.UnitTests.Bug; public class MultipleInterfaceInheritance : AutoMapperSpecBase diff --git a/src/UnitTests/Bug/MultipleTypeConverterInterfaces.cs b/src/UnitTests/Bug/MultipleTypeConverterInterfaces.cs index f529b57fd3..aa4e9e4c0f 100644 --- a/src/UnitTests/Bug/MultipleTypeConverterInterfaces.cs +++ b/src/UnitTests/Bug/MultipleTypeConverterInterfaces.cs @@ -1,9 +1,6 @@ -using Shouldly; -using Xunit; - namespace AutoMapper.UnitTests.Bug; - public class When_specifying_a_type_converter_implementing_multiple_type_converter_interfaces : AutoMapperSpecBase +public class When_specifying_a_type_converter_implementing_multiple_type_converter_interfaces : AutoMapperSpecBase { private DestinationFoo _resultFoo; private DestinationBar _resultBar; diff --git a/src/UnitTests/Bug/NamingConventions.cs b/src/UnitTests/Bug/NamingConventions.cs index a1a6db8c6b..b10629bb0a 100644 --- a/src/UnitTests/Bug/NamingConventions.cs +++ b/src/UnitTests/Bug/NamingConventions.cs @@ -1,11 +1,3 @@ -using AutoMapper.Configuration.Conventions; -using AutoMapper.Internal; -using Shouldly; -using System; -using System.Linq; -using System.Reflection; -using Xunit; - namespace AutoMapper.UnitTests.Bug.NamingConventions; public class RemoveNameSplitMapper : NonValidatingSpecBase diff --git a/src/UnitTests/Bug/NestedMappingProjectionsExplicitExpanding.cs b/src/UnitTests/Bug/NestedMappingProjectionsExplicitExpanding.cs index 150f25ec3f..369bd2e5aa 100644 --- a/src/UnitTests/Bug/NestedMappingProjectionsExplicitExpanding.cs +++ b/src/UnitTests/Bug/NestedMappingProjectionsExplicitExpanding.cs @@ -1,10 +1,4 @@ -using System; -using System.Linq; -using AutoMapper.QueryableExtensions; -using Shouldly; -using Xunit; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class NestedMappingProjectionsExplicitExpanding : AutoMapperSpecBase { diff --git a/src/UnitTests/Bug/NonExistingProperty.cs b/src/UnitTests/Bug/NonExistingProperty.cs index 3df6947e5e..45961ebc44 100644 --- a/src/UnitTests/Bug/NonExistingProperty.cs +++ b/src/UnitTests/Bug/NonExistingProperty.cs @@ -1,8 +1,4 @@ -using System; -using Shouldly; -using Xunit; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class NonExistingProperty : NonValidatingSpecBase { diff --git a/src/UnitTests/Bug/NullArrayBug.cs b/src/UnitTests/Bug/NullArrayBug.cs index 4a7421bb4a..7a55f8e8d9 100644 --- a/src/UnitTests/Bug/NullArrayBug.cs +++ b/src/UnitTests/Bug/NullArrayBug.cs @@ -1,8 +1,4 @@ namespace AutoMapper.UnitTests.Bug; - -using Shouldly; -using Xunit; - public class NullArrayBug : AutoMapperSpecBase { private static Source _source; diff --git a/src/UnitTests/Bug/NullConstructorParameterName.cs b/src/UnitTests/Bug/NullConstructorParameterName.cs index 766ad321a9..9aabd4654a 100644 --- a/src/UnitTests/Bug/NullConstructorParameterName.cs +++ b/src/UnitTests/Bug/NullConstructorParameterName.cs @@ -1,7 +1,4 @@ -using System; -using System.Reflection; -using System.Reflection.Emit; -using Xunit; +using System.Reflection.Emit; namespace AutoMapper.UnitTests.Bug; diff --git a/src/UnitTests/Bug/NullSubstituteInnerClass.cs b/src/UnitTests/Bug/NullSubstituteInnerClass.cs index f4e845e56f..ecad7ef026 100644 --- a/src/UnitTests/Bug/NullSubstituteInnerClass.cs +++ b/src/UnitTests/Bug/NullSubstituteInnerClass.cs @@ -1,8 +1,4 @@ -using Xunit; -using Shouldly; -using System; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class NullSubstituteInnerClass : AutoMapperSpecBase { diff --git a/src/UnitTests/Bug/NullSubstituteType.cs b/src/UnitTests/Bug/NullSubstituteType.cs index cdf1275a6f..2d9f8aac11 100644 --- a/src/UnitTests/Bug/NullSubstituteType.cs +++ b/src/UnitTests/Bug/NullSubstituteType.cs @@ -1,8 +1,4 @@ -using Xunit; -using Shouldly; -using System; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class NullSubstituteType : AutoMapperSpecBase { diff --git a/src/UnitTests/Bug/NullToString.cs b/src/UnitTests/Bug/NullToString.cs index 398c76f0d2..8c5747cf27 100644 --- a/src/UnitTests/Bug/NullToString.cs +++ b/src/UnitTests/Bug/NullToString.cs @@ -1,8 +1,4 @@ -using Xunit; -using Shouldly; -using System; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class NullToString : AutoMapperSpecBase { diff --git a/src/UnitTests/Bug/NullableBytesAndEnums.cs b/src/UnitTests/Bug/NullableBytesAndEnums.cs index c6044694b3..cdcc13bbab 100644 --- a/src/UnitTests/Bug/NullableBytesAndEnums.cs +++ b/src/UnitTests/Bug/NullableBytesAndEnums.cs @@ -1,6 +1,3 @@ -using Shouldly; -using Xunit; - namespace AutoMapper.UnitTests.Bug; public class NullableBytesAndEnums : AutoMapperSpecBase diff --git a/src/UnitTests/Bug/NullableConverterBug.cs b/src/UnitTests/Bug/NullableConverterBug.cs index aca5532a6e..8ad841aa2b 100644 --- a/src/UnitTests/Bug/NullableConverterBug.cs +++ b/src/UnitTests/Bug/NullableConverterBug.cs @@ -1,15 +1,9 @@ -using Xunit; -using Shouldly; - -namespace AutoMapper.UnitTests.Bug +namespace AutoMapper.UnitTests.Bug { namespace NullableConverterBug { namespace AutoMapperIssue { - using System; - using System.Collections.Generic; - using AutoMapper; public class TestProblem { [Fact] diff --git a/src/UnitTests/Bug/NullableDateTime.cs b/src/UnitTests/Bug/NullableDateTime.cs index 1d02a85752..47e58987ee 100644 --- a/src/UnitTests/Bug/NullableDateTime.cs +++ b/src/UnitTests/Bug/NullableDateTime.cs @@ -1,10 +1,4 @@ -using System; -using System.Linq; -using Shouldly; -using AutoMapper; -using Xunit; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class NullableDateTimeMapFromArray : AutoMapperSpecBase { diff --git a/src/UnitTests/Bug/NullableEnumToNullableValueType.cs b/src/UnitTests/Bug/NullableEnumToNullableValueType.cs index c215edbaea..159e6dd20e 100644 --- a/src/UnitTests/Bug/NullableEnumToNullableValueType.cs +++ b/src/UnitTests/Bug/NullableEnumToNullableValueType.cs @@ -1,7 +1,4 @@ -using Shouldly; -using Xunit; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class NullableEnumToNullableValueType { diff --git a/src/UnitTests/Bug/NullableEnums.cs b/src/UnitTests/Bug/NullableEnums.cs index f261ebdfe8..00d12689a3 100644 --- a/src/UnitTests/Bug/NullableEnums.cs +++ b/src/UnitTests/Bug/NullableEnums.cs @@ -1,7 +1,4 @@ -using Xunit; -using Shouldly; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class NullableEnums : AutoMapperSpecBase { diff --git a/src/UnitTests/Bug/NullableIntToNullableDecimal.cs b/src/UnitTests/Bug/NullableIntToNullableDecimal.cs index fc419b9a0c..3b9a1c52b9 100644 --- a/src/UnitTests/Bug/NullableIntToNullableDecimal.cs +++ b/src/UnitTests/Bug/NullableIntToNullableDecimal.cs @@ -1,8 +1,4 @@ -using Xunit; -using Shouldly; -using System; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class NullableIntToNullableDecimal : AutoMapperSpecBase { diff --git a/src/UnitTests/Bug/NullableIntToNullableEnum.cs b/src/UnitTests/Bug/NullableIntToNullableEnum.cs index a1c82a814f..5d15df6025 100644 --- a/src/UnitTests/Bug/NullableIntToNullableEnum.cs +++ b/src/UnitTests/Bug/NullableIntToNullableEnum.cs @@ -1,9 +1,4 @@ -using System; -using Shouldly; -using AutoMapper; -using Xunit; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class NullableIntToNullableEnum : AutoMapperSpecBase { diff --git a/src/UnitTests/Bug/NullablePropertiesBug.cs b/src/UnitTests/Bug/NullablePropertiesBug.cs index af16328852..3a86571c8e 100644 --- a/src/UnitTests/Bug/NullablePropertiesBug.cs +++ b/src/UnitTests/Bug/NullablePropertiesBug.cs @@ -1,7 +1,4 @@ -using Xunit; -using Shouldly; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class NullablePropertiesBug { diff --git a/src/UnitTests/Bug/NullableResolveUsing.cs b/src/UnitTests/Bug/NullableResolveUsing.cs index cab70ae7ae..c618c31bc3 100644 --- a/src/UnitTests/Bug/NullableResolveUsing.cs +++ b/src/UnitTests/Bug/NullableResolveUsing.cs @@ -1,8 +1,4 @@ -using Xunit; -using Shouldly; -using System; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class NullableResolveUsing : AutoMapperSpecBase { diff --git a/src/UnitTests/Bug/NullableToInvalid.cs b/src/UnitTests/Bug/NullableToInvalid.cs index 667928165a..2928ffc1f9 100644 --- a/src/UnitTests/Bug/NullableToInvalid.cs +++ b/src/UnitTests/Bug/NullableToInvalid.cs @@ -1,7 +1,3 @@ -using System; -using Shouldly; -using Xunit; - namespace AutoMapper.UnitTests.Bug; public class NullableToInvalid : NonValidatingSpecBase diff --git a/src/UnitTests/Bug/NullableUntypedMapFrom.cs b/src/UnitTests/Bug/NullableUntypedMapFrom.cs index e4966c5557..d804aac3ac 100644 --- a/src/UnitTests/Bug/NullableUntypedMapFrom.cs +++ b/src/UnitTests/Bug/NullableUntypedMapFrom.cs @@ -1,7 +1,4 @@ -using Xunit; -using Shouldly; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class NullableUntypedMapFrom : AutoMapperSpecBase { diff --git a/src/UnitTests/Bug/ObjectEnumToObjectEnum.cs b/src/UnitTests/Bug/ObjectEnumToObjectEnum.cs index 9e2df7d2ad..21e584d9d9 100644 --- a/src/UnitTests/Bug/ObjectEnumToObjectEnum.cs +++ b/src/UnitTests/Bug/ObjectEnumToObjectEnum.cs @@ -1,9 +1,4 @@ -using System; -using Shouldly; -using AutoMapper.Internal.Mappers; -using Xunit; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class ObjectEnumToObjectEnum : AutoMapperSpecBase { diff --git a/src/UnitTests/Bug/ObjectTypeMapFailure.cs b/src/UnitTests/Bug/ObjectTypeMapFailure.cs index 805773a0ec..ad67630e86 100644 --- a/src/UnitTests/Bug/ObjectTypeMapFailure.cs +++ b/src/UnitTests/Bug/ObjectTypeMapFailure.cs @@ -1,7 +1,4 @@ -using Xunit; -using Shouldly; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class ObjectTypeMapFailure : NonValidatingSpecBase { diff --git a/src/UnitTests/Bug/OneSourceWithMultipleDestinationsAndPreserveReferences.cs b/src/UnitTests/Bug/OneSourceWithMultipleDestinationsAndPreserveReferences.cs index 92a09e9496..ad61e6bc71 100644 --- a/src/UnitTests/Bug/OneSourceWithMultipleDestinationsAndPreserveReferences.cs +++ b/src/UnitTests/Bug/OneSourceWithMultipleDestinationsAndPreserveReferences.cs @@ -1,7 +1,4 @@ -using Xunit; -using Shouldly; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class OneSourceWithMultipleDestinationsAndPreserveReferences : AutoMapperSpecBase { diff --git a/src/UnitTests/Bug/OneSourceWithMultipleDestinationsWithoutPR.cs b/src/UnitTests/Bug/OneSourceWithMultipleDestinationsWithoutPR.cs index 8188853321..57b3241658 100644 --- a/src/UnitTests/Bug/OneSourceWithMultipleDestinationsWithoutPR.cs +++ b/src/UnitTests/Bug/OneSourceWithMultipleDestinationsWithoutPR.cs @@ -1,7 +1,4 @@ -using Xunit; -using Shouldly; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class OneSourceWithMultipleDestinationsWithoutPR : AutoMapperSpecBase { diff --git a/src/UnitTests/Bug/ParentChildResolversBug.cs b/src/UnitTests/Bug/ParentChildResolversBug.cs index 3b1c16cd88..d2937673cf 100644 --- a/src/UnitTests/Bug/ParentChildResolversBug.cs +++ b/src/UnitTests/Bug/ParentChildResolversBug.cs @@ -2,9 +2,6 @@ { namespace ParentChildResolversBug { - using Shouldly; - using Xunit; - public enum DestEnum { a, diff --git a/src/UnitTests/Bug/PreserveReferencesSameDestination.cs b/src/UnitTests/Bug/PreserveReferencesSameDestination.cs index 881909cd72..d2690925a4 100644 --- a/src/UnitTests/Bug/PreserveReferencesSameDestination.cs +++ b/src/UnitTests/Bug/PreserveReferencesSameDestination.cs @@ -1,10 +1,4 @@ -using Xunit; -using Shouldly; -using System; -using System.Linq; -using System.Collections.Generic; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class Self_referencing_existing_destination : AutoMapperSpecBase { diff --git a/src/UnitTests/Bug/ProjectCollectionsBug.cs b/src/UnitTests/Bug/ProjectCollectionsBug.cs index 0417c2fd72..b9f6f19ecb 100644 --- a/src/UnitTests/Bug/ProjectCollectionsBug.cs +++ b/src/UnitTests/Bug/ProjectCollectionsBug.cs @@ -1,14 +1,7 @@ namespace AutoMapper.UnitTests.Bug { - using System.Collections.Generic; - namespace ProjectCollectionsBug { - using System; - using System.Linq; - using QueryableExtensions; - using Xunit; - public class A { public int AP1 { get; set; } diff --git a/src/UnitTests/Bug/ProjectConstructorParameters.cs b/src/UnitTests/Bug/ProjectConstructorParameters.cs index 21de3d19a3..52f2eeb827 100644 --- a/src/UnitTests/Bug/ProjectConstructorParameters.cs +++ b/src/UnitTests/Bug/ProjectConstructorParameters.cs @@ -1,9 +1,4 @@ -using System.Linq; -using AutoMapper.QueryableExtensions; -using Shouldly; -using Xunit; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class ProjectConstructorParameters : AutoMapperSpecBase { diff --git a/src/UnitTests/Bug/ProjectUsingTheQueriedEntity.cs b/src/UnitTests/Bug/ProjectUsingTheQueriedEntity.cs index c166ee6781..f8fddb3cd1 100644 --- a/src/UnitTests/Bug/ProjectUsingTheQueriedEntity.cs +++ b/src/UnitTests/Bug/ProjectUsingTheQueriedEntity.cs @@ -1,10 +1,4 @@ -using Xunit; -using Shouldly; -using System; -using System.Linq; -using AutoMapper.QueryableExtensions; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class ProjectUsingTheQueriedEntity : AutoMapperSpecBase { diff --git a/src/UnitTests/Bug/PropertyNamedType.cs b/src/UnitTests/Bug/PropertyNamedType.cs index cdcbc08074..371eaff5ca 100644 --- a/src/UnitTests/Bug/PropertyNamedType.cs +++ b/src/UnitTests/Bug/PropertyNamedType.cs @@ -1,8 +1,4 @@ -using Xunit; -using Shouldly; -using System; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class PropertyNamedType { diff --git a/src/UnitTests/Bug/ReadOnlyCollectionMappingBug.cs b/src/UnitTests/Bug/ReadOnlyCollectionMappingBug.cs index f37310f114..b851d8a832 100644 --- a/src/UnitTests/Bug/ReadOnlyCollectionMappingBug.cs +++ b/src/UnitTests/Bug/ReadOnlyCollectionMappingBug.cs @@ -1,9 +1,4 @@ -using System.Collections.Generic; -using System.Collections.ObjectModel; -using Shouldly; -using Xunit; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; // Bug #511 // https://github.com/AutoMapper/AutoMapper/issues/511 diff --git a/src/UnitTests/Bug/ReadOnlyFieldMappingBug.cs b/src/UnitTests/Bug/ReadOnlyFieldMappingBug.cs index 2690c700a6..5b6e9e9c74 100644 --- a/src/UnitTests/Bug/ReadOnlyFieldMappingBug.cs +++ b/src/UnitTests/Bug/ReadOnlyFieldMappingBug.cs @@ -1,7 +1,4 @@ -using Shouldly; -using Xunit; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class ReadOnlyFieldMappingBug : AutoMapperSpecBase { diff --git a/src/UnitTests/Bug/RecognizeDestinationPostfixes.cs b/src/UnitTests/Bug/RecognizeDestinationPostfixes.cs index b4d911bed5..3343319dca 100644 --- a/src/UnitTests/Bug/RecognizeDestinationPostfixes.cs +++ b/src/UnitTests/Bug/RecognizeDestinationPostfixes.cs @@ -1,8 +1,4 @@ -using Shouldly; -using System; -using Xunit; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class RecognizeDestinationPostfixes : AutoMapperSpecBase { diff --git a/src/UnitTests/Bug/RecognizeIxesBug.cs b/src/UnitTests/Bug/RecognizeIxesBug.cs index 2791af873b..9ef41661db 100644 --- a/src/UnitTests/Bug/RecognizeIxesBug.cs +++ b/src/UnitTests/Bug/RecognizeIxesBug.cs @@ -1,6 +1,3 @@ -using Xunit; -using Shouldly; - namespace AutoMapper.UnitTests.Bug { namespace RecognizeIxesBug diff --git a/src/UnitTests/Bug/RemovePrefixes.cs b/src/UnitTests/Bug/RemovePrefixes.cs index c35411cf15..fb2d84a6a5 100644 --- a/src/UnitTests/Bug/RemovePrefixes.cs +++ b/src/UnitTests/Bug/RemovePrefixes.cs @@ -1,9 +1,4 @@ -using Xunit; -using Shouldly; -using System; -using AutoMapper.Internal.Mappers; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class RemovePrefixes : NonValidatingSpecBase { diff --git a/src/UnitTests/Bug/RepeatedMappingConfigurationTest.cs b/src/UnitTests/Bug/RepeatedMappingConfigurationTest.cs index 2ae967ffb7..703d6823b0 100644 --- a/src/UnitTests/Bug/RepeatedMappingConfigurationTest.cs +++ b/src/UnitTests/Bug/RepeatedMappingConfigurationTest.cs @@ -1,5 +1,3 @@ -using Xunit; - namespace AutoMapper.UnitTests.Bug; public class When_mapping_for_derived_class_is_duplicated : NonValidatingSpecBase diff --git a/src/UnitTests/Bug/ReportMissingInclude.cs b/src/UnitTests/Bug/ReportMissingInclude.cs index ead988c6fb..2c8397e6f1 100644 --- a/src/UnitTests/Bug/ReportMissingInclude.cs +++ b/src/UnitTests/Bug/ReportMissingInclude.cs @@ -1,8 +1,4 @@ -using Xunit; -using Shouldly; -using System; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class ReportMissingInclude { diff --git a/src/UnitTests/Bug/ReverseMapReplaceMemberName.cs b/src/UnitTests/Bug/ReverseMapReplaceMemberName.cs index 462bff2e45..0bcf5fad83 100644 --- a/src/UnitTests/Bug/ReverseMapReplaceMemberName.cs +++ b/src/UnitTests/Bug/ReverseMapReplaceMemberName.cs @@ -1,8 +1,4 @@ -using Xunit; -using Shouldly; -using System; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class ReverseMapAndReplaceMemberName : AutoMapperSpecBase { diff --git a/src/UnitTests/Bug/SelectiveConfigurationValidation.cs b/src/UnitTests/Bug/SelectiveConfigurationValidation.cs index 1f69759648..8ea76621e7 100644 --- a/src/UnitTests/Bug/SelectiveConfigurationValidation.cs +++ b/src/UnitTests/Bug/SelectiveConfigurationValidation.cs @@ -1,8 +1,4 @@ namespace AutoMapper.UnitTests.Bug; - -using System; -using Xunit; - public class SelectiveConfigurationValidation : NonValidatingSpecBase { public class GoodSrc { } diff --git a/src/UnitTests/Bug/SequenceContainsNoElementsTest.cs b/src/UnitTests/Bug/SequenceContainsNoElementsTest.cs index 7d89ad0cbc..5b04758864 100644 --- a/src/UnitTests/Bug/SequenceContainsNoElementsTest.cs +++ b/src/UnitTests/Bug/SequenceContainsNoElementsTest.cs @@ -1,11 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Collections; -using Xunit; -using Shouldly; - namespace AutoMapper.UnitTests.Bug; public class SequenceContainsNoElementsTest : AutoMapperSpecBase diff --git a/src/UnitTests/Bug/SetterOnlyBug.cs b/src/UnitTests/Bug/SetterOnlyBug.cs index 9270020cc4..8fc097e351 100644 --- a/src/UnitTests/Bug/SetterOnlyBug.cs +++ b/src/UnitTests/Bug/SetterOnlyBug.cs @@ -2,9 +2,6 @@ { namespace SetterOnlyBug { - using Shouldly; - using Xunit; - public class MappingTests : AutoMapperSpecBase { protected override MapperConfiguration CreateConfiguration() => new(cfg => diff --git a/src/UnitTests/Bug/StructMapping.cs b/src/UnitTests/Bug/StructMapping.cs index d7e75fb7c4..259e19297d 100644 --- a/src/UnitTests/Bug/StructMapping.cs +++ b/src/UnitTests/Bug/StructMapping.cs @@ -1,8 +1,4 @@ -using Xunit; -using Shouldly; -using System; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class StructMapping : AutoMapperSpecBase { diff --git a/src/UnitTests/Bug/SubclassMappings.cs b/src/UnitTests/Bug/SubclassMappings.cs index 3b94a507ac..bc06171697 100644 --- a/src/UnitTests/Bug/SubclassMappings.cs +++ b/src/UnitTests/Bug/SubclassMappings.cs @@ -1,6 +1,4 @@ -using Xunit; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class SubclassMappings : AutoMapperSpecBase { diff --git a/src/UnitTests/Bug/TargetISet.cs b/src/UnitTests/Bug/TargetISet.cs index 2b33ecad2f..274e0c6f27 100644 --- a/src/UnitTests/Bug/TargetISet.cs +++ b/src/UnitTests/Bug/TargetISet.cs @@ -1,9 +1,4 @@ -using Xunit; -using Shouldly; -using System; -using System.Collections.Generic; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class TargetISet : AutoMapperSpecBase { diff --git a/src/UnitTests/Bug/TypeMapIncludeBaseTypes.cs b/src/UnitTests/Bug/TypeMapIncludeBaseTypes.cs index 42214fc428..2b74a6eac4 100644 --- a/src/UnitTests/Bug/TypeMapIncludeBaseTypes.cs +++ b/src/UnitTests/Bug/TypeMapIncludeBaseTypes.cs @@ -1,9 +1,4 @@ -using AutoMapper.Internal; -using Shouldly; -using System.Linq; -using Xunit; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public abstract class TypeMapIncludeBaseTypes { diff --git a/src/UnitTests/Bug/UseDestinationValue.cs b/src/UnitTests/Bug/UseDestinationValue.cs index a645b8a6a0..1550b3c728 100644 --- a/src/UnitTests/Bug/UseDestinationValue.cs +++ b/src/UnitTests/Bug/UseDestinationValue.cs @@ -1,9 +1,4 @@ -using Xunit; -using Shouldly; -using System; -using System.Collections.Generic; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class UseDestinationValue : AutoMapperSpecBase { diff --git a/src/UnitTests/Bug/WithoutPreserveReferencesSameDestination.cs b/src/UnitTests/Bug/WithoutPreserveReferencesSameDestination.cs index 1424a7f69a..c77258bb22 100644 --- a/src/UnitTests/Bug/WithoutPreserveReferencesSameDestination.cs +++ b/src/UnitTests/Bug/WithoutPreserveReferencesSameDestination.cs @@ -1,10 +1,4 @@ -using Xunit; -using Shouldly; -using System; -using System.Linq; -using System.Collections.Generic; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class Self_referencing_existing_destination_without_PreserveReferences : AutoMapperSpecBase { diff --git a/src/UnitTests/BuildExecutionPlan.cs b/src/UnitTests/BuildExecutionPlan.cs index 713b888f23..2dd4eb551e 100644 --- a/src/UnitTests/BuildExecutionPlan.cs +++ b/src/UnitTests/BuildExecutionPlan.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using Shouldly; -using Xunit; -namespace AutoMapper.UnitTests; +namespace AutoMapper.UnitTests; public class BuildExecutionPlan : AutoMapperSpecBase { Model _source; diff --git a/src/UnitTests/CollectionMapping.cs b/src/UnitTests/CollectionMapping.cs index f237fb43b5..9f2e906957 100644 --- a/src/UnitTests/CollectionMapping.cs +++ b/src/UnitTests/CollectionMapping.cs @@ -1,12 +1,4 @@ -using System; -using System.Linq; -using System.Collections.Generic; -using System.Collections.ObjectModel; using System.Collections.Specialized; -using Xunit; -using Shouldly; -using System.Collections; -using AutoMapper.Internal; using System.Collections.Immutable; namespace AutoMapper.UnitTests; diff --git a/src/UnitTests/ConditionalMapping.cs b/src/UnitTests/ConditionalMapping.cs index 921b352209..c0db7c0e4f 100644 --- a/src/UnitTests/ConditionalMapping.cs +++ b/src/UnitTests/ConditionalMapping.cs @@ -1,9 +1,3 @@ -using System; -using System.Linq; -using System.Reflection; -using Xunit; -using Shouldly; - namespace AutoMapper.UnitTests.ConditionalMapping; public class When_adding_a_condition_for_all_members : AutoMapperSpecBase diff --git a/src/UnitTests/ConfigCompilation.cs b/src/UnitTests/ConfigCompilation.cs index a6d22a8f2b..d700f7f61c 100644 --- a/src/UnitTests/ConfigCompilation.cs +++ b/src/UnitTests/ConfigCompilation.cs @@ -1,9 +1,4 @@ namespace AutoMapper.UnitTests; - -using System.Collections.Generic; -using Shouldly; -using Xunit; - public class ConfigCompilation : NonValidatingSpecBase { public class Source { } diff --git a/src/UnitTests/ConfigurationFeatureTest.cs b/src/UnitTests/ConfigurationFeatureTest.cs index f97cac2667..0e2a40ffbe 100644 --- a/src/UnitTests/ConfigurationFeatureTest.cs +++ b/src/UnitTests/ConfigurationFeatureTest.cs @@ -1,8 +1,4 @@ using AutoMapper.Features; -using AutoMapper.Internal; -using Shouldly; -using System.Collections.Generic; -using Xunit; namespace AutoMapper.UnitTests; diff --git a/src/UnitTests/ConfigurationRules.cs b/src/UnitTests/ConfigurationRules.cs index f41fee8a84..b7f390d725 100644 --- a/src/UnitTests/ConfigurationRules.cs +++ b/src/UnitTests/ConfigurationRules.cs @@ -1,10 +1,4 @@ -using System; -using System.Linq; -using AutoMapper.Internal; -using Shouldly; -using Xunit; - -namespace AutoMapper.UnitTests; +namespace AutoMapper.UnitTests; public class ConfigurationRules : NonValidatingSpecBase { diff --git a/src/UnitTests/ConfigurationValidation.cs b/src/UnitTests/ConfigurationValidation.cs index 72d7366aa9..3f80f819bb 100644 --- a/src/UnitTests/ConfigurationValidation.cs +++ b/src/UnitTests/ConfigurationValidation.cs @@ -1,9 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Shouldly; -using Xunit; - namespace AutoMapper.UnitTests.ConfigurationValidation; public class ConstructorMappingValidation : NonValidatingSpecBase diff --git a/src/UnitTests/Constructors.cs b/src/UnitTests/Constructors.cs index dcc51069ec..2ba648e765 100644 --- a/src/UnitTests/Constructors.cs +++ b/src/UnitTests/Constructors.cs @@ -1,10 +1,4 @@ -using System; -using System.Linq; -using System.Linq.Expressions; -using Xunit; -using Shouldly; -using System.Collections.Generic; -namespace AutoMapper.UnitTests.Constructors; +namespace AutoMapper.UnitTests.Constructors; public class RecordConstructorValidation : AutoMapperSpecBase { diff --git a/src/UnitTests/ContextItems.cs b/src/UnitTests/ContextItems.cs index c8e54db0a8..e31233ca69 100644 --- a/src/UnitTests/ContextItems.cs +++ b/src/UnitTests/ContextItems.cs @@ -1,14 +1,7 @@ -using System.Collections.Generic; -using System.Linq; - -namespace AutoMapper.UnitTests +namespace AutoMapper.UnitTests { namespace ContextItems { - using Shouldly; - using System; - using Xunit; - public class When_mapping_with_contextual_values { public class Source diff --git a/src/UnitTests/CustomCollectionTester.cs b/src/UnitTests/CustomCollectionTester.cs index 0bb162567b..ffa8d11128 100644 --- a/src/UnitTests/CustomCollectionTester.cs +++ b/src/UnitTests/CustomCollectionTester.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using Xunit; - -namespace AutoMapper.UnitTests; +namespace AutoMapper.UnitTests; public class CustomCollectionTester { [Fact] public void Should_be_able_to_handle_custom_dictionary_with_custom_methods() { diff --git a/src/UnitTests/CustomMapping.cs b/src/UnitTests/CustomMapping.cs index 9f72d33ae7..c559a4d80e 100644 --- a/src/UnitTests/CustomMapping.cs +++ b/src/UnitTests/CustomMapping.cs @@ -1,10 +1,3 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using Shouldly; -using Xunit; - namespace AutoMapper.UnitTests; public class When_implementing_multiple_IValueResolver_interfaces : AutoMapperSpecBase diff --git a/src/UnitTests/CustomValidations.cs b/src/UnitTests/CustomValidations.cs index 834d3ef406..a21d424d56 100644 --- a/src/UnitTests/CustomValidations.cs +++ b/src/UnitTests/CustomValidations.cs @@ -1,10 +1,5 @@ -using System; -using System.Linq.Expressions; using AutoMapper.Configuration; -using AutoMapper.Internal; using AutoMapper.Internal.Mappers; -using Shouldly; -using Xunit; namespace AutoMapper.UnitTests; diff --git a/src/UnitTests/Dictionaries.cs b/src/UnitTests/Dictionaries.cs index 7a69f57acd..1c7a638440 100644 --- a/src/UnitTests/Dictionaries.cs +++ b/src/UnitTests/Dictionaries.cs @@ -1,11 +1,3 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; -using Shouldly; -using Xunit; - namespace AutoMapper.UnitTests { namespace Dictionaries diff --git a/src/UnitTests/EnumToNullableEnum.cs b/src/UnitTests/EnumToNullableEnum.cs index 7e2e111592..f76ce611f0 100644 --- a/src/UnitTests/EnumToNullableEnum.cs +++ b/src/UnitTests/EnumToNullableEnum.cs @@ -1,7 +1,4 @@ -using Shouldly; -using Xunit; - -namespace AutoMapper.UnitTests; +namespace AutoMapper.UnitTests; public class EnumToNullableEnum : AutoMapperSpecBase { diff --git a/src/UnitTests/Enumerations.cs b/src/UnitTests/Enumerations.cs index f5644ca72f..dd0ffaf58e 100644 --- a/src/UnitTests/Enumerations.cs +++ b/src/UnitTests/Enumerations.cs @@ -1,8 +1,5 @@ -using System; using System.Runtime.Serialization; using AutoMapper.UnitTests; -using Shouldly; -using Xunit; namespace AutoMapper.Tests; diff --git a/src/UnitTests/ExplicitMapperCreation.cs b/src/UnitTests/ExplicitMapperCreation.cs index 4298c79cdb..b1430327aa 100644 --- a/src/UnitTests/ExplicitMapperCreation.cs +++ b/src/UnitTests/ExplicitMapperCreation.cs @@ -1,6 +1,4 @@ -using Shouldly; -using Xunit; -namespace AutoMapper.UnitTests; +namespace AutoMapper.UnitTests; public class ExplicitMapperCreation : AutoMapperSpecBase { protected override MapperConfiguration CreateConfiguration() =>new(cfg => cfg.CreateMap()); diff --git a/src/UnitTests/ExpressionBridge.cs b/src/UnitTests/ExpressionBridge.cs index 3d8306cfb3..4dc849bca5 100644 --- a/src/UnitTests/ExpressionBridge.cs +++ b/src/UnitTests/ExpressionBridge.cs @@ -1,12 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq.Expressions; -using Shouldly; -using Xunit; -using System.Linq; using AutoMapper.QueryableExtensions.Impl; -using AutoMapper.Internal; -using AutoMapper.QueryableExtensions; namespace AutoMapper.UnitTests { diff --git a/src/UnitTests/ExtensionMethods.cs b/src/UnitTests/ExtensionMethods.cs index 8916453005..5e5591ba39 100644 --- a/src/UnitTests/ExtensionMethods.cs +++ b/src/UnitTests/ExtensionMethods.cs @@ -1,10 +1,3 @@ -using Xunit; -using Shouldly; -using System.Collections.Generic; -using System.Linq; -using System; -using AutoMapper.Internal; - namespace AutoMapper.UnitTests; interface IGeneric { } diff --git a/src/UnitTests/FillingExistingDestination.cs b/src/UnitTests/FillingExistingDestination.cs index 5b2beb9154..d13b684176 100644 --- a/src/UnitTests/FillingExistingDestination.cs +++ b/src/UnitTests/FillingExistingDestination.cs @@ -1,8 +1,3 @@ -using System.Collections.Generic; -using Shouldly; -using Xunit; -using System.Linq; - namespace AutoMapper.UnitTests; public class When_a_source_child_object_is_null : AutoMapperSpecBase diff --git a/src/UnitTests/ForAllMaps.cs b/src/UnitTests/ForAllMaps.cs index a6bf37cf6e..5c219b55b9 100644 --- a/src/UnitTests/ForAllMaps.cs +++ b/src/UnitTests/ForAllMaps.cs @@ -1,8 +1,4 @@ -using Xunit; -using Shouldly; -using System; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class ForAllMaps : AutoMapperSpecBase { diff --git a/src/UnitTests/ForAllMembers.cs b/src/UnitTests/ForAllMembers.cs index 97ad1ee7c1..e24001f4d0 100644 --- a/src/UnitTests/ForAllMembers.cs +++ b/src/UnitTests/ForAllMembers.cs @@ -1,10 +1,4 @@ -using System; -using Shouldly; -using Xunit; - -namespace AutoMapper.UnitTests.ForAllMembers; - -using Internal; +namespace AutoMapper.UnitTests.ForAllMembers; public class When_conditionally_applying_a_resolver_globally : AutoMapperSpecBase { public class Source diff --git a/src/UnitTests/ForPath.cs b/src/UnitTests/ForPath.cs index a9e013afaf..d84f6eea3c 100644 --- a/src/UnitTests/ForPath.cs +++ b/src/UnitTests/ForPath.cs @@ -1,11 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using AutoMapper; -using Shouldly; -using Xunit; - -namespace AutoMapper.UnitTests; +namespace AutoMapper.UnitTests; public class InheritForPath : AutoMapperSpecBase { diff --git a/src/UnitTests/General.cs b/src/UnitTests/General.cs index a1e6aaf9b3..e4d618fa16 100644 --- a/src/UnitTests/General.cs +++ b/src/UnitTests/General.cs @@ -1,9 +1,3 @@ -using System; -using System.Collections.Generic; -using Shouldly; -using Xunit; -using System.Linq; - namespace AutoMapper.UnitTests { namespace General diff --git a/src/UnitTests/IMappingExpression/ForCtorParam.cs b/src/UnitTests/IMappingExpression/ForCtorParam.cs index 5d13f98778..da7bfaad1b 100644 --- a/src/UnitTests/IMappingExpression/ForCtorParam.cs +++ b/src/UnitTests/IMappingExpression/ForCtorParam.cs @@ -1,10 +1,4 @@ -using System; -using Xunit; -using Shouldly; -using System.Linq; -using System.Collections.Generic; - -namespace AutoMapper.UnitTests; +namespace AutoMapper.UnitTests; public class ForCtorParam_MapFrom_String : AutoMapperSpecBase { diff --git a/src/UnitTests/IMappingExpression/IncludeMembers.cs b/src/UnitTests/IMappingExpression/IncludeMembers.cs index 8dd54b04d0..bca6d9ef04 100644 --- a/src/UnitTests/IMappingExpression/IncludeMembers.cs +++ b/src/UnitTests/IMappingExpression/IncludeMembers.cs @@ -1,13 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using System.Text; -using System.Threading.Tasks; -using AutoMapper.Execution; -using AutoMapper.Internal; -using Shouldly; -using Xunit; +using AutoMapper.Execution; namespace AutoMapper.UnitTests; diff --git a/src/UnitTests/IMappingExpression/NonGenericConstructorTests.cs b/src/UnitTests/IMappingExpression/NonGenericConstructorTests.cs index f49c604cbd..9ab0169528 100644 --- a/src/UnitTests/IMappingExpression/NonGenericConstructorTests.cs +++ b/src/UnitTests/IMappingExpression/NonGenericConstructorTests.cs @@ -1,12 +1,4 @@ namespace AutoMapper.UnitTests.Projection; - -using System; -using System.Linq; -using System.Linq.Expressions; -using QueryableExtensions; -using Shouldly; -using Xunit; - public class NonGenericConstructorTests : AutoMapperSpecBase { private Dest[] _dest; diff --git a/src/UnitTests/IMappingExpression/NonGenericProjectEnumTest.cs b/src/UnitTests/IMappingExpression/NonGenericProjectEnumTest.cs index 3ac98fe155..db74bf86a4 100644 --- a/src/UnitTests/IMappingExpression/NonGenericProjectEnumTest.cs +++ b/src/UnitTests/IMappingExpression/NonGenericProjectEnumTest.cs @@ -1,12 +1,4 @@ -using System; - -namespace AutoMapper.UnitTests.Projection; - -using QueryableExtensions; -using Shouldly; -using System.Linq; -using Xunit; - +namespace AutoMapper.UnitTests.Projection; public class NonGenericProjectEnumTest { private MapperConfiguration _config; diff --git a/src/UnitTests/IMappingExpression/NonGenericResolveUsing.cs b/src/UnitTests/IMappingExpression/NonGenericResolveUsing.cs index d9c68b63b1..e8a4db5649 100644 --- a/src/UnitTests/IMappingExpression/NonGenericResolveUsing.cs +++ b/src/UnitTests/IMappingExpression/NonGenericResolveUsing.cs @@ -1,7 +1,3 @@ -using Xunit; -using Shouldly; -using System.Linq; - namespace AutoMapper.UnitTests; public class When_using_non_generic_ResolveUsing : AutoMapperSpecBase diff --git a/src/UnitTests/IMappingExpression/NonGenericReverseMapping.cs b/src/UnitTests/IMappingExpression/NonGenericReverseMapping.cs index f12525aad5..34b4084440 100644 --- a/src/UnitTests/IMappingExpression/NonGenericReverseMapping.cs +++ b/src/UnitTests/IMappingExpression/NonGenericReverseMapping.cs @@ -1,14 +1,7 @@ -using Xunit; -using Shouldly; -using System.Linq; - namespace AutoMapper.UnitTests { namespace NonGenericReverseMapping { - using System; - using System.Text.RegularExpressions; - public class When_reverse_mapping_classes_with_simple_properties : AutoMapperSpecBase { private Source _source; diff --git a/src/UnitTests/IgnoreAllPropertiesWithAnInaccessibleSetterTests.cs b/src/UnitTests/IgnoreAllPropertiesWithAnInaccessibleSetterTests.cs index b2844cb36c..6dafb29df9 100644 --- a/src/UnitTests/IgnoreAllPropertiesWithAnInaccessibleSetterTests.cs +++ b/src/UnitTests/IgnoreAllPropertiesWithAnInaccessibleSetterTests.cs @@ -1,6 +1,4 @@ -using Xunit; - -namespace AutoMapper.UnitTests; +namespace AutoMapper.UnitTests; public class SomeSource { diff --git a/src/UnitTests/IgnoreAllTests.cs b/src/UnitTests/IgnoreAllTests.cs index e63397020f..a8acf5f1c0 100644 --- a/src/UnitTests/IgnoreAllTests.cs +++ b/src/UnitTests/IgnoreAllTests.cs @@ -1,8 +1,3 @@ -using System.Collections.Generic; -using Xunit; -using Shouldly; -using System; - namespace AutoMapper.UnitTests; public class When_overriding_global_ignore : AutoMapperSpecBase diff --git a/src/UnitTests/Indexers.cs b/src/UnitTests/Indexers.cs index b82d8368b0..2711f5372c 100644 --- a/src/UnitTests/Indexers.cs +++ b/src/UnitTests/Indexers.cs @@ -1,7 +1,3 @@ -using System; -using Shouldly; -using Xunit; - namespace AutoMapper.UnitTests { namespace Indexers diff --git a/src/UnitTests/InterfaceMapping.cs b/src/UnitTests/InterfaceMapping.cs index a0d7a4725a..34712f0540 100644 --- a/src/UnitTests/InterfaceMapping.cs +++ b/src/UnitTests/InterfaceMapping.cs @@ -1,9 +1,3 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; -using Shouldly; -using Xunit; namespace AutoMapper.UnitTests.InterfaceMapping; public class InterfaceInheritance : AutoMapperSpecBase diff --git a/src/UnitTests/Internal/CreateProxyThreading.cs b/src/UnitTests/Internal/CreateProxyThreading.cs index ff51ba162b..84c49e2f83 100644 --- a/src/UnitTests/Internal/CreateProxyThreading.cs +++ b/src/UnitTests/Internal/CreateProxyThreading.cs @@ -1,8 +1,4 @@ -using System; -using System.Linq; -using System.Threading.Tasks; -using AutoMapper.Execution; -using Xunit; +using AutoMapper.Execution; namespace AutoMapper.UnitTests; diff --git a/src/UnitTests/Internal/GenerateSimilarType.cs b/src/UnitTests/Internal/GenerateSimilarType.cs index fd6dbbe92f..0a717ff739 100644 --- a/src/UnitTests/Internal/GenerateSimilarType.cs +++ b/src/UnitTests/Internal/GenerateSimilarType.cs @@ -1,9 +1,4 @@ -using System.Linq; -using System.Collections.Generic; -using AutoMapper.Execution; -using Xunit; -using Shouldly; -using System; +using AutoMapper.Execution; namespace AutoMapper.UnitTests; diff --git a/src/UnitTests/Internal/MapperTests.cs b/src/UnitTests/Internal/MapperTests.cs index 67786371c0..d9cf2982ee 100644 --- a/src/UnitTests/Internal/MapperTests.cs +++ b/src/UnitTests/Internal/MapperTests.cs @@ -1,6 +1,3 @@ -using Xunit; -using Shouldly; - namespace AutoMapper.UnitTests.Tests; public class MapperTests : NonValidatingSpecBase diff --git a/src/UnitTests/Internal/ObjectFactoryTests.cs b/src/UnitTests/Internal/ObjectFactoryTests.cs index d65383c5c9..3d081c55f0 100644 --- a/src/UnitTests/Internal/ObjectFactoryTests.cs +++ b/src/UnitTests/Internal/ObjectFactoryTests.cs @@ -1,7 +1,3 @@ -using System; -using Shouldly; -using Xunit; - namespace AutoMapper.UnitTests; using Execution; diff --git a/src/UnitTests/Internal/PrimitiveExtensionsTester.cs b/src/UnitTests/Internal/PrimitiveExtensionsTester.cs index 24f554b239..65b7e2d827 100644 --- a/src/UnitTests/Internal/PrimitiveExtensionsTester.cs +++ b/src/UnitTests/Internal/PrimitiveExtensionsTester.cs @@ -1,9 +1,3 @@ -using Xunit; -using Shouldly; -using AutoMapper.Internal; -using System; -using System.Linq; -using System.Linq.Expressions; using AutoMapper.Execution; namespace AutoMapper.UnitTests; diff --git a/src/UnitTests/Internal/TypeMapFactorySpecs.cs b/src/UnitTests/Internal/TypeMapFactorySpecs.cs index 7b79b193be..7cf0081e2a 100644 --- a/src/UnitTests/Internal/TypeMapFactorySpecs.cs +++ b/src/UnitTests/Internal/TypeMapFactorySpecs.cs @@ -1,14 +1,6 @@ -using System.Linq; using System.Text.RegularExpressions; -using Xunit; -using Shouldly; -using AutoMapper.Configuration.Conventions; namespace AutoMapper.UnitTests.Tests; - -using AutoMapper.Internal; -using System; - public class StubNamingConvention : INamingConvention { public Regex SplittingExpression { get; set; } diff --git a/src/UnitTests/Internationalization.cs b/src/UnitTests/Internationalization.cs index 6f0a8e466c..2fa4b437e2 100644 --- a/src/UnitTests/Internationalization.cs +++ b/src/UnitTests/Internationalization.cs @@ -1,6 +1,3 @@ -using Xunit; -using Shouldly; - namespace AutoMapper.UnitTests { namespace Internationalization diff --git a/src/UnitTests/MapToAttributeTest.cs b/src/UnitTests/MapToAttributeTest.cs index 46cb564834..e084e65b5b 100644 --- a/src/UnitTests/MapToAttributeTest.cs +++ b/src/UnitTests/MapToAttributeTest.cs @@ -1,12 +1,4 @@ -using AutoMapper.Internal.Mappers; -using AutoMapper.Configuration.Conventions; -using Shouldly; -using Xunit; -using System; -using System.Reflection; -using System.Collections.Generic; -using System.Linq; -using AutoMapper.Internal; +using AutoMapper.Configuration.Conventions; namespace AutoMapper.UnitTests; diff --git a/src/UnitTests/Mappers/ConstructorMapperTests.cs b/src/UnitTests/Mappers/ConstructorMapperTests.cs index 7df0e3ded4..b212daae1a 100644 --- a/src/UnitTests/Mappers/ConstructorMapperTests.cs +++ b/src/UnitTests/Mappers/ConstructorMapperTests.cs @@ -1,6 +1,4 @@ -using Shouldly; -using Xunit; -namespace AutoMapper.UnitTests.Mappers; +namespace AutoMapper.UnitTests.Mappers; public class ConstructorMapperTests : AutoMapperSpecBase { diff --git a/src/UnitTests/Mappers/ConversionOperators.cs b/src/UnitTests/Mappers/ConversionOperators.cs index a543fee618..c00f6b5a53 100644 --- a/src/UnitTests/Mappers/ConversionOperators.cs +++ b/src/UnitTests/Mappers/ConversionOperators.cs @@ -1,7 +1,3 @@ -using Xunit; -using Shouldly; -using System; - namespace AutoMapper.UnitTests; public class Nullable_conversion_operator : NonValidatingSpecBase diff --git a/src/UnitTests/Mappers/ConvertMapperTests.cs b/src/UnitTests/Mappers/ConvertMapperTests.cs index f0b8b34a4c..f90a3e06ba 100644 --- a/src/UnitTests/Mappers/ConvertMapperTests.cs +++ b/src/UnitTests/Mappers/ConvertMapperTests.cs @@ -1,8 +1,4 @@ -using AutoMapper.Internal; -using AutoMapper.Internal.Mappers; -using Shouldly; -using System; -using Xunit; +using AutoMapper.Internal.Mappers; namespace AutoMapper.UnitTests.Mappers; diff --git a/src/UnitTests/Mappers/CustomMapperTests.cs b/src/UnitTests/Mappers/CustomMapperTests.cs index d9633f6c49..91d49191d7 100644 --- a/src/UnitTests/Mappers/CustomMapperTests.cs +++ b/src/UnitTests/Mappers/CustomMapperTests.cs @@ -1,13 +1,6 @@ -using System; -using Shouldly; -using System.Linq.Expressions; -using AutoMapper.Internal.Mappers; -using Xunit; -using AutoMapper.Internal; -using System.ComponentModel; +using AutoMapper.Internal.Mappers; using System.Globalization; namespace AutoMapper.UnitTests.Mappers; - using static TypeDescriptor; public class When_specifying_mapping_with_the_BCL_type_converter_class : NonValidatingSpecBase { diff --git a/src/UnitTests/Mappers/DynamicMapperTests.cs b/src/UnitTests/Mappers/DynamicMapperTests.cs index 58166df21d..b16a0fa0a2 100644 --- a/src/UnitTests/Mappers/DynamicMapperTests.cs +++ b/src/UnitTests/Mappers/DynamicMapperTests.cs @@ -1,8 +1,4 @@ -using System.Collections.Generic; -using System.Dynamic; -using System.Linq; -using Shouldly; -using Xunit; +using System.Dynamic; namespace AutoMapper.UnitTests.Mappers.Dynamic; diff --git a/src/UnitTests/Mappers/NameValueCollectionMapperTests.cs b/src/UnitTests/Mappers/NameValueCollectionMapperTests.cs index 7a973ef6e4..5cb9b66d8c 100644 --- a/src/UnitTests/Mappers/NameValueCollectionMapperTests.cs +++ b/src/UnitTests/Mappers/NameValueCollectionMapperTests.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Specialized; -using AutoMapper.Internal.Mappers; -using Shouldly; -using Xunit; +using System.Collections.Specialized; namespace AutoMapper.UnitTests.Mappers; diff --git a/src/UnitTests/Mappers/ReadOnlyCollectionMapperTests.cs b/src/UnitTests/Mappers/ReadOnlyCollectionMapperTests.cs index 73e2caa89b..403a9e76fa 100644 --- a/src/UnitTests/Mappers/ReadOnlyCollectionMapperTests.cs +++ b/src/UnitTests/Mappers/ReadOnlyCollectionMapperTests.cs @@ -1,12 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; -using System.Text; -using Shouldly; -using Xunit; - -namespace AutoMapper.UnitTests.Mappers +namespace AutoMapper.UnitTests.Mappers { namespace ReadOnlyCollections { diff --git a/src/UnitTests/Mappers/ReadOnlyDictionaryMapperTests.cs b/src/UnitTests/Mappers/ReadOnlyDictionaryMapperTests.cs index 163089f4f6..fdf1567aaf 100644 --- a/src/UnitTests/Mappers/ReadOnlyDictionaryMapperTests.cs +++ b/src/UnitTests/Mappers/ReadOnlyDictionaryMapperTests.cs @@ -1,9 +1,4 @@ -using System.Collections.Generic; -using System.Collections.ObjectModel; -using Shouldly; -using Xunit; - -namespace AutoMapper.UnitTests.Mappers.ReadOnlyDictionaryMapper; +namespace AutoMapper.UnitTests.Mappers.ReadOnlyDictionaryMapper; public class When_mapping_to_interface_readonly_dictionary : AutoMapperSpecBase { diff --git a/src/UnitTests/Mappers/StringDictionaryMapperTests.cs b/src/UnitTests/Mappers/StringDictionaryMapperTests.cs index dca397a9b7..c0585c6967 100644 --- a/src/UnitTests/Mappers/StringDictionaryMapperTests.cs +++ b/src/UnitTests/Mappers/StringDictionaryMapperTests.cs @@ -1,11 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; -using AutoMapper.Internal; -using Shouldly; -using Xunit; -using StringDictionary = System.Collections.Generic.Dictionary; +using StringDictionary = System.Collections.Generic.Dictionary; namespace AutoMapper.UnitTests.Mappers; diff --git a/src/UnitTests/Mappers/TypeHelperTests.cs b/src/UnitTests/Mappers/TypeHelperTests.cs index af41519a97..f6f4255e22 100644 --- a/src/UnitTests/Mappers/TypeHelperTests.cs +++ b/src/UnitTests/Mappers/TypeHelperTests.cs @@ -1,10 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using AutoMapper.Internal; -using Shouldly; -using Xunit; - namespace AutoMapper.UnitTests.Mappers; public class TypeHelperTests diff --git a/src/UnitTests/MappingExceptions.cs b/src/UnitTests/MappingExceptions.cs index 2411bc60b0..73bf4ac17f 100644 --- a/src/UnitTests/MappingExceptions.cs +++ b/src/UnitTests/MappingExceptions.cs @@ -1,8 +1,3 @@ -using System; -using System.Diagnostics; -using Xunit; -using Shouldly; - namespace AutoMapper.UnitTests.MappingExceptions; public class When_encountering_a_member_mapping_problem_during_mapping : NonValidatingSpecBase diff --git a/src/UnitTests/MappingExpressionFeatureWithReverseTest.cs b/src/UnitTests/MappingExpressionFeatureWithReverseTest.cs index 7bade8b588..bc1ea72810 100644 --- a/src/UnitTests/MappingExpressionFeatureWithReverseTest.cs +++ b/src/UnitTests/MappingExpressionFeatureWithReverseTest.cs @@ -1,10 +1,4 @@ using AutoMapper.Features; -using AutoMapper.Internal; -using Shouldly; -using System; -using System.Collections.Generic; -using System.Linq; -using Xunit; namespace AutoMapper.UnitTests; diff --git a/src/UnitTests/MappingExpressionFeatureWithoutReverseTest.cs b/src/UnitTests/MappingExpressionFeatureWithoutReverseTest.cs index c574bdfc68..1d7e3dde39 100644 --- a/src/UnitTests/MappingExpressionFeatureWithoutReverseTest.cs +++ b/src/UnitTests/MappingExpressionFeatureWithoutReverseTest.cs @@ -1,9 +1,4 @@ using AutoMapper.Features; -using AutoMapper.Internal; -using Shouldly; -using System.Collections.Generic; -using System.Linq; -using Xunit; namespace AutoMapper.UnitTests; diff --git a/src/UnitTests/MappingInheritance/ApplyIncludeBaseRecursively.cs b/src/UnitTests/MappingInheritance/ApplyIncludeBaseRecursively.cs index a4a9148222..55c9bb8097 100644 --- a/src/UnitTests/MappingInheritance/ApplyIncludeBaseRecursively.cs +++ b/src/UnitTests/MappingInheritance/ApplyIncludeBaseRecursively.cs @@ -1,9 +1,4 @@ -using System; -using Shouldly; -using AutoMapper; -using Xunit; - -namespace AutoMapper.UnitTests.MappingInheritance; +namespace AutoMapper.UnitTests.MappingInheritance; public class ApplyIncludeBaseRecursively : AutoMapperSpecBase { diff --git a/src/UnitTests/MappingInheritance/ConventionMappedCollectionShouldMapBaseTypes.cs b/src/UnitTests/MappingInheritance/ConventionMappedCollectionShouldMapBaseTypes.cs index ad4077d5a9..1c103da9e6 100644 --- a/src/UnitTests/MappingInheritance/ConventionMappedCollectionShouldMapBaseTypes.cs +++ b/src/UnitTests/MappingInheritance/ConventionMappedCollectionShouldMapBaseTypes.cs @@ -1,11 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Shouldly; -using Xunit; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class ConventionMappedCollectionShouldMapBaseTypes { diff --git a/src/UnitTests/MappingInheritance/IgnoreShouldBeInherited.cs b/src/UnitTests/MappingInheritance/IgnoreShouldBeInherited.cs index 4a58fbe889..6bd1ce7b93 100644 --- a/src/UnitTests/MappingInheritance/IgnoreShouldBeInherited.cs +++ b/src/UnitTests/MappingInheritance/IgnoreShouldBeInherited.cs @@ -1,8 +1,4 @@ -using System; -using Shouldly; -using Xunit; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class IgnoreShouldBeInheritedRegardlessOfMapOrder : AutoMapperSpecBase { diff --git a/src/UnitTests/MappingInheritance/IgnoreShouldBeInheritedIfConventionCannotMap.cs b/src/UnitTests/MappingInheritance/IgnoreShouldBeInheritedIfConventionCannotMap.cs index 423299e1ab..8aa68bdb65 100644 --- a/src/UnitTests/MappingInheritance/IgnoreShouldBeInheritedIfConventionCannotMap.cs +++ b/src/UnitTests/MappingInheritance/IgnoreShouldBeInheritedIfConventionCannotMap.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Xunit; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class IgnoreShouldBeInheritedIfConventionCannotMap { diff --git a/src/UnitTests/MappingInheritance/IncludeAllDerived.cs b/src/UnitTests/MappingInheritance/IncludeAllDerived.cs index 30f6cbabc0..6386a40d98 100644 --- a/src/UnitTests/MappingInheritance/IncludeAllDerived.cs +++ b/src/UnitTests/MappingInheritance/IncludeAllDerived.cs @@ -1,7 +1,4 @@ -using Shouldly; -using Xunit; - -namespace AutoMapper.UnitTests.MappingInheritance; +namespace AutoMapper.UnitTests.MappingInheritance; public class IncludeAllDerived : AutoMapperSpecBase { diff --git a/src/UnitTests/MappingInheritance/IncludeBaseBug.cs b/src/UnitTests/MappingInheritance/IncludeBaseBug.cs index 71125f878b..b46744635a 100644 --- a/src/UnitTests/MappingInheritance/IncludeBaseBug.cs +++ b/src/UnitTests/MappingInheritance/IncludeBaseBug.cs @@ -1,8 +1,4 @@ namespace AutoMapper.UnitTests.MappingInheritance; - -using Shouldly; -using System; -using Xunit; public class Include : AutoMapperSpecBase { public class From diff --git a/src/UnitTests/MappingInheritance/IncludeBaseShouldNotCreateMaps.cs b/src/UnitTests/MappingInheritance/IncludeBaseShouldNotCreateMaps.cs index 1fc074d9e8..ab7014dfc7 100644 --- a/src/UnitTests/MappingInheritance/IncludeBaseShouldNotCreateMaps.cs +++ b/src/UnitTests/MappingInheritance/IncludeBaseShouldNotCreateMaps.cs @@ -1,7 +1,4 @@ -using System; -using Xunit; - -namespace AutoMapper.UnitTests.MappingInheritance; +namespace AutoMapper.UnitTests.MappingInheritance; public class IncludeBaseShouldNotCreateMaps : AutoMapperSpecBase { diff --git a/src/UnitTests/MappingInheritance/IncludeBaseShouldValidateTypes.cs b/src/UnitTests/MappingInheritance/IncludeBaseShouldValidateTypes.cs index 353a6a6f48..63770b3abe 100644 --- a/src/UnitTests/MappingInheritance/IncludeBaseShouldValidateTypes.cs +++ b/src/UnitTests/MappingInheritance/IncludeBaseShouldValidateTypes.cs @@ -1,8 +1,4 @@ -using Shouldly; -using System; -using Xunit; - -namespace AutoMapper.UnitTests; +namespace AutoMapper.UnitTests; public class IncludeBaseShouldValidateTypes { diff --git a/src/UnitTests/MappingInheritance/IncludeBaseWithNonGenericUsage.cs b/src/UnitTests/MappingInheritance/IncludeBaseWithNonGenericUsage.cs index 091c431033..8aae990604 100644 --- a/src/UnitTests/MappingInheritance/IncludeBaseWithNonGenericUsage.cs +++ b/src/UnitTests/MappingInheritance/IncludeBaseWithNonGenericUsage.cs @@ -1,7 +1,3 @@ -using System; -using Shouldly; -using Xunit; - namespace AutoMapper.UnitTests.MappingInheritance; public class IncludeBaseWithNonGenericUsage : AutoMapperSpecBase diff --git a/src/UnitTests/MappingInheritance/IncludedBaseMappingShouldInheritBaseMappings.cs b/src/UnitTests/MappingInheritance/IncludedBaseMappingShouldInheritBaseMappings.cs index c9fc825dd8..35579223e7 100644 --- a/src/UnitTests/MappingInheritance/IncludedBaseMappingShouldInheritBaseMappings.cs +++ b/src/UnitTests/MappingInheritance/IncludedBaseMappingShouldInheritBaseMappings.cs @@ -1,11 +1,4 @@ -using Shouldly; -using Xunit; - -namespace AutoMapper.UnitTests.Bug; - -using AutoMapper; -using CustomMapping; - +namespace AutoMapper.UnitTests.Bug; public class IncludedMappingShouldInheritBaseMappings : NonValidatingSpecBase { diff --git a/src/UnitTests/MappingInheritance/IncludedMappingShouldInheritBaseMappings.cs b/src/UnitTests/MappingInheritance/IncludedMappingShouldInheritBaseMappings.cs index 972ee0c0f1..66eb31db63 100644 --- a/src/UnitTests/MappingInheritance/IncludedMappingShouldInheritBaseMappings.cs +++ b/src/UnitTests/MappingInheritance/IncludedMappingShouldInheritBaseMappings.cs @@ -1,9 +1,4 @@ -using Shouldly; -using System.Collections.Generic; -using System.Linq; -using Xunit; - -namespace AutoMapper.UnitTests; +namespace AutoMapper.UnitTests; public class ReadonlyCollectionPropertiesOverride : AutoMapperSpecBase { diff --git a/src/UnitTests/MappingInheritance/InheritanceWithoutIncludeShouldWork.cs b/src/UnitTests/MappingInheritance/InheritanceWithoutIncludeShouldWork.cs index ca9e281c44..2cd3926f51 100644 --- a/src/UnitTests/MappingInheritance/InheritanceWithoutIncludeShouldWork.cs +++ b/src/UnitTests/MappingInheritance/InheritanceWithoutIncludeShouldWork.cs @@ -1,8 +1,4 @@ namespace AutoMapper.UnitTests.MappingInheritance; - -using Shouldly; -using Xunit; - public class InheritanceWithoutIncludeShouldWork : AutoMapperSpecBase { public class FooBase { } diff --git a/src/UnitTests/MappingInheritance/MapToBaseClass.cs b/src/UnitTests/MappingInheritance/MapToBaseClass.cs index cf74825073..7609d2efe2 100644 --- a/src/UnitTests/MappingInheritance/MapToBaseClass.cs +++ b/src/UnitTests/MappingInheritance/MapToBaseClass.cs @@ -1,8 +1,4 @@ namespace AutoMapper.UnitTests.MappingInheritance; - -using System; -using Shouldly; -using Xunit; public class MapToBaseClass : AutoMapperSpecBase { A _destination; diff --git a/src/UnitTests/MappingInheritance/MultipleInheritedBaseMappingsOfSameTypeFails.cs b/src/UnitTests/MappingInheritance/MultipleInheritedBaseMappingsOfSameTypeFails.cs index 863b3e37dc..fd88c990f8 100644 --- a/src/UnitTests/MappingInheritance/MultipleInheritedBaseMappingsOfSameTypeFails.cs +++ b/src/UnitTests/MappingInheritance/MultipleInheritedBaseMappingsOfSameTypeFails.cs @@ -1,6 +1,4 @@ -using Xunit; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class MultipleMappingsOfSameTypeFails { diff --git a/src/UnitTests/MappingInheritance/OpenGenericsWithInheritance.cs b/src/UnitTests/MappingInheritance/OpenGenericsWithInheritance.cs index bf3f12a7e5..8723aa66fa 100644 --- a/src/UnitTests/MappingInheritance/OpenGenericsWithInheritance.cs +++ b/src/UnitTests/MappingInheritance/OpenGenericsWithInheritance.cs @@ -1,12 +1,4 @@ -using Shouldly; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Xunit; - -namespace AutoMapper.UnitTests; +namespace AutoMapper.UnitTests; public class OpenGenericsWithAs : AutoMapperSpecBase { diff --git a/src/UnitTests/MappingInheritance/OverrideIgnore.cs b/src/UnitTests/MappingInheritance/OverrideIgnore.cs index 3c49af8d54..b832a799d7 100644 --- a/src/UnitTests/MappingInheritance/OverrideIgnore.cs +++ b/src/UnitTests/MappingInheritance/OverrideIgnore.cs @@ -1,7 +1,4 @@ -using Shouldly; -using Xunit; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class OverrideIgnore { diff --git a/src/UnitTests/MappingInheritance/PreserveReferencesWithInheritance.cs b/src/UnitTests/MappingInheritance/PreserveReferencesWithInheritance.cs index 34a37aec15..55d18ed4b8 100644 --- a/src/UnitTests/MappingInheritance/PreserveReferencesWithInheritance.cs +++ b/src/UnitTests/MappingInheritance/PreserveReferencesWithInheritance.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using Xunit; - -namespace AutoMapper.UnitTests +namespace AutoMapper.UnitTests { namespace Source { diff --git a/src/UnitTests/MappingInheritance/PropertyOnMappingShouldResolveMostSpecificType.cs b/src/UnitTests/MappingInheritance/PropertyOnMappingShouldResolveMostSpecificType.cs index d24823f0c0..17ca78dbb6 100644 --- a/src/UnitTests/MappingInheritance/PropertyOnMappingShouldResolveMostSpecificType.cs +++ b/src/UnitTests/MappingInheritance/PropertyOnMappingShouldResolveMostSpecificType.cs @@ -1,8 +1,4 @@ -using System.Collections.Generic; -using Shouldly; -using Xunit; - -namespace AutoMapper.UnitTests.Bug; +namespace AutoMapper.UnitTests.Bug; public class PropertyOnMappingShouldResolveMostSpecificType { diff --git a/src/UnitTests/MappingInheritance/ReverseMapWithInclude.cs b/src/UnitTests/MappingInheritance/ReverseMapWithInclude.cs index 5d427cb003..33853aad08 100644 --- a/src/UnitTests/MappingInheritance/ReverseMapWithInclude.cs +++ b/src/UnitTests/MappingInheritance/ReverseMapWithInclude.cs @@ -1,9 +1,4 @@ namespace AutoMapper.UnitTests.MappingInheritance; - -using System; -using Shouldly; -using Xunit; - public class ReverseMapWithInclude : NonValidatingSpecBase { public class Duck : Animal { } diff --git a/src/UnitTests/MappingInheritance/ShouldInheritBeforeAndAfterMap.cs b/src/UnitTests/MappingInheritance/ShouldInheritBeforeAndAfterMap.cs index 976d4b0978..e1be498d61 100644 --- a/src/UnitTests/MappingInheritance/ShouldInheritBeforeAndAfterMap.cs +++ b/src/UnitTests/MappingInheritance/ShouldInheritBeforeAndAfterMap.cs @@ -1,9 +1,4 @@ -using System; -using AutoMapper.Internal.Mappers; -using Shouldly; -using Xunit; - -namespace AutoMapper.UnitTests.MappingInheritance; +namespace AutoMapper.UnitTests.MappingInheritance; public class ShouldInheritBeforeAndAfterMapOnlyOnce : AutoMapperSpecBase { diff --git a/src/UnitTests/MappingInheritance/ShouldSupportOnlyDestinationTypeBeingDerived.cs b/src/UnitTests/MappingInheritance/ShouldSupportOnlyDestinationTypeBeingDerived.cs index 9608ce9ce5..0aca4fe38c 100644 --- a/src/UnitTests/MappingInheritance/ShouldSupportOnlyDestinationTypeBeingDerived.cs +++ b/src/UnitTests/MappingInheritance/ShouldSupportOnlyDestinationTypeBeingDerived.cs @@ -1,8 +1,4 @@ -using System; -using Shouldly; -using Xunit; - -namespace AutoMapper.UnitTests.MappingInheritance; +namespace AutoMapper.UnitTests.MappingInheritance; public class AsWithMissingMap : NonValidatingSpecBase { diff --git a/src/UnitTests/MappingInheritance/SourceValidationWithInheritance.cs b/src/UnitTests/MappingInheritance/SourceValidationWithInheritance.cs index 311ee4ac59..232911b21d 100644 --- a/src/UnitTests/MappingInheritance/SourceValidationWithInheritance.cs +++ b/src/UnitTests/MappingInheritance/SourceValidationWithInheritance.cs @@ -1,7 +1,4 @@ -using System; -using Xunit; - -namespace AutoMapper.UnitTests; +namespace AutoMapper.UnitTests; public class SourceValidationWithInheritance : AutoMapperSpecBase { diff --git a/src/UnitTests/MappingOrder.cs b/src/UnitTests/MappingOrder.cs index 3974ea7415..8343b38a79 100644 --- a/src/UnitTests/MappingOrder.cs +++ b/src/UnitTests/MappingOrder.cs @@ -1,7 +1,3 @@ -using Xunit; -using Shouldly; -using System; - namespace AutoMapper.UnitTests { namespace MappingOrder diff --git a/src/UnitTests/MaxDepthTests.cs b/src/UnitTests/MaxDepthTests.cs index 1c1259eed9..581485ca9c 100644 --- a/src/UnitTests/MaxDepthTests.cs +++ b/src/UnitTests/MaxDepthTests.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Text; -using Shouldly; -using Xunit; - -namespace AutoMapper.UnitTests; +namespace AutoMapper.UnitTests; public class MaxDepthTests { diff --git a/src/UnitTests/MaxExecutionPlanDepth.cs b/src/UnitTests/MaxExecutionPlanDepth.cs index 71182b1853..e5c61011ac 100644 --- a/src/UnitTests/MaxExecutionPlanDepth.cs +++ b/src/UnitTests/MaxExecutionPlanDepth.cs @@ -1,11 +1,4 @@ -using AutoMapper; -using System; -using System.Linq; -using Xunit; -using Shouldly; -using AutoMapper.Internal; - -namespace AutoMapper.UnitTests; +namespace AutoMapper.UnitTests; public class MaxExecutionPlanDepth : AutoMapperSpecBase { diff --git a/src/UnitTests/MemberNameReplacers.cs b/src/UnitTests/MemberNameReplacers.cs index 3a394899ce..161e4fc763 100644 --- a/src/UnitTests/MemberNameReplacers.cs +++ b/src/UnitTests/MemberNameReplacers.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Xunit; - -namespace AutoMapper.UnitTests; +namespace AutoMapper.UnitTests; public class When_using_a_member_name_replacer : NonValidatingSpecBase { diff --git a/src/UnitTests/MemberResolution.cs b/src/UnitTests/MemberResolution.cs index 922dcd2079..5a90d4841c 100644 --- a/src/UnitTests/MemberResolution.cs +++ b/src/UnitTests/MemberResolution.cs @@ -1,7 +1,3 @@ -using System; -using System.Collections.Generic; -using Shouldly; -using Xunit; namespace AutoMapper.UnitTests.MemberResolution; public class When_multiple_source_members_match_postfix : AutoMapperSpecBase diff --git a/src/UnitTests/NestedContainers.cs b/src/UnitTests/NestedContainers.cs index a171aee1b9..00cba5faef 100644 --- a/src/UnitTests/NestedContainers.cs +++ b/src/UnitTests/NestedContainers.cs @@ -1,7 +1,3 @@ -using System; -using Xunit; -using Shouldly; - namespace AutoMapper.UnitTests { namespace NestedContainers diff --git a/src/UnitTests/NullBehavior.cs b/src/UnitTests/NullBehavior.cs index 59e8ee79ed..eeb0a1bad1 100644 --- a/src/UnitTests/NullBehavior.cs +++ b/src/UnitTests/NullBehavior.cs @@ -1,11 +1,3 @@ -using System.Linq; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using Shouldly; -using Xunit; -using System.Collections; -using System; - namespace AutoMapper.UnitTests.NullBehavior; public class NullCheckDefault : AutoMapperSpecBase diff --git a/src/UnitTests/OpenGenerics.cs b/src/UnitTests/OpenGenerics.cs index d91ba4554b..c422fcaf4e 100644 --- a/src/UnitTests/OpenGenerics.cs +++ b/src/UnitTests/OpenGenerics.cs @@ -1,10 +1,4 @@ -using Shouldly; -using System; -using System.Collections.Generic; -using System.Linq; -using Xunit; - -namespace AutoMapper.UnitTests; +namespace AutoMapper.UnitTests; public class SealGenerics : AutoMapperSpecBase { diff --git a/src/UnitTests/Profiles.cs b/src/UnitTests/Profiles.cs index 62782117f4..1a458e810f 100644 --- a/src/UnitTests/Profiles.cs +++ b/src/UnitTests/Profiles.cs @@ -1,7 +1,3 @@ -using System; -using Shouldly; -using Xunit; - namespace AutoMapper.UnitTests { namespace Profiles diff --git a/src/UnitTests/Projection/ConstructorTests.cs b/src/UnitTests/Projection/ConstructorTests.cs index 60e973ce34..74156d00c5 100644 --- a/src/UnitTests/Projection/ConstructorTests.cs +++ b/src/UnitTests/Projection/ConstructorTests.cs @@ -1,10 +1,4 @@ -using System.Collections.Generic; -using System.Linq; -using AutoMapper.QueryableExtensions; -using Shouldly; -using Xunit; - -namespace AutoMapper.UnitTests.Projection; +namespace AutoMapper.UnitTests.Projection; public class ConstructorLetClause : AutoMapperSpecBase { diff --git a/src/UnitTests/Projection/ExplicitExpansion.cs b/src/UnitTests/Projection/ExplicitExpansion.cs index e8d9457a21..47c80e99de 100644 --- a/src/UnitTests/Projection/ExplicitExpansion.cs +++ b/src/UnitTests/Projection/ExplicitExpansion.cs @@ -1,10 +1,4 @@ namespace AutoMapper.UnitTests.Projection; - -using System.Linq; -using QueryableExtensions; -using Shouldly; -using Xunit; - public class ExplicitExpansion : AutoMapperSpecBase { private Dest[] _dests; diff --git a/src/UnitTests/Projection/ExplicitExpansionWithInheritance.cs b/src/UnitTests/Projection/ExplicitExpansionWithInheritance.cs index cd42517d24..738fd9f6a8 100644 --- a/src/UnitTests/Projection/ExplicitExpansionWithInheritance.cs +++ b/src/UnitTests/Projection/ExplicitExpansionWithInheritance.cs @@ -1,12 +1,4 @@ -using AutoMapper.QueryableExtensions; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Xunit; - -namespace AutoMapper.UnitTests.Projection; +namespace AutoMapper.UnitTests.Projection; public class ExplicitExpansionWithInheritance : AutoMapperSpecBase { diff --git a/src/UnitTests/Projection/ExplicitValues.cs b/src/UnitTests/Projection/ExplicitValues.cs index 687a651e21..97cd6d4121 100644 --- a/src/UnitTests/Projection/ExplicitValues.cs +++ b/src/UnitTests/Projection/ExplicitValues.cs @@ -1,11 +1,4 @@ namespace AutoMapper.UnitTests.Projection; - -using System.Collections.Generic; -using System.Linq; -using QueryableExtensions; -using Shouldly; -using Xunit; - public class ExplicitValues : AutoMapperSpecBase { private List _dests; diff --git a/src/UnitTests/Projection/GenericsTests.cs b/src/UnitTests/Projection/GenericsTests.cs index 3824dd5c3e..a5e2c50088 100644 --- a/src/UnitTests/Projection/GenericsTests.cs +++ b/src/UnitTests/Projection/GenericsTests.cs @@ -1,10 +1,4 @@ namespace AutoMapper.UnitTests.Projection; - -using System.Linq; -using QueryableExtensions; -using Shouldly; -using Xunit; - public class GenericsTests : AutoMapperSpecBase { private Dest[] _dests; diff --git a/src/UnitTests/Projection/InheritedMaps.cs b/src/UnitTests/Projection/InheritedMaps.cs index 70074e8d74..30e75ccd34 100644 --- a/src/UnitTests/Projection/InheritedMaps.cs +++ b/src/UnitTests/Projection/InheritedMaps.cs @@ -2,11 +2,6 @@ { namespace InheritedMaps { - using System.Linq; - using QueryableExtensions; - using Shouldly; - using Xunit; - public class SourceBase { public int OtherValue { get; set; } diff --git a/src/UnitTests/Projection/MapFromTest.cs b/src/UnitTests/Projection/MapFromTest.cs index 749f88865f..be0ae0591e 100644 --- a/src/UnitTests/Projection/MapFromTest.cs +++ b/src/UnitTests/Projection/MapFromTest.cs @@ -1,14 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using Shouldly; -using Xunit; -using AutoMapper.QueryableExtensions; -using AutoMapper.QueryableExtensions.Impl; -using AutoMapper.Internal; - -namespace AutoMapper.UnitTests.Projection.MapFromTest; +namespace AutoMapper.UnitTests.Projection.MapFromTest; public class CustomMapFromExpressionTest { diff --git a/src/UnitTests/Projection/MoreExplanatoryExceptionTests.cs b/src/UnitTests/Projection/MoreExplanatoryExceptionTests.cs index 32ccce1a71..ca120bb16b 100644 --- a/src/UnitTests/Projection/MoreExplanatoryExceptionTests.cs +++ b/src/UnitTests/Projection/MoreExplanatoryExceptionTests.cs @@ -1,12 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Xunit; -using AutoMapper.QueryableExtensions; - -namespace AutoMapper.UnitTests.Projection; +namespace AutoMapper.UnitTests.Projection; public class MoreExplanatoryExceptionTests { diff --git a/src/UnitTests/Projection/NestedAndArraysTests.cs b/src/UnitTests/Projection/NestedAndArraysTests.cs index 5bb99b537b..c469785685 100644 --- a/src/UnitTests/Projection/NestedAndArraysTests.cs +++ b/src/UnitTests/Projection/NestedAndArraysTests.cs @@ -2,12 +2,6 @@ { namespace NestedAndArraysTests { - using System.Collections.Generic; - using QueryableExtensions.Impl; - using Xunit; - using System.Linq; - using AutoMapper.Internal; - public class LinqTests { diff --git a/src/UnitTests/Projection/NestedExpressionsMapFromTests.cs b/src/UnitTests/Projection/NestedExpressionsMapFromTests.cs index f336731301..17da743131 100644 --- a/src/UnitTests/Projection/NestedExpressionsMapFromTests.cs +++ b/src/UnitTests/Projection/NestedExpressionsMapFromTests.cs @@ -2,12 +2,6 @@ { namespace NestedExpressionTests { - using System.Collections.Generic; - using System.Linq; - using QueryableExtensions; - using Shouldly; - using Xunit; - public class NestedExpressionMapFromTests { private MapperConfiguration _config; diff --git a/src/UnitTests/Projection/NonGenericQueryableTests.cs b/src/UnitTests/Projection/NonGenericQueryableTests.cs index 241c6b77ac..82e2298d69 100644 --- a/src/UnitTests/Projection/NonGenericQueryableTests.cs +++ b/src/UnitTests/Projection/NonGenericQueryableTests.cs @@ -1,11 +1,4 @@ namespace AutoMapper.UnitTests.Projection; - -using AutoMapper.QueryableExtensions; -using Shouldly; -using System.Collections.Generic; -using System.Linq; -using Xunit; - public class NonGenericQueryableTests { private MapperConfiguration _config; diff --git a/src/UnitTests/Projection/NullSubstitutes.cs b/src/UnitTests/Projection/NullSubstitutes.cs index 6e68b321e5..6d9f5f5f08 100644 --- a/src/UnitTests/Projection/NullSubstitutes.cs +++ b/src/UnitTests/Projection/NullSubstitutes.cs @@ -1,11 +1,4 @@ namespace AutoMapper.UnitTests.Projection; - -using System.Collections.Generic; -using System.Linq; -using QueryableExtensions; -using Shouldly; -using Xunit; - public class NullSubstitutes : AutoMapperSpecBase { private List _dests; diff --git a/src/UnitTests/Projection/ParameterizedQueriesTests.cs b/src/UnitTests/Projection/ParameterizedQueriesTests.cs index dec2ff88d5..a38cbf7358 100644 --- a/src/UnitTests/Projection/ParameterizedQueriesTests.cs +++ b/src/UnitTests/Projection/ParameterizedQueriesTests.cs @@ -1,13 +1,4 @@ namespace AutoMapper.UnitTests.Projection; - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using QueryableExtensions; -using Shouldly; -using Xunit; - public class ParameterizedQueriesTests_with_anonymous_object_and_factory : AutoMapperSpecBase { private Dest[] _dests; diff --git a/src/UnitTests/Projection/PrimitiveArraysTest.cs b/src/UnitTests/Projection/PrimitiveArraysTest.cs index f1f7dd0896..1c0c63d704 100644 --- a/src/UnitTests/Projection/PrimitiveArraysTest.cs +++ b/src/UnitTests/Projection/PrimitiveArraysTest.cs @@ -1,17 +1,7 @@ -using System; -using System.Collections.Generic; -using Xunit; -using System.Linq; -using Shouldly; - -namespace AutoMapper.UnitTests.Projection +namespace AutoMapper.UnitTests.Projection { namespace PrimitiveArrays { - using AutoMapper.Internal; - using QueryableExtensions; - using QueryableExtensions.Impl; - public class PrimitiveArraysExpressionTest { [Fact] diff --git a/src/UnitTests/Projection/ProjectCollectionEnumerableTest.cs b/src/UnitTests/Projection/ProjectCollectionEnumerableTest.cs index 2e2e16427a..f20975567b 100644 --- a/src/UnitTests/Projection/ProjectCollectionEnumerableTest.cs +++ b/src/UnitTests/Projection/ProjectCollectionEnumerableTest.cs @@ -1,13 +1,4 @@ -using Shouldly; -using Xunit; - -namespace AutoMapper.UnitTests.Projection; - -using System.Collections.Generic; -using System.Linq; - -using AutoMapper; -using QueryableExtensions; +namespace AutoMapper.UnitTests.Projection; public class ProjectCollectionEnumerableTest { diff --git a/src/UnitTests/Projection/ProjectCollectionListTest.cs b/src/UnitTests/Projection/ProjectCollectionListTest.cs index 19ed0f81bc..c6521aa244 100644 --- a/src/UnitTests/Projection/ProjectCollectionListTest.cs +++ b/src/UnitTests/Projection/ProjectCollectionListTest.cs @@ -1,16 +1,4 @@ -using Shouldly; -using Xunit; - -namespace AutoMapper.UnitTests.Projection; - -using System; -using System.Collections.Generic; -using System.Linq; - -using AutoMapper; -using QueryableExtensions; - - +namespace AutoMapper.UnitTests.Projection; public class ProjectCollectionListTest { private MapperConfiguration _config; diff --git a/src/UnitTests/Projection/ProjectEnumTest.cs b/src/UnitTests/Projection/ProjectEnumTest.cs index cf7438ae5f..7caa8804e1 100644 --- a/src/UnitTests/Projection/ProjectEnumTest.cs +++ b/src/UnitTests/Projection/ProjectEnumTest.cs @@ -1,12 +1,4 @@ -using System; - -namespace AutoMapper.UnitTests.Projection; - -using QueryableExtensions; -using Shouldly; -using System.Linq; -using Xunit; - +namespace AutoMapper.UnitTests.Projection; public class ProjectEnumTest { private MapperConfiguration _config; diff --git a/src/UnitTests/Projection/ProjectEnumerableToArrayTest.cs b/src/UnitTests/Projection/ProjectEnumerableToArrayTest.cs index 4345a7317f..3c91985ff3 100644 --- a/src/UnitTests/Projection/ProjectEnumerableToArrayTest.cs +++ b/src/UnitTests/Projection/ProjectEnumerableToArrayTest.cs @@ -1,14 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Xunit; -using Shouldly; - -namespace AutoMapper.UnitTests.Projection; - -using QueryableExtensions; - +namespace AutoMapper.UnitTests.Projection; public class ProjectEnumerableToArrayTest { private MapperConfiguration _config; diff --git a/src/UnitTests/Projection/ProjectIReadOnlyCollection.cs b/src/UnitTests/Projection/ProjectIReadOnlyCollection.cs index 12f0d14439..e53fde0b8f 100644 --- a/src/UnitTests/Projection/ProjectIReadOnlyCollection.cs +++ b/src/UnitTests/Projection/ProjectIReadOnlyCollection.cs @@ -1,14 +1,4 @@ -using Shouldly; -using Xunit; - -namespace AutoMapper.UnitTests.Projection; - -using System.Collections.Generic; -using System.Linq; - -using AutoMapper; -using QueryableExtensions; - +namespace AutoMapper.UnitTests.Projection; public class ProjectIReadOnlyCollection { private MapperConfiguration _config; diff --git a/src/UnitTests/Projection/ProjectTest.cs b/src/UnitTests/Projection/ProjectTest.cs index ffff115a30..ded6a5e948 100644 --- a/src/UnitTests/Projection/ProjectTest.cs +++ b/src/UnitTests/Projection/ProjectTest.cs @@ -1,15 +1,4 @@ -using Xunit; -using Shouldly; - -namespace AutoMapper.UnitTests.Projection; - -using System; -using System.Collections.Generic; -using System.Linq; - -using AutoMapper; -using QueryableExtensions; - +namespace AutoMapper.UnitTests.Projection; public class ProjectWithFields : AutoMapperSpecBase { public class Foo diff --git a/src/UnitTests/Projection/ProjectionMappers.cs b/src/UnitTests/Projection/ProjectionMappers.cs index fdc79d299d..f0607d0858 100644 --- a/src/UnitTests/Projection/ProjectionMappers.cs +++ b/src/UnitTests/Projection/ProjectionMappers.cs @@ -1,17 +1,5 @@ -using System; -using AutoMapper.QueryableExtensions; -using System.Linq; -using Xunit; -using Shouldly; -using System.Linq.Expressions; -using System.Reflection; -using AutoMapper.QueryableExtensions.Impl; -using AutoMapper.Internal; - +using AutoMapper.QueryableExtensions.Impl; namespace AutoMapper.UnitTests.Projection; - -using static Expression; - public class ProjectionMappers : AutoMapperSpecBase { class Source @@ -39,7 +27,7 @@ public void Should_work_with_projections() private class EnumToUnderlyingTypeProjectionMapper : IProjectionMapper { public Expression Project(IGlobalConfiguration configuration, in ProjectionRequest request, Expression resolvedSource, LetPropertyMaps letPropertyMaps) => - Convert(resolvedSource, request.DestinationType); + Expression.Convert(resolvedSource, request.DestinationType); public bool IsMatch(TypePair context) => context.SourceType.IsEnum && Enum.GetUnderlyingType(context.SourceType) == context.DestinationType; } diff --git a/src/UnitTests/Projection/ProjectionTests.cs b/src/UnitTests/Projection/ProjectionTests.cs index 581e993a98..8b6b454404 100644 --- a/src/UnitTests/Projection/ProjectionTests.cs +++ b/src/UnitTests/Projection/ProjectionTests.cs @@ -1,11 +1,4 @@ -using System.Linq; -using Xunit; -using Shouldly; -using AutoMapper; -using AutoMapper.QueryableExtensions; -using System.Collections.Generic; - -namespace AutoMapper.UnitTests.Projection; +namespace AutoMapper.UnitTests.Projection; public class NonNullableToNullable : AutoMapperSpecBase { diff --git a/src/UnitTests/Projection/RecursiveQuery.cs b/src/UnitTests/Projection/RecursiveQuery.cs index 2437e1f622..fbb8f0600d 100644 --- a/src/UnitTests/Projection/RecursiveQuery.cs +++ b/src/UnitTests/Projection/RecursiveQuery.cs @@ -1,13 +1,4 @@ -using AutoMapper.Internal; -using Shouldly; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Xunit; - -namespace AutoMapper.UnitTests.Projection; +namespace AutoMapper.UnitTests.Projection; public class RecursiveQuery : AutoMapperSpecBase { diff --git a/src/UnitTests/Projection/ToStringTests.cs b/src/UnitTests/Projection/ToStringTests.cs index 9f3a712df8..ac5ab7614d 100644 --- a/src/UnitTests/Projection/ToStringTests.cs +++ b/src/UnitTests/Projection/ToStringTests.cs @@ -1,10 +1,4 @@ namespace AutoMapper.UnitTests.Projection; - -using System.Linq; -using QueryableExtensions; -using Shouldly; -using Xunit; - public class ToStringTests : AutoMapperSpecBase { private Dest[] _dests; diff --git a/src/UnitTests/Regression.cs b/src/UnitTests/Regression.cs index 5257b26617..7bf68fa64c 100644 --- a/src/UnitTests/Regression.cs +++ b/src/UnitTests/Regression.cs @@ -1,11 +1,3 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using Shouldly; -using Xunit; -using System.Linq; - namespace AutoMapper.UnitTests { namespace Regression diff --git a/src/UnitTests/ReverseMapWithPreserveReferences.cs b/src/UnitTests/ReverseMapWithPreserveReferences.cs index d401775c14..3a1b588cf4 100644 --- a/src/UnitTests/ReverseMapWithPreserveReferences.cs +++ b/src/UnitTests/ReverseMapWithPreserveReferences.cs @@ -1,9 +1,4 @@ -using System.Collections.Generic; -using System.Linq; -using Shouldly; -using Xunit; - -namespace AutoMapper.UnitTests; +namespace AutoMapper.UnitTests; public class ReverseMapWithPreserveReferences : AutoMapperSpecBase { diff --git a/src/UnitTests/ReverseMapWithoutPreserveReferences.cs b/src/UnitTests/ReverseMapWithoutPreserveReferences.cs index 564986e4b5..6775116c5b 100644 --- a/src/UnitTests/ReverseMapWithoutPreserveReferences.cs +++ b/src/UnitTests/ReverseMapWithoutPreserveReferences.cs @@ -1,9 +1,4 @@ -using System.Collections.Generic; -using System.Linq; -using Shouldly; -using Xunit; - -namespace AutoMapper.UnitTests; +namespace AutoMapper.UnitTests; public class ReverseMapWithoutPreserveReferences : AutoMapperSpecBase { diff --git a/src/UnitTests/ReverseMapping.cs b/src/UnitTests/ReverseMapping.cs index d472823577..5eb946c964 100644 --- a/src/UnitTests/ReverseMapping.cs +++ b/src/UnitTests/ReverseMapping.cs @@ -1,10 +1,4 @@ -using Xunit; -using Shouldly; -using System.Linq; -using System; using System.Text.RegularExpressions; -using System.Reflection; -using AutoMapper.Internal; namespace AutoMapper.UnitTests; diff --git a/src/UnitTests/SeparateConfiguration.cs b/src/UnitTests/SeparateConfiguration.cs index f04b60e588..f71e8d6783 100644 --- a/src/UnitTests/SeparateConfiguration.cs +++ b/src/UnitTests/SeparateConfiguration.cs @@ -1,9 +1,4 @@ namespace AutoMapper.UnitTests; - -using Configuration; -using Shouldly; -using Xunit; - public class SeparateConfiguration : NonValidatingSpecBase { public class Source diff --git a/src/UnitTests/ShouldMapMethod.cs b/src/UnitTests/ShouldMapMethod.cs index dec8b1c161..041aef6025 100644 --- a/src/UnitTests/ShouldMapMethod.cs +++ b/src/UnitTests/ShouldMapMethod.cs @@ -1,8 +1,4 @@ -using Xunit; -using Shouldly; -using System; - -namespace AutoMapper.UnitTests; +namespace AutoMapper.UnitTests; public class ShouldIgnoreOpenGenericMethods : NonValidatingSpecBase { diff --git a/src/UnitTests/ShouldUseConstructor.cs b/src/UnitTests/ShouldUseConstructor.cs index 5228a5c4cc..191bf8faec 100644 --- a/src/UnitTests/ShouldUseConstructor.cs +++ b/src/UnitTests/ShouldUseConstructor.cs @@ -1,8 +1,4 @@ -using System.Linq; -using Shouldly; -using Xunit; - -namespace AutoMapper.UnitTests; +namespace AutoMapper.UnitTests; public class ShouldUseConstructorInternal : NonValidatingSpecBase { diff --git a/src/UnitTests/TesterExtensions.cs b/src/UnitTests/TesterExtensions.cs index 127448baea..7afad44d7e 100644 --- a/src/UnitTests/TesterExtensions.cs +++ b/src/UnitTests/TesterExtensions.cs @@ -1,7 +1,3 @@ -using System.Collections.Generic; -using System.Linq; -using Shouldly; - namespace AutoMapper.UnitTests; public static class StopgapNBehaveExtensions diff --git a/src/UnitTests/TypeConverters.cs b/src/UnitTests/TypeConverters.cs index 0d55db210c..d05f334c8c 100644 --- a/src/UnitTests/TypeConverters.cs +++ b/src/UnitTests/TypeConverters.cs @@ -1,7 +1,3 @@ -using System; -using System.Collections.Generic; -using Shouldly; -using Xunit; namespace AutoMapper.UnitTests.CustomMapping; public class NullableConverter : AutoMapperSpecBase @@ -198,7 +194,7 @@ public Type Convert(string source, Type destination, ResolutionContext context) protected override MapperConfiguration CreateConfiguration() => new(cfg => { - cfg.CreateMap().ConvertUsing((string arg) => Convert.ToInt32(arg)); + cfg.CreateMap().ConvertUsing((string arg) => System.Convert.ToInt32(arg)); cfg.CreateMap().ConvertUsing(new DateTimeTypeConverter()); cfg.CreateMap().ConvertUsing(); cfg.CreateMap(); @@ -262,7 +258,7 @@ public class ParentDestination protected override MapperConfiguration CreateConfiguration() => new(cfg => { - cfg.CreateMap().ConvertUsing(arg => new Destination {Type = Convert.ToInt32(arg.Foo)}); + cfg.CreateMap().ConvertUsing(arg => new Destination {Type = System.Convert.ToInt32(arg.Foo)}); cfg.CreateMap(); }); diff --git a/src/UnitTests/TypeExtensionsTests.cs b/src/UnitTests/TypeExtensionsTests.cs index bc8d8a4ac6..54ba1e1634 100644 --- a/src/UnitTests/TypeExtensionsTests.cs +++ b/src/UnitTests/TypeExtensionsTests.cs @@ -1,8 +1,4 @@ namespace AutoMapper.UnitTests; - -using Shouldly; -using Xunit; - public class TypeExtensionsTests { public class Foo diff --git a/src/UnitTests/UsingEngineInsideMap.cs b/src/UnitTests/UsingEngineInsideMap.cs index c7ed8bc600..8bc0a455f9 100644 --- a/src/UnitTests/UsingEngineInsideMap.cs +++ b/src/UnitTests/UsingEngineInsideMap.cs @@ -1,8 +1,4 @@ namespace AutoMapper.UnitTests; - -using Shouldly; -using Xunit; - public class UsingEngineInsideMap : AutoMapperSpecBase { private Dest _dest; diff --git a/src/UnitTests/ValueConverters.cs b/src/UnitTests/ValueConverters.cs index f79455e9ec..da0965541c 100644 --- a/src/UnitTests/ValueConverters.cs +++ b/src/UnitTests/ValueConverters.cs @@ -1,8 +1,4 @@ -using Shouldly; -using System; -using Xunit; - -namespace AutoMapper.UnitTests; +namespace AutoMapper.UnitTests; public class ValueConverters { diff --git a/src/UnitTests/ValueTransformers.cs b/src/UnitTests/ValueTransformers.cs index 99ac36fb7d..8f80fb3a1b 100644 --- a/src/UnitTests/ValueTransformers.cs +++ b/src/UnitTests/ValueTransformers.cs @@ -1,7 +1,4 @@ -using Shouldly; -using Xunit; - -namespace AutoMapper.UnitTests +namespace AutoMapper.UnitTests { namespace ValueTransformers { diff --git a/src/UnitTests/ValueTypes.cs b/src/UnitTests/ValueTypes.cs index 415ca4e2e2..83a6db6e41 100644 --- a/src/UnitTests/ValueTypes.cs +++ b/src/UnitTests/ValueTypes.cs @@ -1,8 +1,3 @@ -using System; -using Xunit; -using Shouldly; -using System.Linq; - namespace AutoMapper.UnitTests.ValueTypes; public class When_value_types_are_the_source_of_map_cycles : AutoMapperSpecBase @@ -181,8 +176,8 @@ public struct Destination protected override MapperConfiguration CreateConfiguration() => new(cfg => { - cfg.CreateMap().ConvertUsing((string s) => Convert.ToInt32(s)); - cfg.CreateMap().ConvertUsing((string s) => (int?) Convert.ToInt32(s)); + cfg.CreateMap().ConvertUsing((string s) => System.Convert.ToInt32(s)); + cfg.CreateMap().ConvertUsing((string s) => (int?) System.Convert.ToInt32(s)); cfg.CreateMap(); }); From e6f2ca3f0bfa1f0a6118843cc2c283b60256f9dd Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Sun, 4 Sep 2022 13:45:20 +0300 Subject: [PATCH 50/67] cosmetic --- src/AutoMapper/ApiCompatBaseline.txt | 7 ++++++- src/AutoMapper/Configuration/IMappingOperationOptions.cs | 4 ++-- src/AutoMapper/ResolutionContext.cs | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/AutoMapper/ApiCompatBaseline.txt b/src/AutoMapper/ApiCompatBaseline.txt index 7a93b4f49e..a02376fec9 100644 --- a/src/AutoMapper/ApiCompatBaseline.txt +++ b/src/AutoMapper/ApiCompatBaseline.txt @@ -10,6 +10,9 @@ MembersMustExist : Member 'public System.Text.RegularExpressions.Regex AutoMappe InterfacesShouldHaveSameMembers : Interface member 'public TMappingExpression AutoMapper.IMappingExpressionBase.AsProxy()' is present in the implementation but not in the contract. InterfacesShouldHaveSameMembers : Interface member 'public void AutoMapper.IMappingExpressionBase.AsProxy()' is present in the contract but not in the implementation. MembersMustExist : Member 'public void AutoMapper.IMappingExpressionBase.AsProxy()' does not exist in the implementation but it does exist in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public System.Collections.Generic.Dictionary AutoMapper.IMappingOperationOptions.Items.get()' is present in the implementation but not in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public System.Collections.Generic.IDictionary AutoMapper.IMappingOperationOptions.Items.get()' is present in the contract but not in the implementation. +MembersMustExist : Member 'public System.Collections.Generic.IDictionary AutoMapper.IMappingOperationOptions.Items.get()' does not exist in the implementation but it does exist in the contract. InterfacesShouldHaveSameMembers : Interface member 'public System.Text.RegularExpressions.Regex AutoMapper.INamingConvention.SplittingExpression' is present in the contract but not in the implementation. InterfacesShouldHaveSameMembers : Interface member 'public System.String AutoMapper.INamingConvention.ReplaceValue(System.Text.RegularExpressions.Match)' is present in the contract but not in the implementation. MembersMustExist : Member 'public System.String AutoMapper.INamingConvention.ReplaceValue(System.Text.RegularExpressions.Match)' does not exist in the implementation but it does exist in the contract. @@ -28,6 +31,7 @@ MembersMustExist : Member 'public System.Collections.Generic.IReadOnlyCollection CannotSealType : Type 'AutoMapper.LowerUnderscoreNamingConvention' is actually (has the sealed modifier) sealed in the implementation but not sealed in the contract. MembersMustExist : Member 'public System.String AutoMapper.LowerUnderscoreNamingConvention.ReplaceValue(System.Text.RegularExpressions.Match)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Text.RegularExpressions.Regex AutoMapper.LowerUnderscoreNamingConvention.SplittingExpression.get()' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public System.Collections.Generic.IDictionary AutoMapper.MappingOperationOptions.Items.get()' does not exist in the implementation but it does exist in the contract. CannotSealType : Type 'AutoMapper.PascalCaseNamingConvention' is actually (has the sealed modifier) sealed in the implementation but not sealed in the contract. MembersMustExist : Member 'public System.String AutoMapper.PascalCaseNamingConvention.ReplaceValue(System.Text.RegularExpressions.Match)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Text.RegularExpressions.Regex AutoMapper.PascalCaseNamingConvention.SplittingExpression.get()' does not exist in the implementation but it does exist in the contract. @@ -35,6 +39,7 @@ CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.CompilerGener CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.CompilerGeneratedAttribute' exists on 'AutoMapper.Profile.DestinationMemberNamingConvention.set(AutoMapper.INamingConvention)' in the contract but not the implementation. CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.CompilerGeneratedAttribute' exists on 'AutoMapper.Profile.SourceMemberNamingConvention.get()' in the contract but not the implementation. CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.CompilerGeneratedAttribute' exists on 'AutoMapper.Profile.SourceMemberNamingConvention.set(AutoMapper.INamingConvention)' in the contract but not the implementation. +MembersMustExist : Member 'public System.Collections.Generic.IDictionary AutoMapper.ResolutionContext.Items.get()' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public AutoMapper.IMappingOperationOptions AutoMapper.ResolutionContext.Options.get()' does not exist in the implementation but it does exist in the contract. TypesMustExist : Type 'AutoMapper.ValueResolverConfiguration' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Linq.Expressions.LambdaExpression System.Linq.Expressions.LambdaExpression AutoMapper.ValueTransformerConfiguration.TransformerExpression' does not exist in the implementation but it does exist in the contract. @@ -115,4 +120,4 @@ MembersMustExist : Member 'public AutoMapper.Internal.TypePair AutoMapper.Intern MembersMustExist : Member 'public System.Linq.IQueryable AutoMapper.QueryableExtensions.Extensions.Map(System.Linq.IQueryable, System.Linq.IQueryable, AutoMapper.IConfigurationProvider)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Collections.Generic.IReadOnlyCollection AutoMapper.QueryableExtensions.MemberVisitor.MemberPath.get()' does not exist in the implementation but it does exist in the contract. TypesMustExist : Type 'AutoMapper.QueryableExtensions.Impl.MemberAccessQueryMapperVisitor' does not exist in the implementation but it does exist in the contract. -Total Issues: 116 +Total Issues: 121 diff --git a/src/AutoMapper/Configuration/IMappingOperationOptions.cs b/src/AutoMapper/Configuration/IMappingOperationOptions.cs index f78e85d587..8f45ef8c14 100644 --- a/src/AutoMapper/Configuration/IMappingOperationOptions.cs +++ b/src/AutoMapper/Configuration/IMappingOperationOptions.cs @@ -17,7 +17,7 @@ public interface IMappingOperationOptions /// /// Add context items to be accessed at map time inside an or /// - IDictionary Items { get; } + Dictionary Items { get; } /// /// Execute a custom function to the source and/or destination types before member mapping @@ -50,7 +50,7 @@ public class MappingOperationOptions : IMappingOperationO private StringDictionary _items; public MappingOperationOptions(Func serviceCtor) => ServiceCtor = serviceCtor; public Func ServiceCtor { get; private set; } - public IDictionary Items => _items ??= new StringDictionary(); + public Dictionary Items => _items ??= new StringDictionary(); public Action BeforeMapAction { get; protected set; } public Action AfterMapAction { get; protected set; } public void BeforeMap(Action beforeFunction) => BeforeMapAction = beforeFunction; diff --git a/src/AutoMapper/ResolutionContext.cs b/src/AutoMapper/ResolutionContext.cs index 05aa6db08a..a430a190c9 100644 --- a/src/AutoMapper/ResolutionContext.cs +++ b/src/AutoMapper/ResolutionContext.cs @@ -17,7 +17,7 @@ internal ResolutionContext(IInternalRuntimeMapper mapper, IMappingOperationOptio /// /// The items passed in the options of the Map call. /// - public IDictionary Items + public Dictionary Items { get { From daacd80c1009e3b4a72e1cd902f201fac822a0bf Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Sat, 10 Sep 2022 09:41:41 +0300 Subject: [PATCH 51/67] less allocations --- .../Configuration/MapperConfiguration.cs | 28 ++++++--- .../Execution/TypeMapPlanBuilder.cs | 16 +++-- src/AutoMapper/TypeMap.cs | 60 +++++++++++++------ 3 files changed, 74 insertions(+), 30 deletions(-) diff --git a/src/AutoMapper/Configuration/MapperConfiguration.cs b/src/AutoMapper/Configuration/MapperConfiguration.cs index 6e8aaf444c..ccb33dfb5a 100644 --- a/src/AutoMapper/Configuration/MapperConfiguration.cs +++ b/src/AutoMapper/Configuration/MapperConfiguration.cs @@ -60,6 +60,7 @@ public class MapperConfiguration : IGlobalConfiguration private readonly Dictionary _defaults; private readonly ParameterReplaceVisitor _parameterReplaceVisitor = new(); private readonly ConvertParameterReplaceVisitor _convertParameterReplaceVisitor = new(); + private readonly List _typesInheritance = new(); public MapperConfiguration(MapperConfigurationExpression configurationExpression) { var configuration = (IGlobalConfigurationExpression)configurationExpression; @@ -114,6 +115,7 @@ public MapperConfiguration(MapperConfigurationExpression configurationExpression _defaults = null; _convertParameterReplaceVisitor = null; _parameterReplaceVisitor = null; + _typesInheritance = null; _sealed = true; return; void Seal() @@ -325,12 +327,25 @@ private TypeMap GetTypeMap(TypePair initialTypes) { return typeMap; } - var allSourceTypes = GetTypeInheritance(initialTypes.SourceType); - var allDestinationTypes = GetTypeInheritance(initialTypes.DestinationType); - foreach (var destinationType in allDestinationTypes) + List typesInheritance; + if (_typesInheritance == null) { - foreach (var sourceType in allSourceTypes) + typesInheritance = new(); + } + else + { + _typesInheritance.Clear(); + typesInheritance = _typesInheritance; + } + GetTypeInheritance(typesInheritance, initialTypes.SourceType); + var sourceTypesLength = typesInheritance.Count; + GetTypeInheritance(typesInheritance, initialTypes.DestinationType); + for(int destinationIndex = sourceTypesLength; destinationIndex < typesInheritance.Count; destinationIndex++) + { + var destinationType = typesInheritance[destinationIndex]; + for(int sourceIndex = 0; sourceIndex < sourceTypesLength; sourceIndex++) { + var sourceType = typesInheritance[sourceIndex]; if (sourceType == initialTypes.SourceType && destinationType == initialTypes.DestinationType) { continue; @@ -348,11 +363,11 @@ private TypeMap GetTypeMap(TypePair initialTypes) } } return null; - static List GetTypeInheritance(Type type) + static void GetTypeInheritance(List types, Type type) { var interfaces = type.GetInterfaces(); var lastIndex = interfaces.Length - 1; - var types = new List(interfaces.Length + 2) { type }; + types.Add(type); Type baseType = type; while ((baseType = baseType.BaseType) != null) { @@ -371,7 +386,6 @@ static List GetTypeInheritance(Type type) { types.Add(interfaceType); } - return types; } TypeMap FindClosedGenericTypeMapFor(TypePair typePair) { diff --git a/src/AutoMapper/Execution/TypeMapPlanBuilder.cs b/src/AutoMapper/Execution/TypeMapPlanBuilder.cs index 1c1235fecc..443b8f2493 100644 --- a/src/AutoMapper/Execution/TypeMapPlanBuilder.cs +++ b/src/AutoMapper/Execution/TypeMapPlanBuilder.cs @@ -174,16 +174,20 @@ private Expression CreateAssignmentFunc(Expression createDestination) { actions.Add(ReplaceParameters(beforeMapAction)); } - foreach (var propertyMap in _typeMap.OrderedPropertyMaps()) + var propertyMaps = _typeMap.OrderedPropertyMaps(); + if (propertyMaps != null) { - if (propertyMap.CanResolveValue) + foreach (var propertyMap in propertyMaps) { - var property = TryPropertyMap(propertyMap); - if (_typeMap.ConstructorParameterMatches(propertyMap.DestinationName)) + if (propertyMap.CanResolveValue) { - property = _initialDestination.IfNullElse(_configuration.Default(property.Type), property); + var property = TryPropertyMap(propertyMap); + if (_typeMap.ConstructorParameterMatches(propertyMap.DestinationName)) + { + property = _initialDestination.IfNullElse(_configuration.Default(property.Type), property); + } + actions.Add(property); } - actions.Add(property); } } foreach (var pathMap in _typeMap.PathMaps) diff --git a/src/AutoMapper/TypeMap.cs b/src/AutoMapper/TypeMap.cs index f22018e546..48c27a9779 100644 --- a/src/AutoMapper/TypeMap.cs +++ b/src/AutoMapper/TypeMap.cs @@ -9,7 +9,7 @@ public class TypeMap { private static readonly MethodInfo CreateProxyMethod = typeof(ObjectFactory).GetStaticMethod(nameof(ObjectFactory.CreateInterfaceProxy)); private TypeMapDetails _details; - private Dictionary _propertyMaps; + private List _propertyMaps; private bool _sealed; public TypeMap(Type sourceType, Type destinationType, ProfileMap profile, TypeMapConfiguration typeMapConfiguration, List sourceMembers = null) { @@ -88,8 +88,8 @@ public MemberList ConfiguredMemberList public bool PreserveReferences { get => (_details?.PreserveReferences).GetValueOrDefault(); set => Details.PreserveReferences = value; } public int MaxDepth { get => (_details?.MaxDepth).GetValueOrDefault(); set => Details.MaxDepth = value; } public bool DisableConstructorValidation { get => (_details?.DisableConstructorValidation).GetValueOrDefault(); set => Details.DisableConstructorValidation = value; } - public IReadOnlyCollection PropertyMaps => (_propertyMaps?.Values).NullCheck(); - public IReadOnlyCollection PathMaps => (_details?.PathMaps?.Values).NullCheck(); + public IReadOnlyCollection PropertyMaps => _propertyMaps.NullCheck(); + public IReadOnlyCollection PathMaps => (_details?.PathMaps).NullCheck(); public IEnumerable MemberMaps { get @@ -136,7 +136,7 @@ private void AddPropertyMap(MemberInfo destProperty, Type destinationPropertyTyp private void AddPropertyMap(PropertyMap propertyMap) { _propertyMaps ??= new(); - _propertyMaps.Add(propertyMap.DestinationName, propertyMap); + _propertyMaps.Add(propertyMap); } public string[] GetUnmappedPropertyNames() { @@ -204,23 +204,20 @@ public void Seal(IGlobalConfiguration configuration) SourceTypeDetails = null; DestinationTypeDetails = null; } - public IEnumerable OrderedPropertyMaps() + public List OrderedPropertyMaps() { if (HasMappingOrder()) { - return PropertyMaps.OrderBy(map => map.MappingOrder); - } - else - { - return PropertyMaps; + _propertyMaps.Sort((left, right) => left.MappingOrder ?? int.MaxValue - right.MappingOrder ?? int.MaxValue); } + return _propertyMaps; bool HasMappingOrder() { if (_propertyMaps == null) { return false; } - foreach (var propertyMap in _propertyMaps.Values) + foreach (var propertyMap in _propertyMaps) { if (propertyMap.MappingOrder != null) { @@ -246,7 +243,21 @@ public void IncludeBaseTypes(TypePair baseTypes) public void ConstructUsingServiceLocator() => CustomCtorFunction = Lambda(ServiceLocator(DestinationType)); internal LambdaExpression CreateMapperLambda(IGlobalConfiguration configuration) => Types.ContainsGenericParameters ? null : new TypeMapPlanBuilder(configuration, this).CreateMapperLambda(); - private PropertyMap GetPropertyMap(string name) => _propertyMaps?.GetValueOrDefault(name); + private PropertyMap GetPropertyMap(string name) + { + if (_propertyMaps == null) + { + return null; + } + foreach (var propertyMap in _propertyMaps) + { + if (propertyMap.DestinationName == name) + { + return propertyMap; + } + } + return null; + } private PropertyMap GetPropertyMap(PropertyMap propertyMap) => GetPropertyMap(propertyMap.DestinationName); public void AsProxy() => CustomCtorFunction = Lambda(Call(CreateProxyMethod, Constant(DestinationType))); internal void CopyInheritedMapsTo(TypeMap typeMap) @@ -278,7 +289,7 @@ class TypeMapDetails public HashSet BeforeMapActions { get; private set; } public HashSet IncludedDerivedTypes { get; private set; } public HashSet IncludedBaseTypes { get; private set; } - public Dictionary PathMaps { get; private set; } + public List PathMaps { get; private set; } public Dictionary SourceMemberConfigs { get; private set; } public HashSet InheritedTypeMaps { get; private set; } public HashSet IncludedMembersTypeMaps { get; private set; } @@ -338,7 +349,7 @@ public void AddValueTransformation(ValueTransformerConfiguration valueTransforme public PathMap FindOrCreatePathMapFor(LambdaExpression destinationExpression, MemberPath path, TypeMap typeMap) { PathMaps ??= new(); - var pathMap = PathMaps.GetValueOrDefault(path); + var pathMap = GetPathMap(path); if (pathMap == null) { pathMap = new(destinationExpression, path, typeMap); @@ -346,7 +357,22 @@ public PathMap FindOrCreatePathMapFor(LambdaExpression destinationExpression, Me } return pathMap; } - private void AddPathMap(PathMap pathMap) => PathMaps.Add(pathMap.MemberPath, pathMap); + private PathMap GetPathMap(MemberPath memberPath) + { + if (PathMaps == null) + { + return null; + } + foreach (var pathMap in PathMaps) + { + if (pathMap.MemberPath == memberPath) + { + return pathMap; + } + } + return null; + } + private void AddPathMap(PathMap pathMap) => PathMaps.Add(pathMap); public void IncludeBaseTypes(TypePair baseTypes) { IncludedBaseTypes ??= new(); @@ -438,7 +464,7 @@ private void ApplyInheritedTypeMap(TypeMap inheritedTypeMap, TypeMap thisMap) return; void ApplyInheritedPropertyMaps(TypeMap inheritedTypeMap, TypeMap thisMap) { - foreach (var inheritedMappedProperty in inheritedTypeMap._propertyMaps.Values) + foreach (var inheritedMappedProperty in inheritedTypeMap._propertyMaps) { if (!inheritedMappedProperty.IsMapped) { @@ -484,7 +510,7 @@ private PathMap[] NotOverridenPathMaps(TypeMap inheritedTypeMap) return Array.Empty(); } PathMaps ??= new(); - return inheritedTypeMap.PathMaps.Where(baseConfig => !PathMaps.ContainsKey(baseConfig.MemberPath)).ToArray(); + return inheritedTypeMap.PathMaps.Where(baseConfig => GetPathMap(baseConfig.MemberPath) == null).ToArray(); } } } \ No newline at end of file From c60878736a96f52474c0750ebfca69a022488c2b Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Sat, 10 Sep 2022 13:06:43 +0300 Subject: [PATCH 52/67] NullMappingOrderComesFirst --- src/AutoMapper/TypeMap.cs | 2 +- src/UnitTests/MappingOrder.cs | 211 +++++++++++++++++++--------------- 2 files changed, 120 insertions(+), 93 deletions(-) diff --git a/src/AutoMapper/TypeMap.cs b/src/AutoMapper/TypeMap.cs index 48c27a9779..703af8771a 100644 --- a/src/AutoMapper/TypeMap.cs +++ b/src/AutoMapper/TypeMap.cs @@ -208,7 +208,7 @@ public List OrderedPropertyMaps() { if (HasMappingOrder()) { - _propertyMaps.Sort((left, right) => left.MappingOrder ?? int.MaxValue - right.MappingOrder ?? int.MaxValue); + _propertyMaps.Sort((left, right) => Comparer.Default.Compare(left.MappingOrder, right.MappingOrder)); } return _propertyMaps; bool HasMappingOrder() diff --git a/src/UnitTests/MappingOrder.cs b/src/UnitTests/MappingOrder.cs index 8343b38a79..197ff6b5c5 100644 --- a/src/UnitTests/MappingOrder.cs +++ b/src/UnitTests/MappingOrder.cs @@ -1,116 +1,143 @@ -namespace AutoMapper.UnitTests +using static AutoMapper.UnitTests.Bug.MapFromClosureBug; + +namespace AutoMapper.UnitTests; + +public class When_specifying_a_mapping_order_for_base_members : AutoMapperSpecBase { - namespace MappingOrder + Destination _destination; + + class Source { - public class When_specifying_a_mapping_order_for_base_members : AutoMapperSpecBase - { - Destination _destination; + public string One { get; set; } - class Source - { - public string One { get; set; } + public string Two { get; set; } + } - public string Two { get; set; } - } + class SourceChild : Source + { + } - class SourceChild : Source - { - } + class Destination + { + // must be defined before property "One" to fail + public string Two { get; set; } - class Destination - { - // must be defined before property "One" to fail - public string Two { get; set; } - - private string one; - - public string One - { - get - { - return this.one; - } - set - { - this.one = value; - this.Two = value; - } - } - } + private string one; - protected override void Because_of() + public string One + { + get { - _destination = Mapper.Map(new SourceChild { One = "first", Two = "second" }); + return this.one; } - - [Fact] - public void Should_inherit_the_mapping_order() + set { - _destination.Two.ShouldBe("first"); + this.one = value; + this.Two = value; } + } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .Include() - .ForMember(dest => dest.One, opt => opt.SetMappingOrder(600)) - .ForMember(dest => dest.Two, opt => opt.SetMappingOrder(-500)); + protected override void Because_of() + { + _destination = Mapper.Map(new SourceChild { One = "first", Two = "second" }); + } + + [Fact] + public void Should_inherit_the_mapping_order() + { + _destination.Two.ShouldBe("first"); + } + + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .Include() + .ForMember(dest => dest.One, opt => opt.SetMappingOrder(600)) + .ForMember(dest => dest.Two, opt => opt.SetMappingOrder(-500)); + + cfg.CreateMap(); + }); +} + +public class When_specifying_a_mapping_order : AutoMapperSpecBase +{ + private Destination _result; + + public class Source + { + private int _startValue; - cfg.CreateMap(); - }); + public Source(int startValue) + { + _startValue = startValue; } - public class When_specifying_a_mapping_order_for_source_members : AutoMapperSpecBase + public int GetValue1() { - private Destination _result; + _startValue += 10; + return _startValue; + } - public class Source - { - private int _startValue; - - public Source(int startValue) - { - _startValue = startValue; - } - - public int GetValue1() - { - _startValue += 10; - return _startValue; - } - - public int GetValue2() - { - _startValue += 5; - return _startValue; - } - } + public int GetValue2() + { + _startValue += 5; + return _startValue; + } + } - public class Destination - { - public int Value1 { get; set; } - public int Value2 { get; set; } - } + public class Destination + { + public int Value1 { get; set; } + public int Value2 { get; set; } + } - protected override MapperConfiguration CreateConfiguration() => new(cfg => - { - cfg.CreateMap() - .ForMember(src => src.Value1, opt => opt.SetMappingOrder(2)) - .ForMember(src => src.Value2, opt => opt.SetMappingOrder(1)); - }); + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.CreateMap() + .ForMember(d => d.Value1, opt => opt.SetMappingOrder(2)) + .ForMember(d => d.Value2, opt => opt.SetMappingOrder(1)); + }); - protected override void Because_of() - { - _result = Mapper.Map(new Source(10)); - } + protected override void Because_of() + { + _result = Mapper.Map(new Source(10)); + } - [Fact] - public void Should_perform_the_mapping_in_the_order_specified() - { - _result.Value2.ShouldBe(15); - _result.Value1.ShouldBe(25); - } + [Fact] + public void Should_perform_the_mapping_in_the_order_specified() + { + _result.Value2.ShouldBe(15); + _result.Value1.ShouldBe(25); + } +} +public class NullMappingOrderComesFirst : AutoMapperSpecBase +{ + public class Source + { + private int _startValue; + public int GetValue1() + { + _startValue += 5; + return _startValue; } - + public int GetValue2() + { + _startValue += 5; + return _startValue; + } + } + public class Destination + { + public int Value1 { get; set; } + public int Value2 { get; set; } + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.CreateMap().ForMember(d => d.Value1, opt => opt.SetMappingOrder(0))); + [Fact] + public void Should_perform_the_mapping_in_the_order_specified() + { + var _result = Mapper.Map(new Source()); + _result.Value2.ShouldBe(5); + _result.Value1.ShouldBe(10); } } \ No newline at end of file From 434703c2cd5adc3ec58a788c9eeab3b65bec79ad Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Sat, 10 Sep 2022 14:26:49 +0300 Subject: [PATCH 53/67] less allocations --- src/AutoMapper/ConstructorMap.cs | 36 ++++++++++++++++++++------------ src/AutoMapper/Features.cs | 31 ++++++++++++++++++++++----- src/AutoMapper/TypeMap.cs | 34 +++++++++++++++++++++--------- 3 files changed, 73 insertions(+), 28 deletions(-) diff --git a/src/AutoMapper/ConstructorMap.cs b/src/AutoMapper/ConstructorMap.cs index 619cfa6a5d..db3df1660e 100644 --- a/src/AutoMapper/ConstructorMap.cs +++ b/src/AutoMapper/ConstructorMap.cs @@ -3,9 +3,9 @@ public class ConstructorMap { private bool? _canResolve; - private readonly Dictionary _ctorParams = new(StringComparer.OrdinalIgnoreCase); + private readonly List _ctorParams = new(); public ConstructorInfo Ctor { get; private set; } - public IReadOnlyCollection CtorParams => _ctorParams.Values; + public IReadOnlyCollection CtorParams => _ctorParams; public void Reset(ConstructorInfo ctor) { Ctor = ctor; @@ -19,7 +19,7 @@ public bool CanResolve } private bool ParametersCanResolve() { - foreach (var param in _ctorParams.Values) + foreach (var param in _ctorParams) { if (!param.CanResolveValue) { @@ -28,14 +28,27 @@ private bool ParametersCanResolve() } return true; } - public ConstructorParameterMap this[string name] => _ctorParams.GetValueOrDefault(name); + public ConstructorParameterMap this[string name] + { + get + { + foreach (var param in _ctorParams) + { + if (param.DestinationName.Equals(name, StringComparison.OrdinalIgnoreCase)) + { + return param; + } + } + return null; + } + } public void AddParameter(ParameterInfo parameter, IEnumerable sourceMembers, TypeMap typeMap) { if (parameter.Name == null) { return; } - _ctorParams.Add(parameter.Name, new ConstructorParameterMap(typeMap, parameter, sourceMembers.ToArray())); + _ctorParams.Add(new(typeMap, parameter, sourceMembers.ToArray())); } public bool ApplyIncludedMember(IncludedMember includedMember) { @@ -45,20 +58,17 @@ public bool ApplyIncludedMember(IncludedMember includedMember) return false; } bool canResolve = false; - foreach (var includedParam in typeMap.ConstructorMap._ctorParams.Values) + var includedParams = typeMap.ConstructorMap._ctorParams; + for(int index = 0; index < includedParams.Count; index++) { - if (!includedParam.CanResolveValue) - { - continue; - } - var name = includedParam.DestinationName; - if (_ctorParams.TryGetValue(name, out var existingParam) && existingParam.CanResolveValue) + var includedParam = includedParams[index]; + if (!includedParam.CanResolveValue || _ctorParams[index].CanResolveValue) { continue; } canResolve = true; _canResolve = null; - _ctorParams[name] = new ConstructorParameterMap(includedParam, includedMember); + _ctorParams[index] = new(includedParam, includedMember); } return canResolve; } diff --git a/src/AutoMapper/Features.cs b/src/AutoMapper/Features.cs index a154ff0dd1..614409ffe1 100644 --- a/src/AutoMapper/Features.cs +++ b/src/AutoMapper/Features.cs @@ -15,7 +15,7 @@ public interface IRuntimeFeature } public class Features : IReadOnlyCollection { - private Dictionary _features; + private List _features; public int Count => _features?.Count ?? 0; /// /// Gets the feature of type . @@ -23,18 +23,39 @@ public class Features : IReadOnlyCollection /// The type of the feature. /// The feature or null if feature not exists. public TFeatureToFind Get() where TFeatureToFind : TFeature => - _features == null ? default : (TFeatureToFind)_features.GetValueOrDefault(typeof(TFeatureToFind)); + _features == null ? default : (TFeatureToFind)GetFeature(typeof(TFeatureToFind)); /// /// Add or update the feature. Existing feature of the same type will be replaced. /// /// The feature. public void Set(TFeature feature) { - _features ??= new Dictionary(); - _features[feature.GetType()] = feature; + _features ??= new(); + int index = 0; + var featureType = feature.GetType(); + for (; index < _features.Count && _features[index].GetType() != featureType; index++); + if (index < _features.Count) + { + _features[index] = feature; + } + else + { + _features.Add(feature); + } + } + object GetFeature(Type featureType) + { + foreach (var feature in _features) + { + if (feature.GetType() == featureType) + { + return feature; + } + } + return null; } public IEnumerator GetEnumerator() => - _features == null ? Enumerable.Empty().GetEnumerator() : _features.Values.GetEnumerator(); + _features == null ? Enumerable.Empty().GetEnumerator() : _features.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } public static class FeatureExtensions diff --git a/src/AutoMapper/TypeMap.cs b/src/AutoMapper/TypeMap.cs index 703af8771a..06d206425f 100644 --- a/src/AutoMapper/TypeMap.cs +++ b/src/AutoMapper/TypeMap.cs @@ -151,7 +151,7 @@ public string[] GetUnmappedPropertyNames() } else { - var ignoredSourceMembers = _details?.SourceMemberConfigs?.Values + var ignoredSourceMembers = _details?.SourceMemberConfigs? .Where(smc => smc.IsIgnored()) .Select(pm => pm.SourceMember.Name); properties = Profile.CreateTypeDetails(SourceType).ReadAccessors @@ -290,7 +290,7 @@ class TypeMapDetails public HashSet IncludedDerivedTypes { get; private set; } public HashSet IncludedBaseTypes { get; private set; } public List PathMaps { get; private set; } - public Dictionary SourceMemberConfigs { get; private set; } + public List SourceMemberConfigs { get; private set; } public HashSet InheritedTypeMaps { get; private set; } public HashSet IncludedMembersTypeMaps { get; private set; } public List ValueTransformerConfigs { get; private set; } @@ -391,14 +391,25 @@ public bool AddMemberMap(IncludedMember includedMember) public SourceMemberConfig FindOrCreateSourceMemberConfigFor(MemberInfo sourceMember) { SourceMemberConfigs ??= new(); - var config = SourceMemberConfigs.GetValueOrDefault(sourceMember); - - if (config != null) return config; - - config = new(sourceMember); - SourceMemberConfigs.Add(config.SourceMember, config); + var config = GetSourceMemberConfig(sourceMember); + if (config == null) + { + config = new(sourceMember); + SourceMemberConfigs.Add(config); + } return config; } + private SourceMemberConfig GetSourceMemberConfig(MemberInfo sourceMember) + { + foreach (var sourceConfig in SourceMemberConfigs) + { + if (sourceConfig.SourceMember == sourceMember) + { + return sourceConfig; + } + } + return null; + } public bool AddInheritedMap(TypeMap inheritedTypeMap) { InheritedTypeMaps ??= new(); @@ -484,9 +495,12 @@ void ApplyInheritedPropertyMaps(TypeMap inheritedTypeMap, TypeMap thisMap) void ApplyInheritedSourceMembers(TypeMapDetails inheritedTypeMap) { SourceMemberConfigs ??= new(); - foreach (var inheritedSourceConfig in inheritedTypeMap.SourceMemberConfigs.Values) + foreach (var inheritedSourceConfig in inheritedTypeMap.SourceMemberConfigs) { - SourceMemberConfigs.TryAdd(inheritedSourceConfig.SourceMember, inheritedSourceConfig); + if (GetSourceMemberConfig(inheritedSourceConfig.SourceMember) == null) + { + SourceMemberConfigs.Add(inheritedSourceConfig); + } } } } From 4ba0e5fe03ea70d544fb2984278e71e74d3590da Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Sat, 10 Sep 2022 15:13:50 +0300 Subject: [PATCH 54/67] we could include a different constructor --- src/AutoMapper/ConstructorMap.cs | 6 +-- .../IMappingExpression/IncludeMembers.cs | 37 +++++++++++++++++++ 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/src/AutoMapper/ConstructorMap.cs b/src/AutoMapper/ConstructorMap.cs index db3df1660e..96dd5c38bd 100644 --- a/src/AutoMapper/ConstructorMap.cs +++ b/src/AutoMapper/ConstructorMap.cs @@ -52,13 +52,13 @@ public void AddParameter(ParameterInfo parameter, IEnumerable source } public bool ApplyIncludedMember(IncludedMember includedMember) { - var typeMap = includedMember.TypeMap; - if (CanResolve || typeMap.ConstructorMap == null) + var includedMap = includedMember.TypeMap.ConstructorMap; + if (CanResolve || includedMap?.Ctor != Ctor) { return false; } bool canResolve = false; - var includedParams = typeMap.ConstructorMap._ctorParams; + var includedParams = includedMap._ctorParams; for(int index = 0; index < includedParams.Count; index++) { var includedParam = includedParams[index]; diff --git a/src/UnitTests/IMappingExpression/IncludeMembers.cs b/src/UnitTests/IMappingExpression/IncludeMembers.cs index bca6d9ef04..7ed3315301 100644 --- a/src/UnitTests/IMappingExpression/IncludeMembers.cs +++ b/src/UnitTests/IMappingExpression/IncludeMembers.cs @@ -1714,4 +1714,41 @@ public void Should_work() dest.TheField.ShouldBe(2); dest.Level1Field.ShouldBe(3); } +} +public class IncludeMembersMultipleConstructorMapping : AutoMapperSpecBase +{ + public class Source + { + public int Id; + public Level1 FieldLevel1; + } + public class Level1 + { + public Level2 FieldLevel2; + public long Level1Field; + } + public class Level2 + { + public long TheField; + } + public record Destination(int Id, long TheField, long Level1Field) + { + public Destination(Level2 fieldLevel2, long level1Field) : this(-1, fieldLevel2.TheField, level1Field) { } + public Destination(long theField) : this(-2, theField, -2) { } + } + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.ShouldUseConstructor = c => c.IsPublic; + cfg.CreateMap().IncludeMembers(s => s.FieldLevel1); + cfg.CreateMap(MemberList.None).IncludeMembers(s => s.FieldLevel2); + cfg.CreateMap(MemberList.None); + }); + [Fact] + public void Should_work() + { + var dest = Map(new Source { Id = 1, FieldLevel1 = new Level1 { Level1Field = 3, FieldLevel2 = new Level2 { TheField = 2 } } }); + dest.Id.ShouldBe(1); + dest.TheField.ShouldBe(2); + dest.Level1Field.ShouldBe(3); + } } \ No newline at end of file From b98273e1ff5e38afad37686045102e232075bb63 Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Sat, 10 Sep 2022 19:49:58 +0300 Subject: [PATCH 55/67] less allocations --- src/AutoMapper/ApiCompatBaseline.txt | 4 +- .../Configuration/ConfigurationValidator.cs | 6 +-- src/AutoMapper/Configuration/Conventions.cs | 12 ++--- src/AutoMapper/Configuration/Profile.cs | 10 ++-- .../Execution/TypeMapPlanBuilder.cs | 26 ++++++++--- src/AutoMapper/Internal/PrimitiveHelper.cs | 17 +++++++ src/AutoMapper/Internal/TypeDetails.cs | 4 +- src/AutoMapper/ProfileMap.cs | 8 ++-- .../QueryableExtensions/ProjectionBuilder.cs | 12 +++-- src/AutoMapper/TypeMap.cs | 46 +++++++++---------- 10 files changed, 88 insertions(+), 57 deletions(-) diff --git a/src/AutoMapper/ApiCompatBaseline.txt b/src/AutoMapper/ApiCompatBaseline.txt index a02376fec9..65036fe6d1 100644 --- a/src/AutoMapper/ApiCompatBaseline.txt +++ b/src/AutoMapper/ApiCompatBaseline.txt @@ -68,8 +68,6 @@ MembersMustExist : Member 'public System.Reflection.MemberInfo AutoMapper.Config InterfacesShouldHaveSameMembers : Interface member 'public System.Reflection.MemberInfo AutoMapper.Configuration.Conventions.ISourceToDestinationNameMapper.GetSourceMember(AutoMapper.Internal.TypeDetails, System.Type, System.Type, System.String)' is present in the implementation but not in the contract. InterfacesShouldHaveSameMembers : Interface member 'public void AutoMapper.Configuration.Conventions.ISourceToDestinationNameMapper.Merge(AutoMapper.Configuration.Conventions.ISourceToDestinationNameMapper)' is present in the implementation but not in the contract. TypesMustExist : Type 'AutoMapper.Configuration.Conventions.ParentSourceToDestinationNameMapper' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'public System.Collections.Generic.List AutoMapper.Configuration.Conventions.PrePostfixName.DestinationPostfixes.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'public System.Collections.Generic.List AutoMapper.Configuration.Conventions.PrePostfixName.DestinationPrefixes.get()' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Reflection.MemberInfo AutoMapper.Configuration.Conventions.PrePostfixName.GetMatchingMemberInfo(AutoMapper.Internal.TypeDetails, System.Type, System.Type, System.String)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Collections.Generic.List AutoMapper.Configuration.Conventions.PrePostfixName.Postfixes.get()' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Collections.Generic.List AutoMapper.Configuration.Conventions.PrePostfixName.Prefixes.get()' does not exist in the implementation but it does exist in the contract. @@ -120,4 +118,4 @@ MembersMustExist : Member 'public AutoMapper.Internal.TypePair AutoMapper.Intern MembersMustExist : Member 'public System.Linq.IQueryable AutoMapper.QueryableExtensions.Extensions.Map(System.Linq.IQueryable, System.Linq.IQueryable, AutoMapper.IConfigurationProvider)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Collections.Generic.IReadOnlyCollection AutoMapper.QueryableExtensions.MemberVisitor.MemberPath.get()' does not exist in the implementation but it does exist in the contract. TypesMustExist : Type 'AutoMapper.QueryableExtensions.Impl.MemberAccessQueryMapperVisitor' does not exist in the implementation but it does exist in the contract. -Total Issues: 121 +Total Issues: 119 diff --git a/src/AutoMapper/Configuration/ConfigurationValidator.cs b/src/AutoMapper/Configuration/ConfigurationValidator.cs index 613b2fb395..73139f3be5 100644 --- a/src/AutoMapper/Configuration/ConfigurationValidator.cs +++ b/src/AutoMapper/Configuration/ConfigurationValidator.cs @@ -45,7 +45,7 @@ where unmappedPropertyNames.Length > 0 || !canConstruct { throw new AutoMapperConfigurationException(badTypeMaps); } - var typeMapsChecked = new List(); + var typeMapsChecked = new HashSet(); var configExceptions = new List(); foreach (var typeMap in maps) { @@ -67,7 +67,7 @@ where unmappedPropertyNames.Length > 0 || !canConstruct throw configExceptions[0]; } } - private void DryRunTypeMap(IGlobalConfiguration config, ICollection typeMapsChecked, TypePair types, TypeMap typeMap, MemberMap memberMap) + private void DryRunTypeMap(IGlobalConfiguration config, HashSet typeMapsChecked, TypePair types, TypeMap typeMap, MemberMap memberMap) { if(typeMap == null) { @@ -107,7 +107,7 @@ private void DryRunTypeMap(IGlobalConfiguration config, ICollection typ } } } - private void CheckPropertyMaps(IGlobalConfiguration config, ICollection typeMapsChecked, TypeMap typeMap) + private void CheckPropertyMaps(IGlobalConfiguration config, HashSet typeMapsChecked, TypeMap typeMap) { foreach (var memberMap in typeMap.MemberMaps) { diff --git a/src/AutoMapper/Configuration/Conventions.cs b/src/AutoMapper/Configuration/Conventions.cs index b24bb55f0c..8e414c02b4 100644 --- a/src/AutoMapper/Configuration/Conventions.cs +++ b/src/AutoMapper/Configuration/Conventions.cs @@ -69,8 +69,8 @@ public void Merge(MemberConfiguration other) } public class PrePostfixName : ISourceToDestinationNameMapper { - public HashSet DestinationPrefixes { get; } = new(); - public HashSet DestinationPostfixes { get; } = new(); + public List DestinationPrefixes { get; } = new(); + public List DestinationPostfixes { get; } = new(); public MemberInfo GetSourceMember(TypeDetails sourceTypeDetails, Type destType, Type destMemberType, string nameToSearch) { MemberInfo member; @@ -86,13 +86,13 @@ public MemberInfo GetSourceMember(TypeDetails sourceTypeDetails, Type destType, public void Merge(ISourceToDestinationNameMapper other) { var typedOther = (PrePostfixName)other; - DestinationPrefixes.UnionWith(typedOther.DestinationPrefixes); - DestinationPostfixes.UnionWith(typedOther.DestinationPostfixes); + DestinationPrefixes.TryAdd(typedOther.DestinationPrefixes); + DestinationPostfixes.TryAdd(typedOther.DestinationPostfixes); } } public class ReplaceName : ISourceToDestinationNameMapper { - public HashSet MemberNameReplacers { get; } = new(); + public List MemberNameReplacers { get; } = new(); public MemberInfo GetSourceMember(TypeDetails sourceTypeDetails, Type destType, Type destMemberType, string nameToSearch) { var possibleSourceNames = PossibleNames(nameToSearch); @@ -116,7 +116,7 @@ public MemberInfo GetSourceMember(TypeDetails sourceTypeDetails, Type destType, public void Merge(ISourceToDestinationNameMapper other) { var typedOther = (ReplaceName)other; - MemberNameReplacers.UnionWith(typedOther.MemberNameReplacers); + MemberNameReplacers.TryAdd(typedOther.MemberNameReplacers); } private string[] PossibleNames(string nameToSearch) => MemberNameReplacers.Select(r => nameToSearch.Replace(r.OriginalValue, r.NewValue)) diff --git a/src/AutoMapper/Configuration/Profile.cs b/src/AutoMapper/Configuration/Profile.cs index adf0a32f00..499b7fb33e 100644 --- a/src/AutoMapper/Configuration/Profile.cs +++ b/src/AutoMapper/Configuration/Profile.cs @@ -165,12 +165,12 @@ public void ReplaceMemberName(string original, string newValue) _replaceName = new(); _memberConfiguration.NameToMemberMappers.Add(_replaceName); } - _replaceName.MemberNameReplacers.Add(new(original, newValue)); + _replaceName.MemberNameReplacers.TryAdd(new MemberNameReplacer(original, newValue)); } - public void RecognizePrefixes(params string[] prefixes) => _prefixes.AddRange(prefixes); - public void RecognizePostfixes(params string[] postfixes) => _postfixes.AddRange(postfixes); - public void RecognizeDestinationPrefixes(params string[] prefixes) => _prePostfixName.DestinationPrefixes.UnionWith(prefixes); - public void RecognizeDestinationPostfixes(params string[] postfixes) => _prePostfixName.DestinationPostfixes.UnionWith(postfixes); + public void RecognizePrefixes(params string[] prefixes) => _prefixes.TryAdd(prefixes); + public void RecognizePostfixes(params string[] postfixes) => _postfixes.TryAdd(postfixes); + public void RecognizeDestinationPrefixes(params string[] prefixes) => _prePostfixName.DestinationPrefixes.TryAdd(prefixes); + public void RecognizeDestinationPostfixes(params string[] postfixes) => _prePostfixName.DestinationPostfixes.TryAdd(postfixes); public void AddGlobalIgnore(string propertyNameStartingWith) { _globalIgnores ??= new(); diff --git a/src/AutoMapper/Execution/TypeMapPlanBuilder.cs b/src/AutoMapper/Execution/TypeMapPlanBuilder.cs index 443b8f2493..cb4baabc89 100644 --- a/src/AutoMapper/Execution/TypeMapPlanBuilder.cs +++ b/src/AutoMapper/Execution/TypeMapPlanBuilder.cs @@ -170,9 +170,13 @@ private Expression CreateAssignmentFunc(Expression createDestination) typeMapExpression = Constant(_typeMap); actions.Add(Call(ContextParameter, IncTypeDepthInfo, typeMapExpression)); } - foreach (var beforeMapAction in _typeMap.BeforeMapActions) + var beforeMap = _typeMap.BeforeMapActions; + if (beforeMap.Count > 0) { - actions.Add(ReplaceParameters(beforeMapAction)); + foreach (var beforeMapAction in beforeMap) + { + actions.Add(ReplaceParameters(beforeMapAction)); + } } var propertyMaps = _typeMap.OrderedPropertyMaps(); if (propertyMaps != null) @@ -190,16 +194,24 @@ private Expression CreateAssignmentFunc(Expression createDestination) } } } - foreach (var pathMap in _typeMap.PathMaps) + var pathMaps = _typeMap.PathMaps; + if (pathMaps.Count > 0) { - if (!pathMap.Ignored) + foreach (var pathMap in pathMaps) { - actions.Add(TryPathMap(pathMap)); + if (!pathMap.Ignored) + { + actions.Add(TryPathMap(pathMap)); + } } } - foreach (var afterMapAction in _typeMap.AfterMapActions) + var afterMap = _typeMap.AfterMapActions; + if (afterMap.Count > 0) { - actions.Add(ReplaceParameters(afterMapAction)); + foreach (var afterMapAction in afterMap) + { + actions.Add(ReplaceParameters(afterMapAction)); + } } if (hasMaxDepth) { diff --git a/src/AutoMapper/Internal/PrimitiveHelper.cs b/src/AutoMapper/Internal/PrimitiveHelper.cs index a524173f0b..7f1dd6b922 100644 --- a/src/AutoMapper/Internal/PrimitiveHelper.cs +++ b/src/AutoMapper/Internal/PrimitiveHelper.cs @@ -5,6 +5,23 @@ namespace AutoMapper.Internal; [EditorBrowsable(EditorBrowsableState.Never)] public static class PrimitiveHelper { + public static bool TryAdd(this List list, T value) + { + if (!list.Contains(value)) + { + list.Add(value); + return true; + } + return false; + } + public static List TryAdd(this List list, IEnumerable values) + { + foreach (var value in values) + { + list.TryAdd(value); + } + return list; + } public static ReadOnlyCollection ToReadOnly(this T item) where T : Expression => new ReadOnlyCollectionBuilder{ item }.ToReadOnlyCollection(); public static IReadOnlyCollection NullCheck(this IReadOnlyCollection source) => source ?? Array.Empty(); public static IEnumerable Concat(this IReadOnlyCollection collection, IReadOnlyCollection otherCollection) diff --git a/src/AutoMapper/Internal/TypeDetails.cs b/src/AutoMapper/Internal/TypeDetails.cs index 309f6d33a9..6eb8849a89 100644 --- a/src/AutoMapper/Internal/TypeDetails.cs +++ b/src/AutoMapper/Internal/TypeDetails.cs @@ -126,7 +126,7 @@ public MethodInfo Close() public override object[] GetCustomAttributes(Type attributeType, bool inherit) => throw new NotImplementedException(); public override bool IsDefined(Type attributeType, bool inherit) => throw new NotImplementedException(); } - public static string[] PossibleNames(string memberName, HashSet prefixes, HashSet postfixes) + public static string[] PossibleNames(string memberName, List prefixes, List postfixes) { List result = null; foreach (var prefix in prefixes) @@ -142,7 +142,7 @@ public static string[] PossibleNames(string memberName, HashSet prefixes } PostFixes(ref result, postfixes, memberName); return result == null ? Array.Empty() : result.ToArray(); - static void PostFixes(ref List result, HashSet postfixes, string name) + static void PostFixes(ref List result, List postfixes, string name) { foreach (var postfix in postfixes) { diff --git a/src/AutoMapper/ProfileMap.cs b/src/AutoMapper/ProfileMap.cs index bfe1ddb398..01cc37c5dd 100644 --- a/src/AutoMapper/ProfileMap.cs +++ b/src/AutoMapper/ProfileMap.cs @@ -33,8 +33,8 @@ public ProfileMap(IProfileConfiguration profile, IGlobalConfigurationExpression AllPropertyMapActions = profile.AllPropertyMapActions.Concat(globalProfile?.AllPropertyMapActions).ToArray(); AllTypeMapActions = profile.AllTypeMapActions.Concat(globalProfile?.AllTypeMapActions).ToArray(); profileInternal.MemberConfiguration.Seal(); - Prefixes = new(profileInternal.Prefixes.Concat(configuration?.Prefixes)); - Postfixes = new(profileInternal.Postfixes.Concat(configuration?.Postfixes)); + Prefixes.TryAdd(profileInternal.Prefixes.Concat(configuration?.Prefixes)); + Postfixes.TryAdd(profileInternal.Postfixes.Concat(configuration?.Postfixes)); TypeMapConfigs(); OpenTypeMapConfigs(); _typeDetails = new(2 * _typeMapConfigs.Length); @@ -92,8 +92,8 @@ internal void Clear() public HashSet GlobalIgnores { get; } public MemberConfiguration MemberConfiguration { get; } public IEnumerable SourceExtensionMethods { get; } - public HashSet Prefixes { get; } - public HashSet Postfixes { get; } + public List Prefixes { get; } = new(); + public List Postfixes { get; } = new(); public IReadOnlyCollection ValueTransformers { get; } public TypeDetails CreateTypeDetails(Type type) { diff --git a/src/AutoMapper/QueryableExtensions/ProjectionBuilder.cs b/src/AutoMapper/QueryableExtensions/ProjectionBuilder.cs index 6730889cf4..0a4f3a303e 100644 --- a/src/AutoMapper/QueryableExtensions/ProjectionBuilder.cs +++ b/src/AutoMapper/QueryableExtensions/ProjectionBuilder.cs @@ -282,13 +282,13 @@ internal bool IsEquivalentTo(SubQueryPath other) => LetExpression == other.LetEx class GePropertiesVisitor : ExpressionVisitor { private readonly Expression _target; - public HashSet Members { get; } = new(); + public List Members { get; } = new(); public GePropertiesVisitor(Expression target) => _target = target; protected override Expression VisitMember(MemberExpression node) { if(node.Expression == _target) { - Members.Add(node.Member); + Members.TryAdd(node.Member); } return base.VisitMember(node); } @@ -415,8 +415,12 @@ class ConstantExpressionReplacementVisitor : ParameterExpressionVisitor [DebuggerDisplay("{SourceType.Name}, {DestinationType.Name}")] public readonly record struct ProjectionRequest(Type SourceType, Type DestinationType, MemberPath[] MembersToExpand, ICollection PreviousRequests) { - public ProjectionRequest InnerRequest(Type sourceType, Type destinationType) => - new(sourceType, destinationType, MembersToExpand, new HashSet(PreviousRequests) { this }); + public ProjectionRequest InnerRequest(Type sourceType, Type destinationType) + { + var previousRequests = PreviousRequests.ToList(); + previousRequests.TryAdd(this); + return new(sourceType, destinationType, MembersToExpand, previousRequests); + } public bool AlreadyExists => PreviousRequests.Contains(this); public bool Equals(ProjectionRequest other) => SourceType == other.SourceType && DestinationType == other.DestinationType && MembersToExpand.SequenceEqual(other.MembersToExpand); diff --git a/src/AutoMapper/TypeMap.cs b/src/AutoMapper/TypeMap.cs index 06d206425f..7bca8672ec 100644 --- a/src/AutoMapper/TypeMap.cs +++ b/src/AutoMapper/TypeMap.cs @@ -167,11 +167,11 @@ public string[] GetUnmappedPropertyNames() public PropertyMap FindOrCreatePropertyMapFor(MemberInfo destinationProperty, Type destinationPropertyType) { var propertyMap = GetPropertyMap(destinationProperty.Name); - if (propertyMap != null) return propertyMap; - - propertyMap = new(destinationProperty, destinationPropertyType, this); - - AddPropertyMap(propertyMap); + if (propertyMap == null) + { + propertyMap = new(destinationProperty, destinationPropertyType, this); + AddPropertyMap(propertyMap); + } return propertyMap; } private void CheckDifferent(TypePair types) @@ -272,7 +272,7 @@ internal void CopyInheritedMapsTo(TypeMap typeMap) public bool AddMemberMap(IncludedMember includedMember) => Details.AddMemberMap(includedMember); public PathMap FindOrCreatePathMapFor(LambdaExpression destinationExpression, MemberPath path, TypeMap typeMap) => Details.FindOrCreatePathMapFor(destinationExpression, path, typeMap); - public bool AddInheritedMap(TypeMap inheritedTypeMap) => Details.AddInheritedMap(inheritedTypeMap); + public void AddInheritedMap(TypeMap inheritedTypeMap) => Details.AddInheritedMap(inheritedTypeMap); public SourceMemberConfig FindOrCreateSourceMemberConfigFor(MemberInfo sourceMember) => Details.FindOrCreateSourceMemberConfigFor(sourceMember); class TypeMapDetails { @@ -285,14 +285,14 @@ class TypeMapDetails public bool IncludeAllDerivedTypes; public LambdaExpression CustomCtorFunction; public MemberList ConfiguredMemberList; - public HashSet AfterMapActions { get; private set; } - public HashSet BeforeMapActions { get; private set; } - public HashSet IncludedDerivedTypes { get; private set; } - public HashSet IncludedBaseTypes { get; private set; } + public List AfterMapActions { get; private set; } + public List BeforeMapActions { get; private set; } + public List IncludedDerivedTypes { get; private set; } + public List IncludedBaseTypes { get; private set; } + public List InheritedTypeMaps { get; private set; } + public List IncludedMembersTypeMaps { get; private set; } public List PathMaps { get; private set; } public List SourceMemberConfigs { get; private set; } - public HashSet InheritedTypeMaps { get; private set; } - public HashSet IncludedMembersTypeMaps { get; private set; } public List ValueTransformerConfigs { get; private set; } public Features Features => _features ??= new(); public void Seal(IGlobalConfiguration configuration, TypeMap thisMap) @@ -305,7 +305,7 @@ public void Seal(IGlobalConfiguration configuration, TypeMap thisMap) if (includedMaps != null) { IncludedMembersTypeMaps ??= new(); - IncludedMembersTypeMaps.UnionWith(includedMaps); + IncludedMembersTypeMaps.TryAdd(includedMaps); } } } @@ -329,17 +329,17 @@ public void Seal(IGlobalConfiguration configuration, TypeMap thisMap) public void IncludeDerivedTypes(TypePair derivedTypes) { IncludedDerivedTypes ??= new(); - IncludedDerivedTypes.Add(derivedTypes); + IncludedDerivedTypes.TryAdd(derivedTypes); } public void AddBeforeMapAction(LambdaExpression beforeMap) { BeforeMapActions ??= new(); - BeforeMapActions.Add(beforeMap); + BeforeMapActions.TryAdd(beforeMap); } public void AddAfterMapAction(LambdaExpression afterMap) { AfterMapActions ??= new(); - AfterMapActions.Add(afterMap); + AfterMapActions.TryAdd(afterMap); } public void AddValueTransformation(ValueTransformerConfiguration valueTransformerConfiguration) { @@ -376,17 +376,17 @@ private PathMap GetPathMap(MemberPath memberPath) public void IncludeBaseTypes(TypePair baseTypes) { IncludedBaseTypes ??= new(); - IncludedBaseTypes.Add(baseTypes); + IncludedBaseTypes.TryAdd(baseTypes); } internal void CopyInheritedMapsTo(TypeMap typeMap) { typeMap.Details.InheritedTypeMaps ??= new(); - typeMap._details.InheritedTypeMaps.UnionWith(InheritedTypeMaps); + typeMap._details.InheritedTypeMaps.TryAdd(InheritedTypeMaps); } public bool AddMemberMap(IncludedMember includedMember) { IncludedMembersTypeMaps ??= new(); - return IncludedMembersTypeMaps.Add(includedMember); + return IncludedMembersTypeMaps.TryAdd(includedMember); } public SourceMemberConfig FindOrCreateSourceMemberConfigFor(MemberInfo sourceMember) { @@ -410,10 +410,10 @@ private SourceMemberConfig GetSourceMemberConfig(MemberInfo sourceMember) } return null; } - public bool AddInheritedMap(TypeMap inheritedTypeMap) + public void AddInheritedMap(TypeMap inheritedTypeMap) { InheritedTypeMaps ??= new(); - return InheritedTypeMaps.Add(inheritedTypeMap); + InheritedTypeMaps.TryAdd(inheritedTypeMap); } private void ApplyIncludedMemberTypeMap(IncludedMember includedMember, TypeMap thisMap) { @@ -509,12 +509,12 @@ void ApplyInheritedMapActions(IEnumerable beforeMap, IEnumerab if (beforeMap != null) { BeforeMapActions ??= new(); - BeforeMapActions.UnionWith(beforeMap); + BeforeMapActions.TryAdd(beforeMap); } if (afterMap != null) { AfterMapActions ??= new(); - AfterMapActions.UnionWith(afterMap); + AfterMapActions.TryAdd(afterMap); } } private PathMap[] NotOverridenPathMaps(TypeMap inheritedTypeMap) From 7eeaf59707e546c5a06df3f62ad6383bb98b3381 Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Sun, 11 Sep 2022 11:21:30 +0300 Subject: [PATCH 56/67] cosmetic --- src/AutoMapper/ApiCompatBaseline.txt | 3 +- src/AutoMapper/Features.cs | 34 ++++++++----------- ...MappingExpressionFeatureWithReverseTest.cs | 16 ++++----- ...pingExpressionFeatureWithoutReverseTest.cs | 25 +++++++------- 4 files changed, 36 insertions(+), 42 deletions(-) diff --git a/src/AutoMapper/ApiCompatBaseline.txt b/src/AutoMapper/ApiCompatBaseline.txt index 65036fe6d1..a2cab135ec 100644 --- a/src/AutoMapper/ApiCompatBaseline.txt +++ b/src/AutoMapper/ApiCompatBaseline.txt @@ -92,6 +92,7 @@ CannotSealType : Type 'AutoMapper.Execution.TypeMapPlanBuilder' is actually (has TypeCannotChangeClassification : Type 'AutoMapper.Execution.TypeMapPlanBuilder' is a 'struct' in the implementation but is a 'class' in the contract. MembersMustExist : Member 'public System.Linq.Expressions.LambdaExpression AutoMapper.Execution.TypeMapPlanBuilder.CreateMapperLambda(System.Collections.Generic.HashSet)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Linq.Expressions.ParameterExpression AutoMapper.Execution.TypeMapPlanBuilder.Source.get()' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public System.Collections.Generic.IEnumerator AutoMapper.Features.Features.GetEnumerator()' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Reflection.ConstructorInfo System.Reflection.ConstructorInfo AutoMapper.Internal.ConstructorParameters.Constructor' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Reflection.ParameterInfo[] System.Reflection.ParameterInfo[] AutoMapper.Internal.ConstructorParameters.Parameters' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public AutoMapper.Internal.TypePair AutoMapper.Internal.TypePair AutoMapper.Internal.MapRequest.RequestedTypes' does not exist in the implementation but it does exist in the contract. @@ -118,4 +119,4 @@ MembersMustExist : Member 'public AutoMapper.Internal.TypePair AutoMapper.Intern MembersMustExist : Member 'public System.Linq.IQueryable AutoMapper.QueryableExtensions.Extensions.Map(System.Linq.IQueryable, System.Linq.IQueryable, AutoMapper.IConfigurationProvider)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Collections.Generic.IReadOnlyCollection AutoMapper.QueryableExtensions.MemberVisitor.MemberPath.get()' does not exist in the implementation but it does exist in the contract. TypesMustExist : Type 'AutoMapper.QueryableExtensions.Impl.MemberAccessQueryMapperVisitor' does not exist in the implementation but it does exist in the contract. -Total Issues: 119 +Total Issues: 120 diff --git a/src/AutoMapper/Features.cs b/src/AutoMapper/Features.cs index 614409ffe1..d01315dd96 100644 --- a/src/AutoMapper/Features.cs +++ b/src/AutoMapper/Features.cs @@ -13,7 +13,7 @@ public interface IRuntimeFeature { void Seal(IGlobalConfiguration configuration); } -public class Features : IReadOnlyCollection +public class Features { private List _features; public int Count => _features?.Count ?? 0; @@ -22,41 +22,35 @@ public class Features : IReadOnlyCollection /// /// The type of the feature. /// The feature or null if feature not exists. - public TFeatureToFind Get() where TFeatureToFind : TFeature => - _features == null ? default : (TFeatureToFind)GetFeature(typeof(TFeatureToFind)); + public TFeatureToFind Get() where TFeatureToFind : TFeature + { + var index = IndexOf(typeof(TFeatureToFind)); + return index < Count ? (TFeatureToFind)_features[index] : default; + } /// /// Add or update the feature. Existing feature of the same type will be replaced. /// /// The feature. public void Set(TFeature feature) { - _features ??= new(); - int index = 0; - var featureType = feature.GetType(); - for (; index < _features.Count && _features[index].GetType() != featureType; index++); - if (index < _features.Count) + var index = IndexOf(feature.GetType()); + if (index < Count) { _features[index] = feature; } else { + _features ??= new(); _features.Add(feature); } } - object GetFeature(Type featureType) + private int IndexOf(Type featureType) { - foreach (var feature in _features) - { - if (feature.GetType() == featureType) - { - return feature; - } - } - return null; + int index = 0; + for (; index < Count && _features[index].GetType() != featureType; index++); + return index; } - public IEnumerator GetEnumerator() => - _features == null ? Enumerable.Empty().GetEnumerator() : _features.GetEnumerator(); - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + public List.Enumerator GetEnumerator() => _features.GetEnumerator(); } public static class FeatureExtensions { diff --git a/src/UnitTests/MappingExpressionFeatureWithReverseTest.cs b/src/UnitTests/MappingExpressionFeatureWithReverseTest.cs index bc1ea72810..3d208a5128 100644 --- a/src/UnitTests/MappingExpressionFeatureWithReverseTest.cs +++ b/src/UnitTests/MappingExpressionFeatureWithReverseTest.cs @@ -23,10 +23,10 @@ public void Adding_same_feature_multiple_times_should_replace_eachother() var typeMap = config.FindTypeMapFor(); - typeMap.Features.Count().ShouldBe(2); + typeMap.Features.Count.ShouldBe(2); var typeMapReverse = config.FindTypeMapFor(); - typeMapReverse.Features.Count().ShouldBe(2); + typeMapReverse.Features.Count.ShouldBe(2); Validate(featureA); Validate(featureB); @@ -50,10 +50,10 @@ public void Add_single_feature_with_reverse() }); var typeMap = config.FindTypeMapFor(); - typeMap.Features.Count().ShouldBe(1); + typeMap.Features.Count.ShouldBe(1); var typeMapReverse = config.FindTypeMapFor(); - typeMapReverse.Features.Count().ShouldBe(1); + typeMapReverse.Features.Count.ShouldBe(1); Validate(featureA); @@ -89,10 +89,10 @@ public void Add_multiple_features_with_reverse() }); var typeMap = config.FindTypeMapFor(); - typeMap.Features.Count().ShouldBe(2); + typeMap.Features.Count.ShouldBe(2); var typeMapReverse = config.FindTypeMapFor(); - typeMapReverse.Features.Count().ShouldBe(2); + typeMapReverse.Features.Count.ShouldBe(2); Validate(featureA); Validate(featureB); @@ -131,10 +131,10 @@ public void Add_multiple_features_with_reverse_overriden() }); var typeMap = config.FindTypeMapFor(); - typeMap.Features.Count().ShouldBe(2); + typeMap.Features.Count.ShouldBe(2); var typeMapReverse = config.FindTypeMapFor(); - typeMapReverse.Features.Count().ShouldBe(2); + typeMapReverse.Features.Count.ShouldBe(2); Validate(featureA, typeMap); Validate(featureB, typeMap); diff --git a/src/UnitTests/MappingExpressionFeatureWithoutReverseTest.cs b/src/UnitTests/MappingExpressionFeatureWithoutReverseTest.cs index 1d7e3dde39..6815891a5b 100644 --- a/src/UnitTests/MappingExpressionFeatureWithoutReverseTest.cs +++ b/src/UnitTests/MappingExpressionFeatureWithoutReverseTest.cs @@ -23,10 +23,10 @@ public void Adding_same_feature_should_replace_eachother() var typeMap = config.FindTypeMapFor(); - typeMap.Features.Count().ShouldBe(2); + typeMap.Features.Count.ShouldBe(2); var typeMapReverse = config.ResolveTypeMap(typeof(Dest), typeof(Source)); - typeMapReverse.Features.Count().ShouldBe(0); + typeMapReverse.Features.Count.ShouldBe(0); Validate(featureA); Validate(featureB); @@ -50,10 +50,10 @@ public void Add_single_feature() }); var typeMap = config.FindTypeMapFor(); - typeMap.Features.Count().ShouldBe(1); + typeMap.Features.Count.ShouldBe(1); var typeMapReverse = config.ResolveTypeMap(typeof(Dest), typeof(Source)); - typeMapReverse.Features.Count().ShouldBe(0); + typeMapReverse.Features.Count.ShouldBe(0); Validate(featureA); @@ -82,10 +82,10 @@ public void Add_single_feature_with_reverse() }); var typeMap = config.FindTypeMapFor(); - typeMap.Features.Count().ShouldBe(1); + typeMap.Features.Count.ShouldBe(1); var typeMapReverse = config.FindTypeMapFor(); - typeMapReverse.Features.Count().ShouldBe(0); + typeMapReverse.Features.Count.ShouldBe(0); Validate(featureA); @@ -117,10 +117,10 @@ public void Add_multiple_features() var typeMap = config.FindTypeMapFor(); - typeMap.Features.Count().ShouldBe(2); + typeMap.Features.Count.ShouldBe(2); var typeMapReverse = config.ResolveTypeMap(typeof(Dest), typeof(Source)); - typeMapReverse.Features.Count().ShouldBe(0); + typeMapReverse.Features.Count.ShouldBe(0); Validate(featureA); Validate(featureB); @@ -152,10 +152,10 @@ public void Add_multiple_features_with_reverse() }); var typeMap = config.FindTypeMapFor(); - typeMap.Features.Count().ShouldBe(2); + typeMap.Features.Count.ShouldBe(2); var typeMapReverse = config.FindTypeMapFor(); - typeMapReverse.Features.Count().ShouldBe(0); + typeMapReverse.Features.Count.ShouldBe(0); Validate(featureA); Validate(featureB); @@ -189,10 +189,10 @@ public void Add_multiple_features_with_reverse_overriden() }); var typeMap = config.FindTypeMapFor(); - typeMap.Features.Count().ShouldBe(2); + typeMap.Features.Count.ShouldBe(2); var typeMapReverse = config.FindTypeMapFor(); - typeMapReverse.Features.Count().ShouldBe(1); + typeMapReverse.Features.Count.ShouldBe(1); Validate(featureA, typeMap); Validate(featureB, typeMap); @@ -210,7 +210,6 @@ void Validate(MappingExpressionFeatureBase feature, TypeMap map, int r typeMapFeature.SealedCount.ShouldBe(1); } } - public class MappingExpressionFeatureA : MappingExpressionFeatureBase { public MappingExpressionFeatureA(int value) : base(value, new TypeMapFeatureA(value)) From efd1df999649eb33b6a7f3ae03cd601c38cdcf7e Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Mon, 12 Sep 2022 06:42:03 +0300 Subject: [PATCH 57/67] allocate _runtimeTypeDetails lazily --- src/AutoMapper/ApiCompatBaseline.txt | 3 ++- .../Internal/LockingConcurrentDictionary.cs | 19 +++++------------ src/AutoMapper/ProfileMap.cs | 21 ++++++++++++------- 3 files changed, 21 insertions(+), 22 deletions(-) diff --git a/src/AutoMapper/ApiCompatBaseline.txt b/src/AutoMapper/ApiCompatBaseline.txt index a2cab135ec..9b5b233ea6 100644 --- a/src/AutoMapper/ApiCompatBaseline.txt +++ b/src/AutoMapper/ApiCompatBaseline.txt @@ -93,6 +93,7 @@ TypeCannotChangeClassification : Type 'AutoMapper.Execution.TypeMapPlanBuilder' MembersMustExist : Member 'public System.Linq.Expressions.LambdaExpression AutoMapper.Execution.TypeMapPlanBuilder.CreateMapperLambda(System.Collections.Generic.HashSet)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Linq.Expressions.ParameterExpression AutoMapper.Execution.TypeMapPlanBuilder.Source.get()' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Collections.Generic.IEnumerator AutoMapper.Features.Features.GetEnumerator()' does not exist in the implementation but it does exist in the contract. +TypesMustExist : Type 'AutoMapper.Internal.ConcurrentDictionaryWrapper' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Reflection.ConstructorInfo System.Reflection.ConstructorInfo AutoMapper.Internal.ConstructorParameters.Constructor' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Reflection.ParameterInfo[] System.Reflection.ParameterInfo[] AutoMapper.Internal.ConstructorParameters.Parameters' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public AutoMapper.Internal.TypePair AutoMapper.Internal.TypePair AutoMapper.Internal.MapRequest.RequestedTypes' does not exist in the implementation but it does exist in the contract. @@ -119,4 +120,4 @@ MembersMustExist : Member 'public AutoMapper.Internal.TypePair AutoMapper.Intern MembersMustExist : Member 'public System.Linq.IQueryable AutoMapper.QueryableExtensions.Extensions.Map(System.Linq.IQueryable, System.Linq.IQueryable, AutoMapper.IConfigurationProvider)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Collections.Generic.IReadOnlyCollection AutoMapper.QueryableExtensions.MemberVisitor.MemberPath.get()' does not exist in the implementation but it does exist in the contract. TypesMustExist : Type 'AutoMapper.QueryableExtensions.Impl.MemberAccessQueryMapperVisitor' does not exist in the implementation but it does exist in the contract. -Total Issues: 120 +Total Issues: 121 diff --git a/src/AutoMapper/Internal/LockingConcurrentDictionary.cs b/src/AutoMapper/Internal/LockingConcurrentDictionary.cs index e38b5a0f0c..5857d9b8d5 100644 --- a/src/AutoMapper/Internal/LockingConcurrentDictionary.cs +++ b/src/AutoMapper/Internal/LockingConcurrentDictionary.cs @@ -1,22 +1,13 @@ using System.Collections.Concurrent; - namespace AutoMapper.Internal; - public readonly struct LockingConcurrentDictionary { - private readonly ConcurrentDictionaryWrapper> _dictionary; - public LockingConcurrentDictionary(Func valueFactory, int capacity = 31) => - _dictionary = new(key => new(() => valueFactory(key)), capacity); - public TValue GetOrAdd(in TKey key) => _dictionary.GetOrAdd(key).Value; -} -public readonly struct ConcurrentDictionaryWrapper -{ - private readonly ConcurrentDictionary _dictionary; - private readonly Func _valueFactory; - public ConcurrentDictionaryWrapper(Func valueFactory, int capacity = 31) + private readonly Func> _valueFactory; + private readonly ConcurrentDictionary> _dictionary; + public LockingConcurrentDictionary(Func valueFactory, int capacity = 31) { + _valueFactory = key => new(()=>valueFactory(key)); _dictionary = new(Environment.ProcessorCount, capacity); - _valueFactory = valueFactory; } - public TValue GetOrAdd(in TKey key) => _dictionary.GetOrAdd(key, _valueFactory); + public TValue GetOrAdd(in TKey key) => _dictionary.GetOrAdd(key, _valueFactory).Value; } \ No newline at end of file diff --git a/src/AutoMapper/ProfileMap.cs b/src/AutoMapper/ProfileMap.cs index 01cc37c5dd..ed5b68c9a4 100644 --- a/src/AutoMapper/ProfileMap.cs +++ b/src/AutoMapper/ProfileMap.cs @@ -1,4 +1,5 @@ using AutoMapper.Configuration.Conventions; +using System.Collections.Concurrent; namespace AutoMapper; [DebuggerDisplay("{Name}")] [EditorBrowsable(EditorBrowsableState.Never)] @@ -8,7 +9,7 @@ public class ProfileMap private TypeMapConfiguration[] _typeMapConfigs; private Dictionary _openTypeMapConfigs; private Dictionary _typeDetails; - private ConcurrentDictionaryWrapper _runtimeTypeDetails; + private ConcurrentDictionary _runtimeTypeDetails; public ProfileMap(IProfileConfiguration profile, IGlobalConfigurationExpression configuration = null) { var globalProfile = (IProfileConfiguration)configuration; @@ -74,7 +75,6 @@ internal void Clear() { _typeDetails = null; _typeMapConfigs = null; - _runtimeTypeDetails = new(TypeDetailsFactory, 2 * _openTypeMapConfigs.Count); } public bool AllowNullCollections { get; } public bool AllowNullDestinationValues { get; } @@ -98,18 +98,25 @@ internal void Clear() public TypeDetails CreateTypeDetails(Type type) { if (_typeDetails == null) - { - return _runtimeTypeDetails.GetOrAdd(type); + { + return CreateRuntimeTypeDetails(type); } if (_typeDetails.TryGetValue(type, out var typeDetails)) { return typeDetails; } - typeDetails = TypeDetailsFactory(type); + typeDetails = new(type, this); _typeDetails.Add(type, typeDetails); - return typeDetails; + return typeDetails; + TypeDetails CreateRuntimeTypeDetails(Type type) + { + if (_runtimeTypeDetails == null) + { + Interlocked.CompareExchange(ref _runtimeTypeDetails, new(Environment.ProcessorCount, 2 * _openTypeMapConfigs.Count), null); + } + return _runtimeTypeDetails.GetOrAdd(type, (type, profile) => new(type, profile), this); + } } - private TypeDetails TypeDetailsFactory(Type type) => new(type, this); public void Register(IGlobalConfiguration configuration) { foreach (var config in _typeMapConfigs) From 3a491a36c00667b1501f5bc62875682ff2d64b52 Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Mon, 12 Sep 2022 08:57:15 +0300 Subject: [PATCH 58/67] create the projection builder lazily --- src/AutoMapper/ApiCompatBaseline.txt | 3 ++- .../Configuration/MapperConfiguration.cs | 18 +++++++++++++----- .../MapperConfigurationExpression.cs | 3 ++- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/AutoMapper/ApiCompatBaseline.txt b/src/AutoMapper/ApiCompatBaseline.txt index 9b5b233ea6..5bccb5f901 100644 --- a/src/AutoMapper/ApiCompatBaseline.txt +++ b/src/AutoMapper/ApiCompatBaseline.txt @@ -31,6 +31,7 @@ MembersMustExist : Member 'public System.Collections.Generic.IReadOnlyCollection CannotSealType : Type 'AutoMapper.LowerUnderscoreNamingConvention' is actually (has the sealed modifier) sealed in the implementation but not sealed in the contract. MembersMustExist : Member 'public System.String AutoMapper.LowerUnderscoreNamingConvention.ReplaceValue(System.Text.RegularExpressions.Match)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Text.RegularExpressions.Regex AutoMapper.LowerUnderscoreNamingConvention.SplittingExpression.get()' does not exist in the implementation but it does exist in the contract. +CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.CompilerGeneratedAttribute' exists on 'AutoMapper.MapperConfigurationExpression.AutoMapper.Internal.IGlobalConfigurationExpression.get_ProjectionMappers()' in the contract but not the implementation. MembersMustExist : Member 'public System.Collections.Generic.IDictionary AutoMapper.MappingOperationOptions.Items.get()' does not exist in the implementation but it does exist in the contract. CannotSealType : Type 'AutoMapper.PascalCaseNamingConvention' is actually (has the sealed modifier) sealed in the implementation but not sealed in the contract. MembersMustExist : Member 'public System.String AutoMapper.PascalCaseNamingConvention.ReplaceValue(System.Text.RegularExpressions.Match)' does not exist in the implementation but it does exist in the contract. @@ -120,4 +121,4 @@ MembersMustExist : Member 'public AutoMapper.Internal.TypePair AutoMapper.Intern MembersMustExist : Member 'public System.Linq.IQueryable AutoMapper.QueryableExtensions.Extensions.Map(System.Linq.IQueryable, System.Linq.IQueryable, AutoMapper.IConfigurationProvider)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Collections.Generic.IReadOnlyCollection AutoMapper.QueryableExtensions.MemberVisitor.MemberPath.get()' does not exist in the implementation but it does exist in the contract. TypesMustExist : Type 'AutoMapper.QueryableExtensions.Impl.MemberAccessQueryMapperVisitor' does not exist in the implementation but it does exist in the contract. -Total Issues: 121 +Total Issues: 122 diff --git a/src/AutoMapper/Configuration/MapperConfiguration.cs b/src/AutoMapper/Configuration/MapperConfiguration.cs index ccb33dfb5a..dff03edc10 100644 --- a/src/AutoMapper/Configuration/MapperConfiguration.cs +++ b/src/AutoMapper/Configuration/MapperConfiguration.cs @@ -41,7 +41,7 @@ public class MapperConfiguration : IGlobalConfiguration private readonly Dictionary _configuredMaps; private readonly Dictionary _resolvedMaps; private readonly LockingConcurrentDictionary _runtimeMaps; - private readonly ProjectionBuilder _projectionBuilder; + private ProjectionBuilder _projectionBuilder; private readonly LockingConcurrentDictionary _executionPlans; private readonly ConfigurationValidator _validator; private readonly Features _features = new(); @@ -71,13 +71,10 @@ public MapperConfiguration(MapperConfigurationExpression configurationExpression _mappers = configuration.Mappers.ToArray(); _executionPlans = new(CompileExecutionPlan); _validator = new(configuration); - _projectionBuilder = new(this, configuration.ProjectionMappers.ToArray()); - _serviceCtor = configuration.ServiceCtor; _enableNullPropagationForQueryMapping = configuration.EnableNullPropagationForQueryMapping ?? false; _maxExecutionPlanDepth = configuration.MaxExecutionPlanDepth + 1; _recursiveQueriesMaxDepth = configuration.RecursiveQueriesMaxDepth; - Configuration = new((IProfileConfiguration)configuration); int typeMapsCount = Configuration.TypeMapsCount; int openTypeMapsCount = Configuration.OpenTypeMapsCount; @@ -235,7 +232,18 @@ LambdaExpression GenerateObjectMapperExpression(in MapRequest mapRequest, IObjec return Lambda(fullExpression, source, destination, ContextParameter); } } - IProjectionBuilder IGlobalConfiguration.ProjectionBuilder => _projectionBuilder; + IProjectionBuilder IGlobalConfiguration.ProjectionBuilder + { + get + { + if (_projectionBuilder == null) + { + CreateProjectionBuilder(); + } + return _projectionBuilder; + void CreateProjectionBuilder() => Interlocked.CompareExchange(ref _projectionBuilder, new(this, _validator.Expression.ProjectionMappers.ToArray()), null); + } + } Func IGlobalConfiguration.ServiceCtor => _serviceCtor; bool IGlobalConfiguration.EnableNullPropagationForQueryMapping => _enableNullPropagationForQueryMapping; int IGlobalConfiguration.MaxExecutionPlanDepth => _maxExecutionPlanDepth; diff --git a/src/AutoMapper/Configuration/MapperConfigurationExpression.cs b/src/AutoMapper/Configuration/MapperConfigurationExpression.cs index 010053059b..a0cf6ef3e0 100644 --- a/src/AutoMapper/Configuration/MapperConfigurationExpression.cs +++ b/src/AutoMapper/Configuration/MapperConfigurationExpression.cs @@ -91,6 +91,7 @@ public class MapperConfigurationExpression : Profile, IGlobalConfigurationExpres private readonly List _validators = new(); private readonly List _mappers; private Func _serviceCtor = Activator.CreateInstance; + private List _projectionMappers; public MapperConfigurationExpression() : base() => _mappers = MapperRegistry.Mappers(); @@ -115,7 +116,7 @@ void IGlobalConfigurationExpression.Validator(Validator validator) => List IGlobalConfigurationExpression.Validators => _validators; - List IGlobalConfigurationExpression.ProjectionMappers { get; } = ProjectionBuilder.DefaultProjectionMappers(); + List IGlobalConfigurationExpression.ProjectionMappers => _projectionMappers ??= ProjectionBuilder.DefaultProjectionMappers(); /// /// How many levels deep should recursive queries be expanded. From 7da36f6435e9de3eb498de48c7422e91c04314d2 Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Mon, 12 Sep 2022 21:22:54 +0300 Subject: [PATCH 59/67] cosmetic --- src/AutoMapper/ApiCompatBaseline.txt | 3 ++- src/AutoMapper/Configuration/Conventions.cs | 1 - .../Configuration/MapperConfiguration.cs | 26 +++++++++--------- .../Configuration/MappingExpression.cs | 27 ------------------- .../MemberConfigurationExpression.cs | 27 +++++++++++++++++++ src/AutoMapper/Features.cs | 3 +-- src/AutoMapper/ProfileMap.cs | 15 +++-------- src/UnitTests/Projection/ProjectTest.cs | 6 +++++ 8 files changed, 52 insertions(+), 56 deletions(-) diff --git a/src/AutoMapper/ApiCompatBaseline.txt b/src/AutoMapper/ApiCompatBaseline.txt index 5bccb5f901..b705fb766c 100644 --- a/src/AutoMapper/ApiCompatBaseline.txt +++ b/src/AutoMapper/ApiCompatBaseline.txt @@ -48,6 +48,7 @@ MembersMustExist : Member 'public System.Type System.Type AutoMapper.ValueTransf InterfacesShouldHaveSameMembers : Default interface member 'public System.Boolean AutoMapper.Configuration.IPropertyMapConfiguration.Ignored' is present in the implementation but not in the contract. InterfacesShouldHaveSameMembers : Default interface member 'public System.Boolean AutoMapper.Configuration.IPropertyMapConfiguration.Ignored.get()' is present in the implementation but not in the contract. CannotRemoveBaseTypeOrInterface : Type 'AutoMapper.Configuration.MappingExpression' does not inherit from base type 'AutoMapper.Configuration.MappingExpressionBase' in the implementation but it does in the contract. +TypesMustExist : Type 'AutoMapper.Configuration.MappingExpression.MemberConfigurationExpression' does not exist in the implementation but it does exist in the contract. CannotRemoveBaseTypeOrInterface : Type 'AutoMapper.Configuration.MappingExpression' does not inherit from base type 'AutoMapper.Configuration.MappingExpressionBase' in the implementation but it does in the contract. TypesMustExist : Type 'AutoMapper.Configuration.MappingExpressionBase' does not exist in the implementation but it does exist in the contract. CannotRemoveBaseTypeOrInterface : Type 'AutoMapper.Configuration.MappingExpressionBase' does not inherit from base type 'AutoMapper.Configuration.MappingExpressionBase' in the implementation but it does in the contract. @@ -121,4 +122,4 @@ MembersMustExist : Member 'public AutoMapper.Internal.TypePair AutoMapper.Intern MembersMustExist : Member 'public System.Linq.IQueryable AutoMapper.QueryableExtensions.Extensions.Map(System.Linq.IQueryable, System.Linq.IQueryable, AutoMapper.IConfigurationProvider)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Collections.Generic.IReadOnlyCollection AutoMapper.QueryableExtensions.MemberVisitor.MemberPath.get()' does not exist in the implementation but it does exist in the contract. TypesMustExist : Type 'AutoMapper.QueryableExtensions.Impl.MemberAccessQueryMapperVisitor' does not exist in the implementation but it does exist in the contract. -Total Issues: 122 +Total Issues: 123 diff --git a/src/AutoMapper/Configuration/Conventions.cs b/src/AutoMapper/Configuration/Conventions.cs index 8e414c02b4..72c7734a15 100644 --- a/src/AutoMapper/Configuration/Conventions.cs +++ b/src/AutoMapper/Configuration/Conventions.cs @@ -1,5 +1,4 @@ namespace AutoMapper.Configuration.Conventions; - public interface ISourceToDestinationNameMapper { MemberInfo GetSourceMember(TypeDetails sourceTypeDetails, Type destType, Type destMemberType, string nameToSearch); diff --git a/src/AutoMapper/Configuration/MapperConfiguration.cs b/src/AutoMapper/Configuration/MapperConfiguration.cs index dff03edc10..6f5de059e0 100644 --- a/src/AutoMapper/Configuration/MapperConfiguration.cs +++ b/src/AutoMapper/Configuration/MapperConfiguration.cs @@ -41,7 +41,7 @@ public class MapperConfiguration : IGlobalConfiguration private readonly Dictionary _configuredMaps; private readonly Dictionary _resolvedMaps; private readonly LockingConcurrentDictionary _runtimeMaps; - private ProjectionBuilder _projectionBuilder; + private LazyValue _projectionBuilder; private readonly LockingConcurrentDictionary _executionPlans; private readonly ConfigurationValidator _validator; private readonly Features _features = new(); @@ -74,6 +74,7 @@ public MapperConfiguration(MapperConfigurationExpression configurationExpression _serviceCtor = configuration.ServiceCtor; _enableNullPropagationForQueryMapping = configuration.EnableNullPropagationForQueryMapping ?? false; _maxExecutionPlanDepth = configuration.MaxExecutionPlanDepth + 1; + _projectionBuilder = new(CreateProjectionBuilder); _recursiveQueriesMaxDepth = configuration.RecursiveQueriesMaxDepth; Configuration = new((IProfileConfiguration)configuration); int typeMapsCount = Configuration.TypeMapsCount; @@ -232,18 +233,8 @@ LambdaExpression GenerateObjectMapperExpression(in MapRequest mapRequest, IObjec return Lambda(fullExpression, source, destination, ContextParameter); } } - IProjectionBuilder IGlobalConfiguration.ProjectionBuilder - { - get - { - if (_projectionBuilder == null) - { - CreateProjectionBuilder(); - } - return _projectionBuilder; - void CreateProjectionBuilder() => Interlocked.CompareExchange(ref _projectionBuilder, new(this, _validator.Expression.ProjectionMappers.ToArray()), null); - } - } + ProjectionBuilder CreateProjectionBuilder() => new(this, _validator.Expression.ProjectionMappers.ToArray()); + IProjectionBuilder IGlobalConfiguration.ProjectionBuilder => _projectionBuilder.Value; Func IGlobalConfiguration.ServiceCtor => _serviceCtor; bool IGlobalConfiguration.EnableNullPropagationForQueryMapping => _enableNullPropagationForQueryMapping; int IGlobalConfiguration.MaxExecutionPlanDepth => _maxExecutionPlanDepth; @@ -493,7 +484,7 @@ IObjectMapper FindMapper(TypePair types) void IGlobalConfiguration.AssertConfigurationIsValid(TypeMap typeMap) => _validator.AssertConfigurationIsValid(this, new[] { typeMap }); void IGlobalConfiguration.AssertConfigurationIsValid(string profileName) { - if (Profiles.All(x => x.Name != profileName)) + if (Array.TrueForAll(Profiles, x => x.Name != profileName)) { throw new ArgumentOutOfRangeException(nameof(profileName), $"Cannot find any profiles with the name '{profileName}'."); } @@ -502,4 +493,11 @@ void IGlobalConfiguration.AssertConfigurationIsValid(string profileName) void IGlobalConfiguration.AssertConfigurationIsValid() => this.Internal().AssertConfigurationIsValid(typeof(TProfile).FullName); void IGlobalConfiguration.RegisterAsMap(TypeMapConfiguration typeMapConfiguration) => _resolvedMaps[typeMapConfiguration.Types] = GetIncludedTypeMap(new(typeMapConfiguration.SourceType, typeMapConfiguration.DestinationTypeOverride)); +} +struct LazyValue where T : class +{ + readonly Func _factory; + T _value = null; + public T Value => LazyInitializer.EnsureInitialized(ref _value, _factory); + public LazyValue(Func factory) => _factory = factory; } \ No newline at end of file diff --git a/src/AutoMapper/Configuration/MappingExpression.cs b/src/AutoMapper/Configuration/MappingExpression.cs index 4728c67da6..cec443a8c6 100644 --- a/src/AutoMapper/Configuration/MappingExpression.cs +++ b/src/AutoMapper/Configuration/MappingExpression.cs @@ -52,33 +52,6 @@ internal MemberConfigurationExpression ForMember(MemberInfo destinationProperty, memberOptions(expression); return expression; } - public class MemberConfigurationExpression : MemberConfigurationExpression, IMemberConfigurationExpression - { - public MemberConfigurationExpression(MemberInfo destinationMember, Type sourceType) : base(destinationMember, sourceType){} - public void MapFrom(Type valueResolverType) => MapFromCore(new(valueResolverType, valueResolverType.GetGenericInterface(typeof(IValueResolver<,,>)))); - public void MapFrom(Type valueResolverType, string sourceMemberName) => - MapFromCore(new(valueResolverType, valueResolverType.GetGenericInterface(typeof(IMemberValueResolver<,,,>))) - { - SourceMemberName = sourceMemberName - }); - public void MapFrom(IMemberValueResolver resolver, string sourceMemberName) => - MapFromCore(new(resolver, typeof(IMemberValueResolver)) - { - SourceMemberName = sourceMemberName - }); - public void ConvertUsing(Type valueConverterType) => ConvertUsingCore(valueConverterType); - public void ConvertUsing(Type valueConverterType, string sourceMemberName) => ConvertUsingCore(valueConverterType, sourceMemberName); - public void ConvertUsing(IValueConverter valueConverter, string sourceMemberName) => - base.ConvertUsingCore(new(valueConverter, typeof(IValueConverter)) - { - SourceMemberName = sourceMemberName - }); - private void ConvertUsingCore(Type valueConverterType, string sourceMemberName = null) => - base.ConvertUsingCore(new(valueConverterType, valueConverterType.GetGenericInterface(typeof(IValueConverter<,>))) - { - SourceMemberName = sourceMemberName - }); - } } public class MappingExpression : MappingExpressionBase>, IMappingExpression, IProjectionExpression diff --git a/src/AutoMapper/Configuration/MemberConfigurationExpression.cs b/src/AutoMapper/Configuration/MemberConfigurationExpression.cs index ec42a88b97..ac0c195b18 100644 --- a/src/AutoMapper/Configuration/MemberConfigurationExpression.cs +++ b/src/AutoMapper/Configuration/MemberConfigurationExpression.cs @@ -165,4 +165,31 @@ public IPropertyMapConfiguration Reverse() return PathConfigurationExpression.Create(SourceExpression, GetDestinationExpression()); } public void DoNotUseDestinationValue() => SetUseDestinationValue(false); +} +public class MemberConfigurationExpression : MemberConfigurationExpression, IMemberConfigurationExpression +{ + public MemberConfigurationExpression(MemberInfo destinationMember, Type sourceType) : base(destinationMember, sourceType){} + public void MapFrom(Type valueResolverType) => MapFromCore(new(valueResolverType, valueResolverType.GetGenericInterface(typeof(IValueResolver<,,>)))); + public void MapFrom(Type valueResolverType, string sourceMemberName) => + MapFromCore(new(valueResolverType, valueResolverType.GetGenericInterface(typeof(IMemberValueResolver<,,,>))) + { + SourceMemberName = sourceMemberName + }); + public void MapFrom(IMemberValueResolver resolver, string sourceMemberName) => + MapFromCore(new(resolver, typeof(IMemberValueResolver)) + { + SourceMemberName = sourceMemberName + }); + public void ConvertUsing(Type valueConverterType) => ConvertUsingCore(valueConverterType); + public void ConvertUsing(Type valueConverterType, string sourceMemberName) => ConvertUsingCore(valueConverterType, sourceMemberName); + public void ConvertUsing(IValueConverter valueConverter, string sourceMemberName) => + base.ConvertUsingCore(new(valueConverter, typeof(IValueConverter)) + { + SourceMemberName = sourceMemberName + }); + private void ConvertUsingCore(Type valueConverterType, string sourceMemberName = null) => + base.ConvertUsingCore(new(valueConverterType, valueConverterType.GetGenericInterface(typeof(IValueConverter<,>))) + { + SourceMemberName = sourceMemberName + }); } \ No newline at end of file diff --git a/src/AutoMapper/Features.cs b/src/AutoMapper/Features.cs index d01315dd96..5af0626f09 100644 --- a/src/AutoMapper/Features.cs +++ b/src/AutoMapper/Features.cs @@ -1,5 +1,4 @@ -using System.Collections; -namespace AutoMapper.Features; +namespace AutoMapper.Features; public interface IGlobalFeature { void Configure(IGlobalConfiguration configuration); diff --git a/src/AutoMapper/ProfileMap.cs b/src/AutoMapper/ProfileMap.cs index ed5b68c9a4..30006b3580 100644 --- a/src/AutoMapper/ProfileMap.cs +++ b/src/AutoMapper/ProfileMap.cs @@ -9,7 +9,7 @@ public class ProfileMap private TypeMapConfiguration[] _typeMapConfigs; private Dictionary _openTypeMapConfigs; private Dictionary _typeDetails; - private ConcurrentDictionary _runtimeTypeDetails; + private LazyValue> _runtimeTypeDetails; public ProfileMap(IProfileConfiguration profile, IGlobalConfigurationExpression configuration = null) { var globalProfile = (IProfileConfiguration)configuration; @@ -39,6 +39,7 @@ public ProfileMap(IProfileConfiguration profile, IGlobalConfigurationExpression TypeMapConfigs(); OpenTypeMapConfigs(); _typeDetails = new(2 * _typeMapConfigs.Length); + _runtimeTypeDetails = new(()=>new(Environment.ProcessorCount, 2 * _openTypeMapConfigs.Count)); return; void TypeMapConfigs() { @@ -99,7 +100,7 @@ public TypeDetails CreateTypeDetails(Type type) { if (_typeDetails == null) { - return CreateRuntimeTypeDetails(type); + return _runtimeTypeDetails.Value.GetOrAdd(type, (type, profile) => new(type, profile), this); } if (_typeDetails.TryGetValue(type, out var typeDetails)) { @@ -108,14 +109,6 @@ public TypeDetails CreateTypeDetails(Type type) typeDetails = new(type, this); _typeDetails.Add(type, typeDetails); return typeDetails; - TypeDetails CreateRuntimeTypeDetails(Type type) - { - if (_runtimeTypeDetails == null) - { - Interlocked.CompareExchange(ref _runtimeTypeDetails, new(Environment.ProcessorCount, 2 * _openTypeMapConfigs.Count), null); - } - return _runtimeTypeDetails.GetOrAdd(type, (type, profile) => new(type, profile), this); - } } public void Register(IGlobalConfiguration configuration) { @@ -187,7 +180,7 @@ private void Configure(TypeMap typeMap, IGlobalConfiguration configuration) { foreach (var propertyMap in typeMap.PropertyMaps) { - var memberExpression = new MappingExpression.MemberConfigurationExpression(propertyMap.DestinationMember, typeMap.SourceType); + var memberExpression = new MemberConfigurationExpression(propertyMap.DestinationMember, typeMap.SourceType); action(propertyMap, memberExpression); memberExpression.Configure(typeMap); } diff --git a/src/UnitTests/Projection/ProjectTest.cs b/src/UnitTests/Projection/ProjectTest.cs index ded6a5e948..32e6cd6a1d 100644 --- a/src/UnitTests/Projection/ProjectTest.cs +++ b/src/UnitTests/Projection/ProjectTest.cs @@ -20,6 +20,12 @@ public class FooDto public void Should_work() { new[] { new Foo() }.AsQueryable().ProjectTo(Configuration).Single().A.ShouldBe(0); + + var p1 = Configuration.Internal().ProjectionBuilder; + var p2 = Configuration.Internal().ProjectionBuilder; + p2.ShouldBe(p1); + var profile = Configuration.Internal().Profiles[0]; + profile.CreateTypeDetails(typeof(DateTime)).ShouldBe(profile.CreateTypeDetails(typeof(DateTime))); } } From 970ab2db8cd042279e6515ff03f8cc0cbd593863 Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Wed, 14 Sep 2022 21:38:43 +0300 Subject: [PATCH 60/67] an adhoc fix for including open generic config --- .../Execution/TypeMapPlanBuilder.cs | 3 +++ src/AutoMapper/Internal/ReflectionHelper.cs | 5 ++-- src/AutoMapper/MemberMap.cs | 2 +- src/AutoMapper/PropertyMap.cs | 18 ++++++++++--- .../OpenGenericsWithInheritance.cs | 26 +++++++++++++++++++ 5 files changed, 48 insertions(+), 6 deletions(-) diff --git a/src/AutoMapper/Execution/TypeMapPlanBuilder.cs b/src/AutoMapper/Execution/TypeMapPlanBuilder.cs index cb4baabc89..af1a0efac7 100644 --- a/src/AutoMapper/Execution/TypeMapPlanBuilder.cs +++ b/src/AutoMapper/Execution/TypeMapPlanBuilder.cs @@ -418,6 +418,7 @@ public interface IValueResolver Type ResolvedType { get; } string SourceMemberName => null; LambdaExpression ProjectToExpression => null; + IValueResolver CloseGenerics(TypeMap typeMap) => this; } public class MemberPathResolver : IValueResolver { @@ -431,6 +432,8 @@ public Expression GetExpression(IGlobalConfiguration configuration, MemberMap me } public MemberInfo GetSourceMember(MemberMap memberMap) => _members.Length == 1 ? _members[0] : null; public LambdaExpression ProjectToExpression => _members.Lambda(); + public IValueResolver CloseGenerics(TypeMap typeMap) => _members[0].DeclaringType.ContainsGenericParameters ? + new MemberPathResolver(ReflectionHelper.GetMemberPath(typeMap.SourceType, Array.ConvertAll(_members, m => m.Name), typeMap)) : this; } public abstract class LambdaValueResolver { diff --git a/src/AutoMapper/Internal/ReflectionHelper.cs b/src/AutoMapper/Internal/ReflectionHelper.cs index e2e81d9dd1..8035ff856b 100644 --- a/src/AutoMapper/Internal/ReflectionHelper.cs +++ b/src/AutoMapper/Internal/ReflectionHelper.cs @@ -45,9 +45,10 @@ public static void SetMemberValue(this MemberInfo propertyOrField, object target FieldInfo field => field.GetValue(target), _ => throw Expected(propertyOrField) }; - public static MemberInfo[] GetMemberPath(Type type, string fullMemberName, TypeMap typeMap = null) + public static MemberInfo[] GetMemberPath(Type type, string fullMemberName, TypeMap typeMap = null) => + GetMemberPath(type, fullMemberName.Split('.'), typeMap); + public static MemberInfo[] GetMemberPath(Type type, string[] memberNames, TypeMap typeMap = null) { - var memberNames = fullMemberName.Split('.'); var sourceDetails = typeMap?.SourceTypeDetails; if (sourceDetails != null && memberNames.Length == 1) { diff --git a/src/AutoMapper/MemberMap.cs b/src/AutoMapper/MemberMap.cs index 040f6a5b9c..eecdf7476e 100644 --- a/src/AutoMapper/MemberMap.cs +++ b/src/AutoMapper/MemberMap.cs @@ -40,7 +40,7 @@ public void MapFrom(LambdaExpression sourceMember) public void MapFrom(string sourceMembersPath, MemberInfo[] members) { var sourceType = TypeMap.SourceType; - var sourceMembers = sourceType.ContainsGenericParameters ? null :// just a placeholder so the member is mapped + var sourceMembers = sourceType.ContainsGenericParameters ? members : members[0].DeclaringType.ContainsGenericParameters ? ReflectionHelper.GetMemberPath(sourceType, sourceMembersPath, TypeMap) : members; Resolver = new MemberPathResolver(sourceMembers); } diff --git a/src/AutoMapper/PropertyMap.cs b/src/AutoMapper/PropertyMap.cs index 0e6ac2bbf2..0a3d0cac3a 100644 --- a/src/AutoMapper/PropertyMap.cs +++ b/src/AutoMapper/PropertyMap.cs @@ -11,8 +11,20 @@ public PropertyMap(MemberInfo destinationMember, Type destinationMemberType, Typ DestinationMember = destinationMember; DestinationType = destinationMemberType; } - public PropertyMap(PropertyMap inheritedMappedProperty, TypeMap typeMap) - : this(inheritedMappedProperty.DestinationMember, inheritedMappedProperty.DestinationType, typeMap) => ApplyInheritedPropertyMap(inheritedMappedProperty); + public PropertyMap(PropertyMap inheritedMappedProperty, TypeMap typeMap) : base(typeMap) + { + DestinationMember = inheritedMappedProperty.DestinationMember; + if (DestinationMember.DeclaringType.ContainsGenericParameters) + { + DestinationMember = typeMap.DestinationSetters.Single(m => m.Name == DestinationMember.Name); + } + DestinationType = inheritedMappedProperty.DestinationType; + if (DestinationType.ContainsGenericParameters) + { + DestinationType = DestinationMember.GetMemberType(); + } + ApplyInheritedPropertyMap(inheritedMappedProperty); + } public PropertyMap(PropertyMap includedMemberMap, TypeMap typeMap, IncludedMember includedMember) : this(includedMemberMap, typeMap) => Details.IncludedMember = includedMember.Chain(includedMemberMap.IncludedMember); private MemberMapDetails Details => _details ??= new(); @@ -39,7 +51,7 @@ public void ApplyInheritedPropertyMap(PropertyMap inheritedMappedProperty) if (inheritedMappedProperty.IsResolveConfigured) { _sourceType = inheritedMappedProperty._sourceType; - Resolver = inheritedMappedProperty.Resolver; + Resolver = inheritedMappedProperty.Resolver.CloseGenerics(TypeMap); } else if (Resolver == null) { diff --git a/src/UnitTests/MappingInheritance/OpenGenericsWithInheritance.cs b/src/UnitTests/MappingInheritance/OpenGenericsWithInheritance.cs index 8723aa66fa..9dfd6eca39 100644 --- a/src/UnitTests/MappingInheritance/OpenGenericsWithInheritance.cs +++ b/src/UnitTests/MappingInheritance/OpenGenericsWithInheritance.cs @@ -218,4 +218,30 @@ public void Should_work() model.Id.ShouldBe(695); model.SubMember.ShouldBe("bar"); } +} +public class IncludeBaseOpenGenerics : AutoMapperSpecBase +{ + public abstract class OrderModel + { + public string Number { get; set; } + } + public class InternetOrderModel : OrderModel + { + } + public abstract class Order + { + public string OrderNumber { get; set; } + } + public class InternetOrder : Order + { + } + protected override MapperConfiguration CreateConfiguration() => new(c => + { + c.CreateMap(typeof(OrderModel<>), typeof(Order<>)) + .ForMember("OrderNumber", o => o.MapFrom("Number")); + c.CreateMap() + .IncludeBase(typeof(OrderModel<>), typeof(Order<>)); + }); + [Fact] + public void Shoud_work() => Mapper.Map(new InternetOrderModel { Number = "42" }).OrderNumber.ShouldBe("42"); } \ No newline at end of file From e7ba023083eda38cd4530f3682a7baec093aeced Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Sun, 18 Sep 2022 09:52:46 +0300 Subject: [PATCH 61/67] cosmetic --- .../Configuration/MapperConfiguration.cs | 19 ++++++------------- .../Configuration/MappingExpression.cs | 2 +- src/AutoMapper/Execution/ExpressionBuilder.cs | 2 +- src/AutoMapper/Internal/TypeDetails.cs | 4 ++-- src/AutoMapper/Mappers/ConstructorMapper.cs | 2 +- .../Mappers/ConversionOperatorMapper.cs | 2 +- src/AutoMapper/Mappers/KeyValueMapper.cs | 2 +- src/AutoMapper/Mappers/ParseStringMapper.cs | 2 +- src/AutoMapper/Mappers/ToStringMapper.cs | 2 +- .../QueryableExtensions/Extensions.cs | 2 +- .../NullsafeQueryRewriter.cs | 12 ++++++------ .../AssignableProjectionMapper.cs | 3 +-- .../StringProjectionMapper.cs | 2 +- 13 files changed, 24 insertions(+), 32 deletions(-) diff --git a/src/AutoMapper/Configuration/MapperConfiguration.cs b/src/AutoMapper/Configuration/MapperConfiguration.cs index 6f5de059e0..ec32cc31b1 100644 --- a/src/AutoMapper/Configuration/MapperConfiguration.cs +++ b/src/AutoMapper/Configuration/MapperConfiguration.cs @@ -45,10 +45,6 @@ public class MapperConfiguration : IGlobalConfiguration private readonly LockingConcurrentDictionary _executionPlans; private readonly ConfigurationValidator _validator; private readonly Features _features = new(); - private readonly int _recursiveQueriesMaxDepth; - private readonly int _maxExecutionPlanDepth; - private readonly bool _enableNullPropagationForQueryMapping; - private readonly Func _serviceCtor; private readonly bool _sealed; private readonly bool _hasOpenMaps; private readonly HashSet _typeMapsPath = new(); @@ -71,11 +67,7 @@ public MapperConfiguration(MapperConfigurationExpression configurationExpression _mappers = configuration.Mappers.ToArray(); _executionPlans = new(CompileExecutionPlan); _validator = new(configuration); - _serviceCtor = configuration.ServiceCtor; - _enableNullPropagationForQueryMapping = configuration.EnableNullPropagationForQueryMapping ?? false; - _maxExecutionPlanDepth = configuration.MaxExecutionPlanDepth + 1; _projectionBuilder = new(CreateProjectionBuilder); - _recursiveQueriesMaxDepth = configuration.RecursiveQueriesMaxDepth; Configuration = new((IProfileConfiguration)configuration); int typeMapsCount = Configuration.TypeMapsCount; int openTypeMapsCount = Configuration.OpenTypeMapsCount; @@ -233,15 +225,16 @@ LambdaExpression GenerateObjectMapperExpression(in MapRequest mapRequest, IObjec return Lambda(fullExpression, source, destination, ContextParameter); } } - ProjectionBuilder CreateProjectionBuilder() => new(this, _validator.Expression.ProjectionMappers.ToArray()); + IGlobalConfigurationExpression ConfigurationExpression => _validator.Expression; + ProjectionBuilder CreateProjectionBuilder() => new(this, ConfigurationExpression.ProjectionMappers.ToArray()); IProjectionBuilder IGlobalConfiguration.ProjectionBuilder => _projectionBuilder.Value; - Func IGlobalConfiguration.ServiceCtor => _serviceCtor; - bool IGlobalConfiguration.EnableNullPropagationForQueryMapping => _enableNullPropagationForQueryMapping; - int IGlobalConfiguration.MaxExecutionPlanDepth => _maxExecutionPlanDepth; + Func IGlobalConfiguration.ServiceCtor => ConfigurationExpression.ServiceCtor; + bool IGlobalConfiguration.EnableNullPropagationForQueryMapping => ConfigurationExpression.EnableNullPropagationForQueryMapping.GetValueOrDefault(); + int IGlobalConfiguration.MaxExecutionPlanDepth => ConfigurationExpression.MaxExecutionPlanDepth + 1; private ProfileMap Configuration { get; } ProfileMap[] IGlobalConfiguration.Profiles => Profiles; internal ProfileMap[] Profiles { get; } - int IGlobalConfiguration.RecursiveQueriesMaxDepth => _recursiveQueriesMaxDepth; + int IGlobalConfiguration.RecursiveQueriesMaxDepth => ConfigurationExpression.RecursiveQueriesMaxDepth; Features IGlobalConfiguration.Features => _features; List IGlobalConfiguration.SourceMembers => _sourceMembers; List IGlobalConfiguration.Variables => _variables; diff --git a/src/AutoMapper/Configuration/MappingExpression.cs b/src/AutoMapper/Configuration/MappingExpression.cs index cec443a8c6..6bb950e180 100644 --- a/src/AutoMapper/Configuration/MappingExpression.cs +++ b/src/AutoMapper/Configuration/MappingExpression.cs @@ -89,7 +89,7 @@ public IMappingExpression IncludeMembers(params Expressio e => { var bodyIsCastToObject = e.Body.NodeType == ExpressionType.Convert && e.Body.Type == typeof(object); - return bodyIsCastToObject ? Expression.Lambda(((UnaryExpression)e.Body).Operand, e.Parameters) : e; + return bodyIsCastToObject ? Lambda(((UnaryExpression)e.Body).Operand, e.Parameters) : e; }); IncludeMembersCore(memberExpressionsWithoutCastToObject); return this; diff --git a/src/AutoMapper/Execution/ExpressionBuilder.cs b/src/AutoMapper/Execution/ExpressionBuilder.cs index 60826491fd..224a93db3d 100644 --- a/src/AutoMapper/Execution/ExpressionBuilder.cs +++ b/src/AutoMapper/Execution/ExpressionBuilder.cs @@ -449,5 +449,5 @@ public class ParameterReplaceVisitor : ReplaceVisitorBase public class ConvertParameterReplaceVisitor : ParameterReplaceVisitor { public override Expression Replace(Expression target, Expression oldNode, Expression newNode) => - base.Replace(target, oldNode, ExpressionBuilder.ToType(newNode, oldNode.Type)); + base.Replace(target, oldNode, ToType(newNode, oldNode.Type)); } \ No newline at end of file diff --git a/src/AutoMapper/Internal/TypeDetails.cs b/src/AutoMapper/Internal/TypeDetails.cs index 6eb8849a89..40c1ff28e0 100644 --- a/src/AutoMapper/Internal/TypeDetails.cs +++ b/src/AutoMapper/Internal/TypeDetails.cs @@ -93,7 +93,7 @@ class GenericMethod : MemberInfo { readonly MethodInfo _genericMethod; readonly Type _genericInterface; - MethodInfo _closedMethod = ExpressionBuilder.DecTypeDepthInfo; + MethodInfo _closedMethod = DecTypeDepthInfo; public GenericMethod(MethodInfo genericMethod, Type genericInterface) { _genericMethod = genericMethod; @@ -101,7 +101,7 @@ public GenericMethod(MethodInfo genericMethod, Type genericInterface) } public MethodInfo Close() { - if (_closedMethod == ExpressionBuilder.DecTypeDepthInfo) + if (_closedMethod == DecTypeDepthInfo) { // Use method.MakeGenericMethod(genericArguments) wrapped in a try/catch(ArgumentException) // in order to catch exceptions resulting from the generic arguments not being compatible diff --git a/src/AutoMapper/Mappers/ConstructorMapper.cs b/src/AutoMapper/Mappers/ConstructorMapper.cs index 96dda2e20f..325214a724 100644 --- a/src/AutoMapper/Mappers/ConstructorMapper.cs +++ b/src/AutoMapper/Mappers/ConstructorMapper.cs @@ -7,6 +7,6 @@ private static ConstructorInfo GetConstructor(Type sourceType, Type destinationT public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) { var constructor = GetConstructor(sourceExpression.Type, destExpression.Type); - return Expression.New(constructor, ToType(sourceExpression, constructor.FirstParameterType())); + return New(constructor, ToType(sourceExpression, constructor.FirstParameterType())); } } \ No newline at end of file diff --git a/src/AutoMapper/Mappers/ConversionOperatorMapper.cs b/src/AutoMapper/Mappers/ConversionOperatorMapper.cs index a13496e1d7..f5d38535ff 100644 --- a/src/AutoMapper/Mappers/ConversionOperatorMapper.cs +++ b/src/AutoMapper/Mappers/ConversionOperatorMapper.cs @@ -18,6 +18,6 @@ private MethodInfo GetConversionOperator(Type sourceType, Type destinationType) public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) { var conversionOperator = GetConversionOperator(sourceExpression.Type, destExpression.Type); - return Expression.Call(conversionOperator, ToType(sourceExpression, conversionOperator.FirstParameterType())); + return Call(conversionOperator, ToType(sourceExpression, conversionOperator.FirstParameterType())); } } diff --git a/src/AutoMapper/Mappers/KeyValueMapper.cs b/src/AutoMapper/Mappers/KeyValueMapper.cs index dd77be0dfb..70a867639c 100644 --- a/src/AutoMapper/Mappers/KeyValueMapper.cs +++ b/src/AutoMapper/Mappers/KeyValueMapper.cs @@ -12,6 +12,6 @@ public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap p var values = new TypePair(sourceArguments[1], destinationArguments[1]); var mapKeys = configuration.MapExpression(profileMap, keys, ExpressionBuilder.Property(sourceExpression, "Key")); var mapValues = configuration.MapExpression(profileMap, values, ExpressionBuilder.Property(sourceExpression, "Value")); - return Expression.New(destinationType.GetConstructor(destinationArguments), mapKeys, mapValues); + return New(destinationType.GetConstructor(destinationArguments), mapKeys, mapValues); } } \ No newline at end of file diff --git a/src/AutoMapper/Mappers/ParseStringMapper.cs b/src/AutoMapper/Mappers/ParseStringMapper.cs index 8a0aac0f2a..93cd16b351 100644 --- a/src/AutoMapper/Mappers/ParseStringMapper.cs +++ b/src/AutoMapper/Mappers/ParseStringMapper.cs @@ -5,5 +5,5 @@ public class ParseStringMapper : IObjectMapper public bool IsMatch(TypePair context) => context.SourceType == typeof(string) && HasParse(context.DestinationType); static bool HasParse(Type type) => type == typeof(Guid) || type == typeof(TimeSpan) || type == typeof(DateTimeOffset); public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) => - Expression.Call(destExpression.Type.GetMethod("Parse", new[] { typeof(string) }), sourceExpression); + Call(destExpression.Type.GetMethod("Parse", new[] { typeof(string) }), sourceExpression); } \ No newline at end of file diff --git a/src/AutoMapper/Mappers/ToStringMapper.cs b/src/AutoMapper/Mappers/ToStringMapper.cs index 97a8767c34..243b05db0f 100644 --- a/src/AutoMapper/Mappers/ToStringMapper.cs +++ b/src/AutoMapper/Mappers/ToStringMapper.cs @@ -5,7 +5,7 @@ public class ToStringMapper : IObjectMapper public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) { var sourceType = sourceExpression.Type; - var toStringCall = Call(sourceExpression, ExpressionBuilder.ObjectToString); + var toStringCall = Call(sourceExpression, ObjectToString); return sourceType.IsEnum ? StringToEnumMapper.CheckEnumMember(sourceExpression, sourceType, toStringCall) : toStringCall; } } \ No newline at end of file diff --git a/src/AutoMapper/QueryableExtensions/Extensions.cs b/src/AutoMapper/QueryableExtensions/Extensions.cs index 41d55ad326..8b50d06579 100644 --- a/src/AutoMapper/QueryableExtensions/Extensions.cs +++ b/src/AutoMapper/QueryableExtensions/Extensions.cs @@ -9,7 +9,7 @@ public static class Extensions { static readonly MethodInfo SelectMethod = typeof(Queryable).StaticGenericMethod("Select", parametersCount: 2); static IQueryable Select(IQueryable source, LambdaExpression lambda) => source.Provider.CreateQuery( - Expression.Call(SelectMethod.MakeGenericMethod(source.ElementType, lambda.ReturnType), source.Expression, Expression.Quote(lambda))); + Call(SelectMethod.MakeGenericMethod(source.ElementType, lambda.ReturnType), source.Expression, Quote(lambda))); /// /// Extension method to project from a queryable using the provided mapping engine /// diff --git a/src/AutoMapper/QueryableExtensions/NullsafeQueryRewriter.cs b/src/AutoMapper/QueryableExtensions/NullsafeQueryRewriter.cs index 556584fe26..0bf827b787 100644 --- a/src/AutoMapper/QueryableExtensions/NullsafeQueryRewriter.cs +++ b/src/AutoMapper/QueryableExtensions/NullsafeQueryRewriter.cs @@ -95,17 +95,17 @@ static Expression BeSafe(Expression target, Expression expression, Func context.DestinationType.IsAssignableFrom(context.SourceType); public Expression Project(IGlobalConfiguration configuration, in ProjectionRequest request, Expression resolvedSource, LetPropertyMaps letPropertyMaps) - => ExpressionBuilder.ToType(resolvedSource, request.DestinationType); + => ToType(resolvedSource, request.DestinationType); } \ No newline at end of file diff --git a/src/AutoMapper/QueryableExtensions/ProjectionMappers/StringProjectionMapper.cs b/src/AutoMapper/QueryableExtensions/ProjectionMappers/StringProjectionMapper.cs index 42f1ea58f8..a635ce7c2d 100644 --- a/src/AutoMapper/QueryableExtensions/ProjectionMappers/StringProjectionMapper.cs +++ b/src/AutoMapper/QueryableExtensions/ProjectionMappers/StringProjectionMapper.cs @@ -5,5 +5,5 @@ public class StringProjectionMapper : IProjectionMapper { public bool IsMatch(TypePair context) => context.DestinationType == typeof(string); public Expression Project(IGlobalConfiguration configuration, in ProjectionRequest request, Expression resolvedSource, LetPropertyMaps letPropertyMaps) - => Expression.Call(resolvedSource, ExpressionBuilder.ObjectToString); + => Call(resolvedSource, ObjectToString); } \ No newline at end of file From 2b99e963028d3213a4feeace07e59c3a39dc698c Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Sun, 18 Sep 2022 18:37:54 +0300 Subject: [PATCH 62/67] MapFrom should override ignore --- .../CtorParamConfigurationExpression.cs | 4 +-- .../MemberConfigurationExpression.cs | 2 +- .../Configuration/TypeMapConfiguration.cs | 2 +- src/AutoMapper/MemberMap.cs | 16 ++++----- .../QueryableExtensions/ProjectionBuilder.cs | 2 +- .../MappingInheritance/OverrideIgnore.cs | 33 +++++++++++-------- 6 files changed, 33 insertions(+), 26 deletions(-) diff --git a/src/AutoMapper/Configuration/CtorParamConfigurationExpression.cs b/src/AutoMapper/Configuration/CtorParamConfigurationExpression.cs index cd56698835..74df41c28e 100644 --- a/src/AutoMapper/Configuration/CtorParamConfigurationExpression.cs +++ b/src/AutoMapper/Configuration/CtorParamConfigurationExpression.cs @@ -45,12 +45,12 @@ public CtorParamConfigurationExpression(string ctorParamName, Type sourceType) } public void MapFrom(Expression> sourceMember) => - _ctorParamActions.Add(cpm => cpm.SetResolver(sourceMember)); + _ctorParamActions.Add(cpm => cpm.MapFrom(sourceMember)); public void MapFrom(Func resolver) { Expression> resolverExpression = (src, dest, destMember, ctxt) => resolver(src, ctxt); - _ctorParamActions.Add(cpm => cpm.Resolver = new FuncResolver(resolverExpression)); + _ctorParamActions.Add(cpm => cpm.SetResolver(new FuncResolver(resolverExpression))); } public void MapFrom(string sourceMembersPath) diff --git a/src/AutoMapper/Configuration/MemberConfigurationExpression.cs b/src/AutoMapper/Configuration/MemberConfigurationExpression.cs index ac0c195b18..be83b6973f 100644 --- a/src/AutoMapper/Configuration/MemberConfigurationExpression.cs +++ b/src/AutoMapper/Configuration/MemberConfigurationExpression.cs @@ -24,7 +24,7 @@ public MemberConfigurationExpression(MemberInfo destinationMember, Type sourceTy public void MapFrom() where TValueResolver : IValueResolver => MapFromCore(new(typeof(TValueResolver), typeof(IValueResolver))); protected void MapFromCore(ClassValueResolver config) => SetResolver(config); - protected void SetResolver(IValueResolver config) => PropertyMapActions.Add(pm => pm.Resolver = config); + protected void SetResolver(IValueResolver config) => PropertyMapActions.Add(pm => pm.SetResolver(config)); public void MapFrom(Expression> sourceMember) where TValueResolver : IMemberValueResolver => MapFromCore(sourceMember); diff --git a/src/AutoMapper/Configuration/TypeMapConfiguration.cs b/src/AutoMapper/Configuration/TypeMapConfiguration.cs index fca220cfac..ffdc1a49bf 100644 --- a/src/AutoMapper/Configuration/TypeMapConfiguration.cs +++ b/src/AutoMapper/Configuration/TypeMapConfiguration.cs @@ -185,7 +185,7 @@ private void ReverseSourceMembers(MemberPath memberPath, LambdaExpression custom var pathMap = reverseTypeMap.FindOrCreatePathMapFor(forPathLambda, memberPath, reverseTypeMap); - pathMap.SetResolver(customExpression); + pathMap.MapFrom(customExpression); }); } protected void ForSourceMemberCore(string sourceMemberName, Action memberOptions) diff --git a/src/AutoMapper/MemberMap.cs b/src/AutoMapper/MemberMap.cs index eecdf7476e..065243548a 100644 --- a/src/AutoMapper/MemberMap.cs +++ b/src/AutoMapper/MemberMap.cs @@ -10,7 +10,12 @@ public class MemberMap : IValueResolver public TypeMap TypeMap { get; protected set; } public LambdaExpression CustomMapExpression => Resolver?.ProjectToExpression; public bool IsResolveConfigured => Resolver != null && Resolver != this; - public void SetResolver(LambdaExpression lambda) => Resolver = new ExpressionResolver(lambda); + public void MapFrom(LambdaExpression lambda) => SetResolver(new ExpressionResolver(lambda)); + public void SetResolver(IValueResolver resolver) + { + Resolver = resolver; + Ignored = false; + } public virtual Type SourceType => default; public virtual MemberInfo[] SourceMembers { get => Array.Empty(); set { } } public virtual IncludedMember IncludedMember => null; @@ -27,22 +32,17 @@ public class MemberMap : IValueResolver public virtual object NullSubstitute { get => default; set { } } public virtual LambdaExpression PreCondition { get => default; set { } } public virtual LambdaExpression Condition { get => default; set { } } - public IValueResolver Resolver { get; set; } + public IValueResolver Resolver { get; protected set; } public virtual IReadOnlyCollection ValueTransformers => Array.Empty(); public MemberInfo SourceMember => Resolver?.GetSourceMember(this); public string GetSourceMemberName() => Resolver?.SourceMemberName ?? SourceMember?.Name; public bool MustUseDestination => UseDestinationValue is true || !CanBeSet; - public void MapFrom(LambdaExpression sourceMember) - { - SetResolver(sourceMember); - Ignored = false; - } public void MapFrom(string sourceMembersPath, MemberInfo[] members) { var sourceType = TypeMap.SourceType; var sourceMembers = sourceType.ContainsGenericParameters ? members : members[0].DeclaringType.ContainsGenericParameters ? ReflectionHelper.GetMemberPath(sourceType, sourceMembersPath, TypeMap) : members; - Resolver = new MemberPathResolver(sourceMembers); + SetResolver(new MemberPathResolver(sourceMembers)); } public override string ToString() => DestinationName; public Expression ChainSourceMembers(Expression source) => SourceMembers.Chain(source); diff --git a/src/AutoMapper/QueryableExtensions/ProjectionBuilder.cs b/src/AutoMapper/QueryableExtensions/ProjectionBuilder.cs index 0a4f3a303e..2953a90bfc 100644 --- a/src/AutoMapper/QueryableExtensions/ProjectionBuilder.cs +++ b/src/AutoMapper/QueryableExtensions/ProjectionBuilder.cs @@ -245,7 +245,7 @@ void ReplaceSubQueries() { var letProperty = letType.GetProperty(letMapInfo.Property.Name); var letPropertyMap = letTypeMap.FindOrCreatePropertyMapFor(letProperty, letMapInfo.Property.Type); - letPropertyMap.SetResolver(Lambda(letMapInfo.LetExpression.ReplaceParameters(letMapInfo.MapFromSource), secondParameter)); + letPropertyMap.MapFrom(Lambda(letMapInfo.LetExpression.ReplaceParameters(letMapInfo.MapFromSource), secondParameter)); projection = projection.Replace(letMapInfo.Marker, Property(secondParameter, letProperty)); } projection = new ReplaceMemberAccessesVisitor(instanceParameter, secondParameter).Visit(projection); diff --git a/src/UnitTests/MappingInheritance/OverrideIgnore.cs b/src/UnitTests/MappingInheritance/OverrideIgnore.cs index b832a799d7..a893d35afe 100644 --- a/src/UnitTests/MappingInheritance/OverrideIgnore.cs +++ b/src/UnitTests/MappingInheritance/OverrideIgnore.cs @@ -1,38 +1,45 @@ namespace AutoMapper.UnitTests.Bug; - -public class OverrideIgnore +public class OverrideIgnoreMapFromString { public class DomainBase { public string SomeProperty { get; set; } } - public class DtoBase { public string SomeDifferentProperty { get; set; } } - [Fact] public void specifying_map_should_override_ignore() { var config = new MapperConfiguration(cfg => cfg.CreateMap() .ForMember(m=>m.SomeDifferentProperty, m=>m.Ignore()) - .ForMember(m=>m.SomeDifferentProperty, m=>m.MapFrom(s=>s.SomeProperty))); + .ForMember(m=>m.SomeDifferentProperty, m=>m.MapFrom("SomeProperty"))); var dto = config.CreateMapper().Map(new DomainBase {SomeProperty = "Test"}); - "Test".ShouldBe(dto.SomeDifferentProperty); + dto.SomeDifferentProperty.ShouldBe("Test"); + } +} +public class OverrideIgnore +{ + public class DomainBase + { + public string SomeProperty { get; set; } + } + public class DtoBase + { + public string SomeDifferentProperty { get; set; } } - [Fact] - public void specifying_map_should_override_ignore_with_one_parameter() + public void specifying_map_should_override_ignore() { var config = new MapperConfiguration(cfg => cfg.CreateMap() - .ForMember(m => m.SomeDifferentProperty, m => m.Ignore()) - .ForMember(m => m.SomeDifferentProperty, m => m.MapFrom(s => s.SomeProperty))); + .ForMember(m=>m.SomeDifferentProperty, m=>m.Ignore()) + .ForMember(m=>m.SomeDifferentProperty, m=>m.MapFrom(s=>s.SomeProperty))); - var dto = config.CreateMapper().Map(new DomainBase { SomeProperty = "Test" }); + var dto = config.CreateMapper().Map(new DomainBase {SomeProperty = "Test"}); - "Test".ShouldBe(dto.SomeDifferentProperty); + dto.SomeDifferentProperty.ShouldBe("Test"); } -} +} \ No newline at end of file From 3f8448a124714abb5af69be5693fa57afb3c66c1 Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Mon, 19 Sep 2022 08:00:14 +0300 Subject: [PATCH 63/67] UseDestinationValueNullable --- src/UnitTests/Bug/UseDestinationValue.cs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/UnitTests/Bug/UseDestinationValue.cs b/src/UnitTests/Bug/UseDestinationValue.cs index 1550b3c728..2be68e795f 100644 --- a/src/UnitTests/Bug/UseDestinationValue.cs +++ b/src/UnitTests/Bug/UseDestinationValue.cs @@ -1,5 +1,19 @@ namespace AutoMapper.UnitTests.Bug; - +public class UseDestinationValueNullable : AutoMapperSpecBase +{ + class Source + { + public int? Value; + } + class Destination + { + public int Value = 42; + } + protected override MapperConfiguration CreateConfiguration() => new(c => + c.CreateMap().ForMember(d => d.Value, o => o.UseDestinationValue())); + [Fact] + public void Should_keep_existing_value() => Map(new Source()).Value.ShouldBe(42); +} public class UseDestinationValue : AutoMapperSpecBase { public class OrganizationDTO From 8b83aa7dadf29f6961c2485161fe749c26f3c26c Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Wed, 21 Sep 2022 09:26:35 +0300 Subject: [PATCH 64/67] cosmetic --- .../Configuration/MapperConfiguration.cs | 24 +++++++++---------- .../Internal/LockingConcurrentDictionary.cs | 1 + 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/AutoMapper/Configuration/MapperConfiguration.cs b/src/AutoMapper/Configuration/MapperConfiguration.cs index ec32cc31b1..69a6c37eea 100644 --- a/src/AutoMapper/Configuration/MapperConfiguration.cs +++ b/src/AutoMapper/Configuration/MapperConfiguration.cs @@ -45,7 +45,6 @@ public class MapperConfiguration : IGlobalConfiguration private readonly LockingConcurrentDictionary _executionPlans; private readonly ConfigurationValidator _validator; private readonly Features _features = new(); - private readonly bool _sealed; private readonly bool _hasOpenMaps; private readonly HashSet _typeMapsPath = new(); private readonly List _sourceMembers = new(); @@ -84,7 +83,6 @@ public MapperConfiguration(MapperConfigurationExpression configurationExpression _defaults = new(3 * typeMapsCount); _configuredMaps = new(typeMapsCount); _hasOpenMaps = openTypeMapsCount > 0; - _runtimeMaps = new(GetTypeMap, openTypeMapsCount); _resolvedMaps = new(2 * typeMapsCount); configuration.Features.Configure(this); @@ -106,7 +104,7 @@ public MapperConfiguration(MapperConfigurationExpression configurationExpression _convertParameterReplaceVisitor = null; _parameterReplaceVisitor = null; _typesInheritance = null; - _sealed = true; + _runtimeMaps = new(GetTypeMap, openTypeMapsCount); return; void Seal() { @@ -289,25 +287,25 @@ TypeMap ResolveTypeMap(TypePair typePair) { return typeMap; } - if (_sealed) + if (_runtimeMaps.IsDefault) { - typeMap = _runtimeMaps.GetOrAdd(typePair); - // if it's a dynamically created type map, we need to seal it outside GetTypeMap to handle recursion + typeMap = GetTypeMap(typePair); + _resolvedMaps.Add(typePair, typeMap); if (typeMap != null && typeMap.MapExpression == null) { - lock (typeMap) - { - typeMap.Seal(this); - } + typeMap.Seal(this); } } else { - typeMap = GetTypeMap(typePair); - _resolvedMaps.Add(typePair, typeMap); + typeMap = _runtimeMaps.GetOrAdd(typePair); + // if it's a dynamically created type map, we need to seal it outside GetTypeMap to handle recursion if (typeMap != null && typeMap.MapExpression == null) { - typeMap.Seal(this); + lock (typeMap) + { + typeMap.Seal(this); + } } } return typeMap; diff --git a/src/AutoMapper/Internal/LockingConcurrentDictionary.cs b/src/AutoMapper/Internal/LockingConcurrentDictionary.cs index 5857d9b8d5..f88b58055f 100644 --- a/src/AutoMapper/Internal/LockingConcurrentDictionary.cs +++ b/src/AutoMapper/Internal/LockingConcurrentDictionary.cs @@ -10,4 +10,5 @@ public LockingConcurrentDictionary(Func valueFactory, int capacity _dictionary = new(Environment.ProcessorCount, capacity); } public TValue GetOrAdd(in TKey key) => _dictionary.GetOrAdd(key, _valueFactory).Value; + public bool IsDefault => _dictionary == null; } \ No newline at end of file From 5e0066e4d4af913a3d672c552bc7dc6bec1804d7 Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Fri, 23 Sep 2022 09:27:25 +0300 Subject: [PATCH 65/67] avoid LINQ --- src/AutoMapper/TypeMap.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/AutoMapper/TypeMap.cs b/src/AutoMapper/TypeMap.cs index 7bca8672ec..fc5d2dcc4e 100644 --- a/src/AutoMapper/TypeMap.cs +++ b/src/AutoMapper/TypeMap.cs @@ -183,9 +183,12 @@ private void CheckDifferent(TypePair types) } internal void IgnorePaths(MemberInfo destinationMember) { - foreach (var pathMap in PathMaps.Where(pm => pm.MemberPath.First == destinationMember)) + foreach (var pathMap in PathMaps) { - pathMap.Ignored = true; + if (pathMap.MemberPath.First == destinationMember) + { + pathMap.Ignored = true; + } } } public bool HasDerivedTypesToInclude => IncludedDerivedTypes.Count > 0; From 7d65b78590b0ecb77c6e03851b802ff0542fe8cd Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Sat, 24 Sep 2022 09:41:27 +0300 Subject: [PATCH 66/67] the destination type name is already in the error message --- src/AutoMapper/ConstructorMap.cs | 2 +- src/UnitTests/ConfigurationValidation.cs | 2 +- src/UnitTests/Constructors.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/AutoMapper/ConstructorMap.cs b/src/AutoMapper/ConstructorMap.cs index 96dd5c38bd..2d2bb21d29 100644 --- a/src/AutoMapper/ConstructorMap.cs +++ b/src/AutoMapper/ConstructorMap.cs @@ -99,6 +99,6 @@ public ConstructorParameterMap(ConstructorParameterMap parameterMap, IncludedMem public override MemberInfo[] SourceMembers { get; set; } public override string DestinationName => Parameter.Name; public Expression DefaultValue(IGlobalConfiguration configuration) => Parameter.IsOptional ? Parameter.GetDefaultValue(configuration) : configuration.Default(DestinationType); - public override string ToString() => $"{Constructor.DeclaringType} {Constructor}, parameter {DestinationName}"; + public override string ToString() => $"{Constructor}, parameter {DestinationName}"; private MemberInfo Constructor => Parameter.Member; } \ No newline at end of file diff --git a/src/UnitTests/ConfigurationValidation.cs b/src/UnitTests/ConfigurationValidation.cs index 3f80f819bb..babd8e4a93 100644 --- a/src/UnitTests/ConfigurationValidation.cs +++ b/src/UnitTests/ConfigurationValidation.cs @@ -29,7 +29,7 @@ private ComplexType(int someMember) [Fact] public void Should_fail_validation() => new Action(AssertConfigurationIsValid).ShouldThrowException(ex=> - ex.MemberMap.ToString().ShouldBe("AutoMapper.UnitTests.ConfigurationValidation.ConstructorMappingValidation+Destination Void .ctor(ComplexType), parameter myComplexMember")); + ex.MemberMap.ToString().ShouldBe("Void .ctor(ComplexType), parameter myComplexMember")); } public class When_using_a_type_converter : AutoMapperSpecBase diff --git a/src/UnitTests/Constructors.cs b/src/UnitTests/Constructors.cs index 2ba648e765..4750056095 100644 --- a/src/UnitTests/Constructors.cs +++ b/src/UnitTests/Constructors.cs @@ -987,7 +987,7 @@ public Dest(Dest foo) public void Should_say_what_parameter_fails() { var ex = new Action(AssertConfigurationIsValid).ShouldThrow(); - ex.Message.ShouldContain("AutoMapper.UnitTests.Constructors.When_mapping_constructor_argument_fails+Dest Void .ctor(Dest), parameter foo", Case.Sensitive); + ex.Message.ShouldContain("Void .ctor(Dest), parameter foo", Case.Sensitive); } } From 3c2d8cdf49463b4ba4abc9530c336b1e43c9b6dd Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Sat, 24 Sep 2022 22:16:37 +0300 Subject: [PATCH 67/67] cosmetic --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 13a595f50b..9b288ebad0 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,9 @@ var configuration = new MapperConfiguration(cfg => cfg.CreateMap(); }); // only during development, validate your mappings; remove it before release +#if DEBUG configuration.AssertConfigurationIsValid(); +#endif // use DI (http://docs.automapper.org/en/latest/Dependency-injection.html) or create the mapper yourself var mapper = configuration.CreateMapper(); ```