From bf2bf918a497735f967d8d2fba1ac12088ed38e8 Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Wed, 1 Apr 2020 10:35:56 +0300 Subject: [PATCH 1/3] disallow mapping into a read-only collection without a setter not needed anymore map read-only collections by default cosmetic When_mapping_to_a_getter_only_ienumerable cosmetic cosmetic upgrade apicompat cosmetic cosmetic add 3.1 target for the integration tests update to Visual Studio 2019 retarget to 3.1 when mapping to an existing collection, we need ICollection, not IList --- appveyor.yml | 2 +- src/AutoMapper/AutoMapper.csproj | 2 +- .../Configuration/Internal/PrimitiveHelper.cs | 5 +- .../Configuration/MappingExpressionBase.cs | 6 +- .../MemberConfigurationExpression.cs | 3 +- .../Configuration/PrimitiveExtensions.cs | 3 - src/AutoMapper/DefaultMemberMap.cs | 1 + src/AutoMapper/Execution/DelegateFactory.cs | 8 +- src/AutoMapper/Execution/ProxyGenerator.cs | 4 +- .../Execution/TypeMapPlanBuilder.cs | 17 ++-- src/AutoMapper/IMemberMap.cs | 1 + src/AutoMapper/Internal/ExpressionFactory.cs | 4 +- src/AutoMapper/Internal/ReflectionHelper.cs | 6 +- src/AutoMapper/MapperConfiguration.cs | 2 +- src/AutoMapper/Mappers/ArrayCopyMapper.cs | 2 +- src/AutoMapper/Mappers/CollectionMapper.cs | 3 +- src/AutoMapper/Mappers/EnumerableMapper.cs | 9 +- .../CollectionMapperExpressionFactory.cs | 14 +-- .../Mappers/Internal/ElementTypeHelper.cs | 2 +- .../Mappers/ReadOnlyCollectionMapper.cs | 2 +- .../Mappers/ReadOnlyDictionaryMapper.cs | 2 +- src/AutoMapper/PathMap.cs | 2 +- src/AutoMapper/Profile.cs | 2 +- src/AutoMapper/ProfileMap.cs | 10 +-- src/AutoMapper/PropertyMap.cs | 11 +-- .../Impl/NullableSourceExpressionBinder.cs | 2 +- .../Impl/QueryMapperVisitor.cs | 4 +- src/AutoMapper/TypeDetails.cs | 58 +++++-------- src/AutoMapper/TypeExtensions.cs | 61 ++----------- src/AutoMapper/TypeMap.cs | 8 +- src/AutoMapper/TypePair.cs | 9 +- .../AutoMapper.IntegrationTests.csproj | 4 +- src/UnitTests/ArraysAndLists.cs | 86 ++++++++++++++++++- src/UnitTests/AutoMapper.UnitTests.csproj | 2 +- .../Bug/MapAtRuntime/MapAtRuntime.cs | 2 +- .../MapAtRuntimeWithCollections.cs | 2 +- src/UnitTests/CollectionMapping.cs | 18 ++++ .../Internal/PrimitiveExtensionsTester.cs | 24 ------ src/UnitTests/Mappers/CustomMapperTests.cs | 2 +- 39 files changed, 204 insertions(+), 201 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 257f2fa2a1..64a2c50981 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -4,7 +4,7 @@ pull_requests: branches: only: - master -image: Visual Studio 2017 +image: Visual Studio 2019 nuget: disable_publish_on_pr: true build_script: diff --git a/src/AutoMapper/AutoMapper.csproj b/src/AutoMapper/AutoMapper.csproj index f16b9a7347..b587e36414 100644 --- a/src/AutoMapper/AutoMapper.csproj +++ b/src/AutoMapper/AutoMapper.csproj @@ -35,7 +35,7 @@ - + diff --git a/src/AutoMapper/Configuration/Internal/PrimitiveHelper.cs b/src/AutoMapper/Configuration/Internal/PrimitiveHelper.cs index 021c908763..a54d87e56e 100644 --- a/src/AutoMapper/Configuration/Internal/PrimitiveHelper.cs +++ b/src/AutoMapper/Configuration/Internal/PrimitiveHelper.cs @@ -43,9 +43,6 @@ public static bool IsQueryableType(Type type) public static bool IsListType(Type type) => typeof(IList).IsAssignableFrom(type); - public static bool IsListOrDictionaryType(Type type) - => type.IsListType() || type.IsDictionaryType(); - public static bool IsDictionaryType(Type type) => type.ImplementsGenericInterface(typeof(IDictionary<,>)); @@ -59,7 +56,7 @@ public static bool ImplementsGenericInterface(Type type, Type interfaceType) } public static bool IsGenericType(Type type, Type genericType) - => type.IsGenericType() && type.GetGenericTypeDefinition() == genericType; + => type.IsGenericType && type.GetGenericTypeDefinition() == genericType; public static Type GetIEnumerableType(Type type) => type.GetGenericInterface(typeof(IEnumerable<>)); diff --git a/src/AutoMapper/Configuration/MappingExpressionBase.cs b/src/AutoMapper/Configuration/MappingExpressionBase.cs index 77ccc066d3..ec0dfb9bd1 100644 --- a/src/AutoMapper/Configuration/MappingExpressionBase.cs +++ b/src/AutoMapper/Configuration/MappingExpressionBase.cs @@ -21,7 +21,7 @@ protected MappingExpressionBase(MemberList memberList, Type sourceType, Type des protected MappingExpressionBase(MemberList memberList, TypePair types) { Types = types; - IsOpenGeneric = types.SourceType.IsGenericTypeDefinition() || types.DestinationType.IsGenericTypeDefinition(); + IsOpenGeneric = types.SourceType.IsGenericTypeDefinition || types.DestinationType.IsGenericTypeDefinition; TypeMapActions.Add(tm => tm.ConfiguredMemberList = memberList); } public TypePair Types { get; } @@ -59,7 +59,7 @@ public void Configure(TypeMap typeMap) } var destTypeInfo = typeMap.DestinationTypeDetails; - if(!typeMap.DestinationType.IsAbstract()) + if(!typeMap.DestinationType.IsAbstract) { foreach(var destCtor in destTypeInfo.Constructors.OrderByDescending(ci => ci.GetParameters().Length)) { @@ -176,7 +176,7 @@ protected void IncludeCore(Type otherSourceType, Type otherDestinationType) protected void CheckIsDerived(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}."); } diff --git a/src/AutoMapper/Configuration/MemberConfigurationExpression.cs b/src/AutoMapper/Configuration/MemberConfigurationExpression.cs index 3c19113b62..d1b5381bee 100644 --- a/src/AutoMapper/Configuration/MemberConfigurationExpression.cs +++ b/src/AutoMapper/Configuration/MemberConfigurationExpression.cs @@ -319,7 +319,7 @@ public void Configure(TypeMap typeMap) { var destMember = DestinationMember; - if(destMember.DeclaringType.IsGenericTypeDefinition()) + if(destMember.DeclaringType.IsGenericTypeDefinition) { destMember = typeMap.DestinationTypeDetails.PublicReadAccessors.Single(m => m.Name == destMember.Name); } @@ -335,7 +335,6 @@ private void Apply(PropertyMap propertyMap) { action(propertyMap); } - propertyMap.CheckMappedReadonly(); } public LambdaExpression SourceExpression => _sourceExpression; diff --git a/src/AutoMapper/Configuration/PrimitiveExtensions.cs b/src/AutoMapper/Configuration/PrimitiveExtensions.cs index 1cabbf8585..f345f1ba00 100644 --- a/src/AutoMapper/Configuration/PrimitiveExtensions.cs +++ b/src/AutoMapper/Configuration/PrimitiveExtensions.cs @@ -47,9 +47,6 @@ public static bool IsQueryableType(this Type type) public static bool IsListType(this Type type) => PrimitiveHelper.IsListType(type); - public static bool IsListOrDictionaryType(this Type type) - => PrimitiveHelper.IsListOrDictionaryType(type); - public static bool IsDictionaryType(this Type type) => PrimitiveHelper.IsDictionaryType(type); diff --git a/src/AutoMapper/DefaultMemberMap.cs b/src/AutoMapper/DefaultMemberMap.cs index fb0d1fbff1..9ebdaf9308 100644 --- a/src/AutoMapper/DefaultMemberMap.cs +++ b/src/AutoMapper/DefaultMemberMap.cs @@ -26,6 +26,7 @@ protected DefaultMemberMap() { } public virtual bool IsMapped => Ignored || CanResolveValue; public virtual bool Ignored { get => default; set { } } public virtual bool Inline { get => true; 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 { } } diff --git a/src/AutoMapper/Execution/DelegateFactory.cs b/src/AutoMapper/Execution/DelegateFactory.cs index 72c7681842..4bae9d6b1c 100644 --- a/src/AutoMapper/Execution/DelegateFactory.cs +++ b/src/AutoMapper/Execution/DelegateFactory.cs @@ -25,7 +25,7 @@ private static Func GenerateConstructor(Type type) return Lambda>(Convert(ctorExpr, typeof(object))).Compile(); } - public static Expression GenerateNonNullConstructorExpression(Type type) => type.IsValueType() + public static Expression GenerateNonNullConstructorExpression(Type type) => type.IsValueType ? Default(type) : (type == typeof(string) ? Constant(string.Empty) @@ -34,7 +34,7 @@ public static Expression GenerateNonNullConstructorExpression(Type type) => type public static Expression GenerateConstructorExpression(Type type) { - if (type.IsValueType()) + if (type.IsValueType) { return Default(type); } @@ -44,7 +44,7 @@ public static Expression GenerateConstructorExpression(Type type) return Constant(null, typeof(string)); } - if (type.IsInterface()) + if (type.IsInterface) { return type.IsDictionaryType() ? CreateCollection(type, typeof(Dictionary<,>)) @@ -54,7 +54,7 @@ public static Expression GenerateConstructorExpression(Type type) : InvalidType(type, $"Cannot create an instance of interface type {type}."); } - if (type.IsAbstract()) + if (type.IsAbstract) { return InvalidType(type, $"Cannot create an instance of abstract type {type}."); } diff --git a/src/AutoMapper/Execution/ProxyGenerator.cs b/src/AutoMapper/Execution/ProxyGenerator.cs index efa1d3113e..83315b6bea 100644 --- a/src/AutoMapper/Execution/ProxyGenerator.cs +++ b/src/AutoMapper/Execution/ProxyGenerator.cs @@ -55,7 +55,7 @@ private static Type EmitProxy(TypeDescription typeDescription) Debug.WriteLine(typeName, "Emitting proxy type"); TypeBuilder typeBuilder = proxyModule.DefineType(typeName, TypeAttributes.Class | TypeAttributes.Sealed | TypeAttributes.Public, typeof(ProxyBase), - interfaceType.IsInterface() ? new[] { interfaceType } : Type.EmptyTypes); + interfaceType.IsInterface ? new[] { interfaceType } : Type.EmptyTypes); ConstructorBuilder constructorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, Type.EmptyTypes); ILGenerator ctorIl = constructorBuilder.GetILGenerator(); @@ -140,7 +140,7 @@ private static Type EmitProxy(TypeDescription typeDescription) public static Type GetProxyType(Type interfaceType) { var key = new TypeDescription(interfaceType); - if(!interfaceType.IsInterface()) + if(!interfaceType.IsInterface) { throw new ArgumentException("Only interfaces can be proxied", nameof(interfaceType)); } diff --git a/src/AutoMapper/Execution/TypeMapPlanBuilder.cs b/src/AutoMapper/Execution/TypeMapPlanBuilder.cs index ce743101a8..5322d61d6d 100644 --- a/src/AutoMapper/Execution/TypeMapPlanBuilder.cs +++ b/src/AutoMapper/Execution/TypeMapPlanBuilder.cs @@ -9,7 +9,8 @@ namespace AutoMapper.Execution using static System.Linq.Expressions.Expression; using static Internal.ExpressionFactory; using static ExpressionBuilder; - using System.Diagnostics; + using System.Diagnostics; + using Internal; public class TypeMapPlanBuilder { @@ -96,7 +97,7 @@ private void CheckForCycles(HashSet typeMapsPath) } if(typeMapsPath.Contains(memberTypeMap)) { - if(memberTypeMap.SourceType.IsValueType()) + if(memberTypeMap.SourceType.IsValueType) { if(memberTypeMap.MaxDepth == 0) { @@ -149,9 +150,9 @@ private LambdaExpression TypeConverterMapper() if (_typeMap.TypeConverterType == null) return null; Type type; - if (_typeMap.TypeConverterType.IsGenericTypeDefinition()) + if (_typeMap.TypeConverterType.IsGenericTypeDefinition) { - var genericTypeParam = _typeMap.SourceType.IsGenericType() + var genericTypeParam = _typeMap.SourceType.IsGenericType ? _typeMap.SourceType.GetTypeInfo().GenericTypeArguments[0] : _typeMap.DestinationTypeToUse.GetTypeInfo().GenericTypeArguments[0]; type = _typeMap.TypeConverterType.MakeGenericType(genericTypeParam); @@ -176,7 +177,7 @@ private Expression CreateDestinationFunc() { var newDestFunc = ToType(CreateNewDestinationFunc(), _typeMap.DestinationTypeToUse); - var getDest = _typeMap.DestinationTypeToUse.IsValueType() ? newDestFunc : Coalesce(_initialDestination, newDestFunc); + var getDest = _typeMap.DestinationTypeToUse.IsValueType ? newDestFunc : Coalesce(_initialDestination, newDestFunc); Expression destinationFunc = Assign(_destination, getDest); @@ -312,7 +313,7 @@ private Expression CreateNewDestinationFunc() { return CreateNewDestinationExpression(_typeMap.ConstructorMap); } - if(_typeMap.DestinationTypeToUse.IsInterface()) + if(_typeMap.DestinationTypeToUse.IsInterface) { var ctor = Call(null, typeof(DelegateFactory).GetDeclaredMethod(nameof(DelegateFactory.CreateCtor), new[] { typeof(Type) }), @@ -399,13 +400,13 @@ private Expression CreatePropertyMapFunc(IMemberMap memberMap, Expression destin getter = destMember; Expression destValueExpr; - if (memberMap.UseDestinationValue.GetValueOrDefault()) + if (memberMap.UseDestinationValue == true || (memberMap.UseDestinationValue == null && !ReflectionHelper.CanBeSet(destinationMember))) { destValueExpr = getter; } else { - if (_initialDestination.Type.IsValueType()) + if (_initialDestination.Type.IsValueType) destValueExpr = Default(memberMap.DestinationType); else destValueExpr = Condition(Equal(_initialDestination, Constant(null)), diff --git a/src/AutoMapper/IMemberMap.cs b/src/AutoMapper/IMemberMap.cs index dbb01e9d13..02ed667cda 100644 --- a/src/AutoMapper/IMemberMap.cs +++ b/src/AutoMapper/IMemberMap.cs @@ -28,5 +28,6 @@ public interface IMemberMap IEnumerable ValueTransformers { get; } MemberInfo SourceMember { get; } bool IsMapped { get; } + bool CanBeSet { get; } } } \ No newline at end of file diff --git a/src/AutoMapper/Internal/ExpressionFactory.cs b/src/AutoMapper/Internal/ExpressionFactory.cs index 1b94c1b1dd..39390fbb7d 100644 --- a/src/AutoMapper/Internal/ExpressionFactory.cs +++ b/src/AutoMapper/Internal/ExpressionFactory.cs @@ -165,7 +165,7 @@ public static Expression NullCheck(Expression expression, Type destinationType) while (true); void NullCheck() { - if (target == null || target.Type.IsValueType()) + if (target == null || target.Type.IsValueType) { return; } @@ -198,7 +198,7 @@ public static Expression Using(Expression disposable, Expression body) public static Expression IfNullElse(Expression expression, Expression then, Expression @else = null) { var nonNullElse = ToType(@else ?? Default(then.Type), then.Type); - if(expression.Type.IsValueType() && !expression.Type.IsNullableType()) + if(expression.Type.IsValueType && !expression.Type.IsNullableType()) { return nonNullElse; } diff --git a/src/AutoMapper/Internal/ReflectionHelper.cs b/src/AutoMapper/Internal/ReflectionHelper.cs index e4b33986a5..231dba1ee6 100644 --- a/src/AutoMapper/Internal/ReflectionHelper.cs +++ b/src/AutoMapper/Internal/ReflectionHelper.cs @@ -21,7 +21,7 @@ public static bool CanBeSet(MemberInfo propertyOrField) public static object GetDefaultValue(ParameterInfo parameter) { - if (parameter.DefaultValue == null && parameter.ParameterType.IsValueType()) + if (parameter.DefaultValue == null && parameter.ParameterType.IsValueType) { return Activator.CreateInstance(parameter.ParameterType); } @@ -83,7 +83,7 @@ public static IEnumerable GetMemberPath(Type type, string fullMember private static Type GetCurrentType(MemberInfo member, Type type) { var memberType = member?.GetMemberType() ?? type; - if (memberType.IsGenericType() && typeof(IEnumerable).IsAssignableFrom(memberType)) + if (memberType.IsGenericType && typeof(IEnumerable).IsAssignableFrom(memberType)) { memberType = memberType.GetTypeInfo().GenericTypeArguments[0]; } @@ -169,7 +169,7 @@ public static Type ReplaceItemType(Type targetType, Type oldType, Type newType) if (targetType == oldType) return newType; - if (targetType.IsGenericType()) + if (targetType.IsGenericType) { var genSubArgs = targetType.GetTypeInfo().GenericTypeArguments; var newGenSubArgs = new Type[genSubArgs.Length]; diff --git a/src/AutoMapper/MapperConfiguration.cs b/src/AutoMapper/MapperConfiguration.cs index a1b408a25c..e13219b1be 100644 --- a/src/AutoMapper/MapperConfiguration.cs +++ b/src/AutoMapper/MapperConfiguration.cs @@ -465,7 +465,7 @@ private static Expression Wrap(MapRequest mapRequest, Delegat var requestedSourceType = mapRequest.RequestedTypes.SourceType; var requestedDestinationType = mapRequest.RequestedTypes.DestinationType; - var destination = requestedDestinationType.IsValueType() ? Coalesce(destinationParameter, New(requestedDestinationType)) : (Expression)destinationParameter; + var destination = requestedDestinationType.IsValueType ? Coalesce(destinationParameter, New(requestedDestinationType)) : (Expression)destinationParameter; // Invoking a delegate here return Lambda( ToType( diff --git a/src/AutoMapper/Mappers/ArrayCopyMapper.cs b/src/AutoMapper/Mappers/ArrayCopyMapper.cs index c383784b10..1eb57192ba 100644 --- a/src/AutoMapper/Mappers/ArrayCopyMapper.cs +++ b/src/AutoMapper/Mappers/ArrayCopyMapper.cs @@ -25,7 +25,7 @@ public override bool IsMatch(TypePair context) => context.DestinationType.IsArray && context.SourceType.IsArray && ElementTypeHelper.GetElementType(context.DestinationType) == ElementTypeHelper.GetElementType(context.SourceType) - && ElementTypeHelper.GetElementType(context.SourceType).IsPrimitive(); + && ElementTypeHelper.GetElementType(context.SourceType).IsPrimitive; public override Expression MapExpression(IConfigurationProvider configurationProvider, ProfileMap profileMap, IMemberMap memberMap, Expression sourceExpression, Expression destExpression, Expression contextExpression) diff --git a/src/AutoMapper/Mappers/CollectionMapper.cs b/src/AutoMapper/Mappers/CollectionMapper.cs index 327e939ec5..83d5e8c517 100644 --- a/src/AutoMapper/Mappers/CollectionMapper.cs +++ b/src/AutoMapper/Mappers/CollectionMapper.cs @@ -9,7 +9,8 @@ namespace AutoMapper.Mappers public class CollectionMapper : EnumerableMapperBase { - public override bool IsMatch(TypePair context) => context.SourceType.IsEnumerableType() && context.DestinationType.IsCollectionType(); + public override bool IsMatch(TypePair context) => context.SourceType.IsEnumerableType() && + (context.DestinationType.IsCollectionType() || context.DestinationType.IsListType()); public override Expression MapExpression(IConfigurationProvider configurationProvider, ProfileMap profileMap, IMemberMap memberMap, Expression sourceExpression, Expression destExpression, Expression contextExpression) diff --git a/src/AutoMapper/Mappers/EnumerableMapper.cs b/src/AutoMapper/Mappers/EnumerableMapper.cs index c9f724e771..b714cadd45 100644 --- a/src/AutoMapper/Mappers/EnumerableMapper.cs +++ b/src/AutoMapper/Mappers/EnumerableMapper.cs @@ -12,16 +12,15 @@ namespace AutoMapper.Mappers public class EnumerableMapper : EnumerableMapperBase { - public override bool IsMatch(TypePair context) => (context.DestinationType.IsInterface() && context.DestinationType.IsEnumerableType() || - context.DestinationType.IsListType()) - && context.SourceType.IsEnumerableType(); + public override bool IsMatch(TypePair context) => + context.SourceType.IsEnumerableType() && (context.DestinationType.IsInterface && context.DestinationType.IsEnumerableType()); public override Expression MapExpression(IConfigurationProvider configurationProvider, ProfileMap profileMap, IMemberMap memberMap, Expression sourceExpression, Expression destExpression, Expression contextExpression) { - if(destExpression.Type.IsInterface()) + if(destExpression.Type.IsInterface) { - var listType = typeof(IList<>).MakeGenericType(ElementTypeHelper.GetElementType(destExpression.Type)); + var listType = typeof(ICollection<>).MakeGenericType(ElementTypeHelper.GetElementType(destExpression.Type)); destExpression = Convert(destExpression, listType); } return MapCollectionExpression(configurationProvider, profileMap, memberMap, sourceExpression, diff --git a/src/AutoMapper/Mappers/Internal/CollectionMapperExpressionFactory.cs b/src/AutoMapper/Mappers/Internal/CollectionMapperExpressionFactory.cs index a75e477d9c..19d1c0c279 100644 --- a/src/AutoMapper/Mappers/Internal/CollectionMapperExpressionFactory.cs +++ b/src/AutoMapper/Mappers/Internal/CollectionMapperExpressionFactory.cs @@ -70,17 +70,21 @@ void UseDestinationValue() else { destination = newExpression; - Expression createInstance = passedDestination.Type.NewExpr(ifInterfaceType); - var isReadOnly = Property(ToType(passedDestination, destinationCollectionType), "IsReadOnly"); - assignNewExpression = Assign(newExpression, - Condition(OrElse(Equal(passedDestination, Constant(null)), isReadOnly), ToType(createInstance, passedDestination.Type), passedDestination)); + var createInstance = passedDestination.Type.NewExpr(ifInterfaceType); + var shouldCreateDestination = Equal(passedDestination, Constant(null)); + if (memberMap?.CanBeSet == true) + { + var isReadOnly = Property(ToType(passedDestination, destinationCollectionType), "IsReadOnly"); + shouldCreateDestination = OrElse(shouldCreateDestination, isReadOnly); + } + assignNewExpression = Assign(newExpression, Condition(shouldCreateDestination, ToType(createInstance, passedDestination.Type), passedDestination)); } } } private static Expression NewExpr(this Type baseType, Type ifInterfaceType) { - var newExpr = baseType.IsInterface() + var newExpr = baseType.IsInterface ? New( ifInterfaceType.MakeGenericType(GetElementTypes(baseType, ElementTypeFlags.BreakKeyValuePair))) diff --git a/src/AutoMapper/Mappers/Internal/ElementTypeHelper.cs b/src/AutoMapper/Mappers/Internal/ElementTypeHelper.cs index 1568242927..b19afd7890 100644 --- a/src/AutoMapper/Mappers/Internal/ElementTypeHelper.cs +++ b/src/AutoMapper/Mappers/Internal/ElementTypeHelper.cs @@ -55,7 +55,7 @@ public static Type[] GetElementTypes(Type enumerableType, IEnumerable enumerable public static Type GetEnumerationType(Type enumType) { - return !enumType.IsEnum() ? null : enumType; + return !enumType.IsEnum ? null : enumType; } internal static IEnumerable GetStaticMethods(this Type type) diff --git a/src/AutoMapper/Mappers/ReadOnlyCollectionMapper.cs b/src/AutoMapper/Mappers/ReadOnlyCollectionMapper.cs index 0cea444981..089050b96e 100644 --- a/src/AutoMapper/Mappers/ReadOnlyCollectionMapper.cs +++ b/src/AutoMapper/Mappers/ReadOnlyCollectionMapper.cs @@ -14,7 +14,7 @@ public class ReadOnlyCollectionMapper : IObjectMapper { public bool IsMatch(TypePair context) { - if (!(context.SourceType.IsEnumerableType() && context.DestinationType.IsGenericType())) + if (!(context.SourceType.IsEnumerableType() && context.DestinationType.IsGenericType)) return false; var genericType = context.DestinationType.GetGenericTypeDefinition(); diff --git a/src/AutoMapper/Mappers/ReadOnlyDictionaryMapper.cs b/src/AutoMapper/Mappers/ReadOnlyDictionaryMapper.cs index ac0bb92458..de9ee6a595 100644 --- a/src/AutoMapper/Mappers/ReadOnlyDictionaryMapper.cs +++ b/src/AutoMapper/Mappers/ReadOnlyDictionaryMapper.cs @@ -16,7 +16,7 @@ public class ReadOnlyDictionaryMapper : IObjectMapper { public bool IsMatch(TypePair context) { - if (!(context.SourceType.IsEnumerableType() && context.DestinationType.IsGenericType())) + if (!(context.SourceType.IsEnumerableType() && context.DestinationType.IsGenericType)) return false; var genericType = context.DestinationType.GetGenericTypeDefinition(); diff --git a/src/AutoMapper/PathMap.cs b/src/AutoMapper/PathMap.cs index f7aeb91318..ec836164e1 100644 --- a/src/AutoMapper/PathMap.cs +++ b/src/AutoMapper/PathMap.cs @@ -38,7 +38,7 @@ public PathMap(LambdaExpression destinationExpression, MemberPath memberPath, Ty public override string DestinationName => MemberPath.ToString(); public override bool CanResolveValue => !Ignored; - + public override bool CanBeSet => ReflectionHelper.CanBeSet(MemberPath.Last); public override bool Ignored { get; set; } public override LambdaExpression Condition { get; set; } } diff --git a/src/AutoMapper/Profile.cs b/src/AutoMapper/Profile.cs index d52987b76c..723ce5a19f 100644 --- a/src/AutoMapper/Profile.cs +++ b/src/AutoMapper/Profile.cs @@ -110,7 +110,7 @@ public IMappingExpression CreateMap(Type sourceType, Type destinationType, Membe _typeMapConfigs.Add(map); - if (sourceType.IsGenericTypeDefinition() || destinationType.IsGenericTypeDefinition()) + if (sourceType.IsGenericTypeDefinition || destinationType.IsGenericTypeDefinition) _openTypeMapConfigs.Add(map); return map; diff --git a/src/AutoMapper/ProfileMap.cs b/src/AutoMapper/ProfileMap.cs index ef60cacc78..516dac7be3 100644 --- a/src/AutoMapper/ProfileMap.cs +++ b/src/AutoMapper/ProfileMap.cs @@ -170,14 +170,14 @@ public TypeMap CreateClosedGenericTypeMap(ITypeMapConfiguration openMapConfig, T if(closedMap.TypeConverterType != null) { var typeParams = - (openMapConfig.SourceType.IsGenericTypeDefinition() ? closedTypes.SourceType.GetGenericArguments() : Type.EmptyTypes) + (openMapConfig.SourceType.IsGenericTypeDefinition ? closedTypes.SourceType.GetGenericArguments() : Type.EmptyTypes) .Concat - (openMapConfig.DestinationType.IsGenericTypeDefinition() ? closedTypes.DestinationType.GetGenericArguments() : Type.EmptyTypes); + (openMapConfig.DestinationType.IsGenericTypeDefinition ? closedTypes.DestinationType.GetGenericArguments() : Type.EmptyTypes); var neededParameters = closedMap.TypeConverterType.GetGenericParameters().Length; closedMap.TypeConverterType = closedMap.TypeConverterType.MakeGenericType(typeParams.Take(neededParameters).ToArray()); } - if(closedMap.DestinationTypeOverride?.IsGenericTypeDefinition() == true) + if(closedMap.DestinationTypeOverride?.IsGenericTypeDefinition == true) { var neededParameters = closedMap.DestinationTypeOverride.GetGenericParameters().Length; closedMap.DestinationTypeOverride = closedMap.DestinationTypeOverride.MakeGenericType(closedTypes.DestinationType.GetGenericArguments().Take(neededParameters).ToArray()); @@ -190,8 +190,8 @@ public ITypeMapConfiguration GetGenericMap(TypePair closedTypes) return _openTypeMapConfigs .SelectMany(tm => tm.ReverseTypeMap == null ? new[] { tm } : new[] { tm, tm.ReverseTypeMap }) .Where(tm => - tm.Types.SourceType.GetGenericTypeDefinitionIfGeneric() == closedTypes.SourceType.GetGenericTypeDefinitionIfGeneric() && - tm.Types.DestinationType.GetGenericTypeDefinitionIfGeneric() == closedTypes.DestinationType.GetGenericTypeDefinitionIfGeneric()) + tm.Types.SourceType.GetTypeDefinitionIfGeneric() == closedTypes.SourceType.GetTypeDefinitionIfGeneric() && + tm.Types.DestinationType.GetTypeDefinitionIfGeneric() == closedTypes.DestinationType.GetTypeDefinitionIfGeneric()) .OrderByDescending(tm => tm.DestinationType == closedTypes.DestinationType) // Favor more specific destination matches, .ThenByDescending(tm => tm.SourceType == closedTypes.SourceType) // then more specific source matches .FirstOrDefault(); diff --git a/src/AutoMapper/PropertyMap.cs b/src/AutoMapper/PropertyMap.cs index dbecd0d73b..3c9daa96e9 100644 --- a/src/AutoMapper/PropertyMap.cs +++ b/src/AutoMapper/PropertyMap.cs @@ -55,6 +55,7 @@ public static LambdaExpression CheckCustomSource(LambdaExpression lambda, Lambda public override IReadOnlyCollection SourceMembers => _memberChain; public override LambdaExpression CustomSource { get; set; } public override bool Inline { get; set; } = true; + public override bool CanBeSet => ReflectionHelper.CanBeSet(DestinationMember); public override bool Ignored { get; set; } public bool AllowNull { get; set; } public int? MappingOrder { get; set; } @@ -112,7 +113,7 @@ public void MapFrom(LambdaExpression sourceMember) public void MapFrom(string propertyOrField) { - var mapExpression = TypeMap.SourceType.IsGenericTypeDefinition() ? + var mapExpression = TypeMap.SourceType.IsGenericTypeDefinition ? // just a placeholder so the member is mapped Lambda(Constant(null)) : MemberAccessLambda(TypeMap.SourceType, propertyOrField); @@ -121,13 +122,5 @@ public void MapFrom(string propertyOrField) public void AddValueTransformation(ValueTransformerConfiguration valueTransformerConfiguration) => _valueTransformerConfigs.Add(valueTransformerConfiguration); - - internal void CheckMappedReadonly() - { - if(IsResolveConfigured && !ReflectionHelper.CanBeSet(DestinationMember)) - { - UseDestinationValue = true; - } - } } } \ No newline at end of file diff --git a/src/AutoMapper/QueryableExtensions/Impl/NullableSourceExpressionBinder.cs b/src/AutoMapper/QueryableExtensions/Impl/NullableSourceExpressionBinder.cs index 2e55de35e3..c4f9d27777 100644 --- a/src/AutoMapper/QueryableExtensions/Impl/NullableSourceExpressionBinder.cs +++ b/src/AutoMapper/QueryableExtensions/Impl/NullableSourceExpressionBinder.cs @@ -16,6 +16,6 @@ public MemberAssignment Build(IConfigurationProvider configuration, PropertyMap } public bool IsMatch(PropertyMap propertyMap, TypeMap propertyTypeMap, ExpressionResolutionResult result) => - result.Type.IsNullableType() && !propertyMap.DestinationType.IsNullableType() && propertyMap.DestinationType.IsValueType(); + result.Type.IsNullableType() && !propertyMap.DestinationType.IsNullableType() && propertyMap.DestinationType.IsValueType; } } \ No newline at end of file diff --git a/src/AutoMapper/QueryableExtensions/Impl/QueryMapperVisitor.cs b/src/AutoMapper/QueryableExtensions/Impl/QueryMapperVisitor.cs index e5b5d22e8e..f46ade8c71 100644 --- a/src/AutoMapper/QueryableExtensions/Impl/QueryMapperVisitor.cs +++ b/src/AutoMapper/QueryableExtensions/Impl/QueryMapperVisitor.cs @@ -120,7 +120,7 @@ private Expression VisitOrderBy(MethodCallExpression node) // for typical orderby expression, a unaryexpression is used that contains a // func which in turn defines the type of the field that has to be used for ordering/sorting - if (newOrderByExpr is UnaryExpression unary && unary.Operand.Type.IsGenericType()) + if (newOrderByExpr is UnaryExpression unary && unary.Operand.Type.IsGenericType) { methodArgs[1] = methodArgs[1].ReplaceItemType(typeof(string), unary.Operand.Type.GetGenericArguments().Last()); } @@ -148,7 +148,7 @@ private MethodInfo ChangeMethodArgTypeFormSourceToDest(MethodInfo mi) private Type ChangeLambdaArgTypeFormSourceToDest(Type lambdaType, Type returnType) { - if (lambdaType.IsGenericType()) + if (lambdaType.IsGenericType) { var genArgs = lambdaType.GetTypeInfo().GenericTypeArguments; var newGenArgs = genArgs.Select(t => t.ReplaceItemType(_sourceType, _destinationType)).ToArray(); diff --git a/src/AutoMapper/TypeDetails.cs b/src/AutoMapper/TypeDetails.cs index 6019b8b0c5..f24f01c3cd 100644 --- a/src/AutoMapper/TypeDetails.cs +++ b/src/AutoMapper/TypeDetails.cs @@ -52,12 +52,10 @@ private IEnumerable PossibleNames(string memberName, IEnumerable yield return s; } - private static IEnumerable PostFixes(IEnumerable postfixes, string name) - { - return - postfixes.Where(postfix => name.EndsWith(postfix, StringComparison.OrdinalIgnoreCase)) - .Select(postfix => name.Remove(name.Length - postfix.Length)); - } + private static IEnumerable PostFixes(IEnumerable postfixes, string name) => + postfixes + .Where(postfix => name.EndsWith(postfix, StringComparison.OrdinalIgnoreCase)) + .Select(postfix => name.Remove(name.Length - postfix.Length)); private static Func MembersToMap( Func shouldMapProperty, @@ -103,9 +101,9 @@ private IEnumerable BuildPublicNoArgExtensionMethods(IEnumerable method.GetParameters()[0].ParameterType == Type); - var genericInterfaces = Type.GetTypeInfo().ImplementedInterfaces.Where(t => t.IsGenericType()); + var genericInterfaces = Type.GetTypeInfo().ImplementedInterfaces.Where(t => t.IsGenericType); - if (Type.IsInterface() && Type.IsGenericType()) + if (Type.IsInterface && Type.IsGenericType) { genericInterfaces = genericInterfaces.Union(new[] { Type }); } @@ -113,7 +111,7 @@ private IEnumerable BuildPublicNoArgExtensionMethods(IEnumerable allMembers) - { + private static MemberInfo[] BuildPublicReadAccessors(IEnumerable allMembers) => // Multiple types may define the same property (e.g. the class and multiple interfaces) - filter this to one of those properties - var filteredMembers = allMembers + allMembers .OfType() .GroupBy(x => x.Name) // group properties of the same name together .Select(x => x.First()) - .Concat(allMembers.Where(x => x is FieldInfo)); // add FieldInfo objects back - - return filteredMembers.ToArray(); - } + .Concat(allMembers.Where(x => x is FieldInfo)) // add FieldInfo objects back + .ToArray(); - private static MemberInfo[] BuildPublicAccessors(IEnumerable allMembers) - { + private static MemberInfo[] BuildPublicAccessors(IEnumerable allMembers) => // Multiple types may define the same property (e.g. the class and multiple interfaces) - filter this to one of those properties - var filteredMembers = allMembers + allMembers .OfType() .GroupBy(x => x.Name) // group properties of the same name together - .Select(x => - x.Any(y => y.CanWrite && y.CanRead) - ? // favor the first property that can both read & write - otherwise pick the first one - x.First(y => y.CanWrite && y.CanRead) - : x.First()) - .Where(pi => pi.CanWrite || pi.PropertyType.IsListOrDictionaryType()) - //.OfType() // cast back to MemberInfo so we can add back FieldInfo objects - .Concat(allMembers.Where(x => x is FieldInfo)); // add FieldInfo objects back - - return filteredMembers.ToArray(); - } + .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 + .Concat(allMembers.Where(x => x is FieldInfo)) // add FieldInfo objects back + .ToArray(); private IEnumerable GetAllPublicReadableMembers(Func membersToMap) => GetAllPublicMembers(PropertyReadable, FieldReadable, membersToMap); @@ -167,9 +153,7 @@ private IEnumerable GetAllPublicWritableMembers(Func GetAllPublicMembers(PropertyWritable, FieldWritable, membersToMap); private IEnumerable GetAllConstructors(Func shouldUseConstructor) - { - return Type.GetDeclaredConstructors().Where(shouldUseConstructor).ToArray(); - } + => Type.GetDeclaredConstructors().Where(shouldUseConstructor).ToArray(); private static bool PropertyReadable(PropertyInfo propertyInfo) => propertyInfo.CanRead; @@ -185,10 +169,10 @@ private IEnumerable GetAllPublicMembers( Func memberAvailableFor) { var typesToScan = new List(); - for (var t = Type; t != null; t = t.BaseType()) + for (var t = Type; t != null; t = t.BaseType) typesToScan.Add(t); - if (Type.IsInterface()) + if (Type.IsInterface) typesToScan.AddRange(Type.GetTypeInfo().ImplementedInterfaces); // Scan all types for public properties and fields @@ -214,4 +198,4 @@ private MethodInfo[] BuildPublicNoArgMethods(Func shouldMapMet .ToArray(); } } -} +} \ No newline at end of file diff --git a/src/AutoMapper/TypeExtensions.cs b/src/AutoMapper/TypeExtensions.cs index d7caeb1180..464ebff699 100644 --- a/src/AutoMapper/TypeExtensions.cs +++ b/src/AutoMapper/TypeExtensions.cs @@ -6,19 +6,16 @@ namespace AutoMapper { - internal static class TypeExtensions { public static bool Has(this MemberInfo member) where TAttribute : Attribute => member.GetCustomAttribute() != null; - public static Type GetGenericTypeDefinitionIfGeneric(this Type type) => type.IsGenericType() ? type.GetGenericTypeDefinition() : type; + public static Type GetTypeDefinitionIfGeneric(this Type type) => type.IsGenericType ? type.GetGenericTypeDefinition() : type; - public static Type[] GetGenericArguments(this Type type) => type.GetTypeInfo().GenericTypeArguments; + public static IEnumerable GetDeclaredConstructors(this Type type) => type.GetTypeInfo().DeclaredConstructors; public static Type[] GetGenericParameters(this Type type) => type.GetGenericTypeDefinition().GetTypeInfo().GenericTypeParameters; - public static IEnumerable GetDeclaredConstructors(this Type type) => type.GetTypeInfo().DeclaredConstructors; - public static Type CreateType(this TypeBuilder type) => type.CreateTypeInfo().AsType(); public static IEnumerable GetDeclaredMembers(this Type type) => type.GetTypeInfo().DeclaredMembers; @@ -27,11 +24,11 @@ public static IEnumerable GetTypeInheritance(this Type type) { yield return type; - var baseType = type.BaseType(); + var baseType = type.BaseType; while(baseType != null) { yield return baseType; - baseType = baseType.BaseType(); + baseType = baseType.BaseType; } } @@ -50,14 +47,9 @@ private static TMethod MatchParameters(this IEnumerable method public static IEnumerable GetAllMethods(this Type type) => type.GetRuntimeMethods(); - public static IEnumerable GetDeclaredProperties(this Type type) => type.GetTypeInfo().DeclaredProperties; - public static PropertyInfo GetDeclaredProperty(this Type type, string name) => type.GetTypeInfo().GetDeclaredProperty(name); - public static object[] GetCustomAttributes(this Type type, Type attributeType, bool inherit) - => type.GetTypeInfo().GetCustomAttributes(attributeType, inherit).Cast().ToArray(); - public static bool IsStatic(this FieldInfo fieldInfo) => fieldInfo?.IsStatic ?? false; public static bool IsStatic(this PropertyInfo propertyInfo) => propertyInfo?.GetGetMethod(true)?.IsStatic @@ -85,49 +77,6 @@ public static bool HasAnInaccessibleSetter(this PropertyInfo property) public static bool IsPublic(this MemberInfo memberInfo) => (memberInfo as FieldInfo)?.IsPublic ?? (memberInfo as PropertyInfo).IsPublic(); - public static bool IsNotPublic(this ConstructorInfo constructorInfo) => constructorInfo.IsPrivate - || constructorInfo.IsFamilyAndAssembly - || constructorInfo.IsFamilyOrAssembly - || constructorInfo.IsFamily; - public static Assembly Assembly(this Type type) => type.GetTypeInfo().Assembly; - - public static Type BaseType(this Type type) => type.GetTypeInfo().BaseType; - - public static bool IsAssignableFrom(this Type type, Type other) => type.GetTypeInfo().IsAssignableFrom(other.GetTypeInfo()); - - public static bool IsAbstract(this Type type) => type.GetTypeInfo().IsAbstract; - - public static bool IsClass(this Type type) => type.GetTypeInfo().IsClass; - - public static bool IsEnum(this Type type) => type.GetTypeInfo().IsEnum; - - public static bool IsGenericType(this Type type) => type.GetTypeInfo().IsGenericType; - - public static bool IsGenericTypeDefinition(this Type type) => type.GetTypeInfo().IsGenericTypeDefinition; - - public static bool IsInterface(this Type type) => type.GetTypeInfo().IsInterface; - - public static bool IsPrimitive(this Type type) => type.GetTypeInfo().IsPrimitive; - - public static bool IsSealed(this Type type) => type.GetTypeInfo().IsSealed; - - public static bool IsValueType(this Type type) => type.GetTypeInfo().IsValueType; - - public static bool IsLiteralType(this Type type) => type == typeof(string) || type.GetTypeInfo().IsValueType; - - public static bool IsInstanceOfType(this Type type, object o) => o != null && type.GetTypeInfo().IsAssignableFrom(o.GetType().GetTypeInfo()); - - public static PropertyInfo[] GetProperties(this Type type) => type.GetRuntimeProperties().ToArray(); - - public static MethodInfo GetGetMethod(this PropertyInfo propertyInfo, bool ignored) => propertyInfo.GetMethod; - - public static MethodInfo GetSetMethod(this PropertyInfo propertyInfo, bool ignored) => propertyInfo.SetMethod; - - public static MethodInfo GetGetMethod(this PropertyInfo propertyInfo) => propertyInfo.GetMethod; - - public static MethodInfo GetSetMethod(this PropertyInfo propertyInfo) => propertyInfo.SetMethod; - - public static FieldInfo GetField(this Type type, string name) => type.GetRuntimeField(name); } -} +} \ No newline at end of file diff --git a/src/AutoMapper/TypeMap.cs b/src/AutoMapper/TypeMap.cs index beef92d2f7..9a6c30f186 100644 --- a/src/AutoMapper/TypeMap.cs +++ b/src/AutoMapper/TypeMap.cs @@ -116,10 +116,10 @@ public PathMap FindPathMapByDestinationPath(string destinationFullPath) => || CustomCtorFunction != null || ConstructDestinationUsingServiceLocator || ConstructorMap?.CanResolve == true - || DestinationTypeToUse.IsInterface() - || DestinationTypeToUse.IsAbstract() - || DestinationTypeToUse.IsGenericTypeDefinition() - || DestinationTypeToUse.IsValueType() + || DestinationTypeToUse.IsInterface + || DestinationTypeToUse.IsAbstract + || DestinationTypeToUse.IsGenericTypeDefinition + || DestinationTypeToUse.IsValueType || DestinationTypeDetails.Constructors.FirstOrDefault(c => c.GetParameters().All(p => p.IsOptional)) != null; public bool IsConstructorMapping => diff --git a/src/AutoMapper/TypePair.cs b/src/AutoMapper/TypePair.cs index 8199e01aba..94a837d1f6 100644 --- a/src/AutoMapper/TypePair.cs +++ b/src/AutoMapper/TypePair.cs @@ -98,9 +98,8 @@ public static TypePair Create(TSource source, TDestinatio { return null; } - var sourceGenericDefinition = SourceType.IsGenericType() ? SourceType.GetGenericTypeDefinition() : SourceType; - var destinationGenericDefinition = DestinationType.IsGenericType() ? DestinationType.GetGenericTypeDefinition() : DestinationType; - + var sourceGenericDefinition = SourceType.GetTypeDefinitionIfGeneric(); + var destinationGenericDefinition = DestinationType.GetTypeDefinitionIfGeneric(); return new TypePair(sourceGenericDefinition, destinationGenericDefinition); } @@ -116,8 +115,8 @@ public TypePair CloseGenericTypes(TypePair closedTypes) { destinationArguments = sourceArguments; } - var closedSourceType = SourceType.IsGenericTypeDefinition() ? SourceType.MakeGenericType(sourceArguments) : SourceType; - var closedDestinationType = DestinationType.IsGenericTypeDefinition() ? DestinationType.MakeGenericType(destinationArguments) : DestinationType; + var closedSourceType = SourceType.IsGenericTypeDefinition ? SourceType.MakeGenericType(sourceArguments) : SourceType; + var closedDestinationType = DestinationType.IsGenericTypeDefinition ? DestinationType.MakeGenericType(destinationArguments) : DestinationType; return new TypePair(closedSourceType, closedDestinationType); } diff --git a/src/IntegrationTests/AutoMapper.IntegrationTests.csproj b/src/IntegrationTests/AutoMapper.IntegrationTests.csproj index 4849858bf5..67446ea78b 100644 --- a/src/IntegrationTests/AutoMapper.IntegrationTests.csproj +++ b/src/IntegrationTests/AutoMapper.IntegrationTests.csproj @@ -1,7 +1,7 @@  - net461 + net461;netcoreapp3.1 AutoMapper.IntegrationTests AutoMapper.IntegrationTests true @@ -17,7 +17,7 @@ - + all runtime; build; native; contentfiles; analyzers diff --git a/src/UnitTests/ArraysAndLists.cs b/src/UnitTests/ArraysAndLists.cs index 7f66d335fc..ebc61fdeaa 100644 --- a/src/UnitTests/ArraysAndLists.cs +++ b/src/UnitTests/ArraysAndLists.cs @@ -274,6 +274,38 @@ 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 Source + { + public int[] IntCollection { get; set; } = new int[0]; + } + + public class Destination + { + public IEnumerable IntCollection { get; set; } = new HashSet { 1, 2, 3, 4, 5 }; + public string Unmapped { get; } + } + + protected override MapperConfiguration Configuration { get; } = new MapperConfiguration(cfg => + { + cfg.CreateMap(); + }); + + protected override void Because_of() + { + _destination = Mapper.Map(new Source(), _destination); + } + + [Fact] + public void Should_clear_the_destination() + { + _destination.IntCollection.Count().ShouldBe(0); + } } public class When_mapping_to_an_existing_array_typed_as_IEnumerable : AutoMapperSpecBase @@ -399,7 +431,59 @@ public void Should_map_from_the_generic_list_of_values_with_formatting() _destination.Values2.ShouldContain("7"); _destination.Values2.ShouldContain("6"); } - } + } + + public class When_mapping_to_a_getter_only_ienumerable : AutoMapperSpecBase + { + 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 Configuration { get; } = new MapperConfiguration(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 + { + 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 Configuration { get; } = new MapperConfiguration(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 { diff --git a/src/UnitTests/AutoMapper.UnitTests.csproj b/src/UnitTests/AutoMapper.UnitTests.csproj index 2e7fe215ff..24a2d4cf98 100644 --- a/src/UnitTests/AutoMapper.UnitTests.csproj +++ b/src/UnitTests/AutoMapper.UnitTests.csproj @@ -1,7 +1,7 @@  - net461;netcoreapp2.0; + net461;netcoreapp3.1; AutoMapper.UnitTests AutoMapper.UnitTests $(NoWarn);649;618 diff --git a/src/UnitTests/Bug/MapAtRuntime/MapAtRuntime.cs b/src/UnitTests/Bug/MapAtRuntime/MapAtRuntime.cs index 416897a150..4a657d0355 100644 --- a/src/UnitTests/Bug/MapAtRuntime/MapAtRuntime.cs +++ b/src/UnitTests/Bug/MapAtRuntime/MapAtRuntime.cs @@ -36,7 +36,7 @@ public class MapAtRuntime : AutoMapperSpecBase cfg.CreateMap().ReverseMap(); cfg.CreateMap().ReverseMap(); cfg.CreateMap().ReverseMap(); - //cfg.ForAllPropertyMaps(p => !p.SourceType.IsValueType(), (pm, o) => o.MapAtRuntime()); + //cfg.ForAllPropertyMaps(p => !p.SourceType.IsValueType, (pm, o) => o.MapAtRuntime()); }); public class Initialize diff --git a/src/UnitTests/Bug/MapAtRuntimeWithCollections/MapAtRuntimeWithCollections.cs b/src/UnitTests/Bug/MapAtRuntimeWithCollections/MapAtRuntimeWithCollections.cs index 55049c3b2f..8a32774af1 100644 --- a/src/UnitTests/Bug/MapAtRuntimeWithCollections/MapAtRuntimeWithCollections.cs +++ b/src/UnitTests/Bug/MapAtRuntimeWithCollections/MapAtRuntimeWithCollections.cs @@ -37,7 +37,7 @@ public class MapAtRuntimeWithCollections : AutoMapperSpecBase cfg.CreateMap().ReverseMap(); cfg.CreateMap().ReverseMap(); cfg.CreateMap().ReverseMap(); - //cfg.ForAllPropertyMaps(p => !p.SourceType.IsValueType(), (pm, o) => o.MapAtRuntime()); + //cfg.ForAllPropertyMaps(p => !p.SourceType.IsValueType, (pm, o) => o.MapAtRuntime()); }); public class Initialize diff --git a/src/UnitTests/CollectionMapping.cs b/src/UnitTests/CollectionMapping.cs index 5103a9cd92..c5016fc921 100644 --- a/src/UnitTests/CollectionMapping.cs +++ b/src/UnitTests/CollectionMapping.cs @@ -396,6 +396,24 @@ public void Should_map_ok() } } + 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 Configuration => new MapperConfiguration(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."); + } + public class When_mapping_to_readonly_property_UseDestinationValue : AutoMapperSpecBase { public class Source diff --git a/src/UnitTests/Internal/PrimitiveExtensionsTester.cs b/src/UnitTests/Internal/PrimitiveExtensionsTester.cs index 21eabbe09c..fd4c1b1e4a 100644 --- a/src/UnitTests/Internal/PrimitiveExtensionsTester.cs +++ b/src/UnitTests/Internal/PrimitiveExtensionsTester.cs @@ -29,29 +29,5 @@ public void Should_find_explicitly_implemented_member() { PrimitiveHelper.GetFieldOrProperty(typeof(DestinationClass), "Value").ShouldNotBeNull(); } - - [Fact] - public void Should_not_flag_only_enumerable_type_as_writeable_collection() - { - PrimitiveHelper.IsListOrDictionaryType(typeof(string)).ShouldBeFalse(); - } - - [Fact] - public void Should_flag_list_as_writable_collection() - { - PrimitiveHelper.IsListOrDictionaryType(typeof(int[])).ShouldBeTrue(); - } - - [Fact] - public void Should_flag_generic_list_as_writeable_collection() - { - PrimitiveHelper.IsListOrDictionaryType(typeof(List)).ShouldBeTrue(); - } - - [Fact] - public void Should_flag_dictionary_as_writeable_collection() - { - PrimitiveHelper.IsListOrDictionaryType(typeof(Dictionary)).ShouldBeTrue(); - } } } \ No newline at end of file diff --git a/src/UnitTests/Mappers/CustomMapperTests.cs b/src/UnitTests/Mappers/CustomMapperTests.cs index 3ed859ff93..313c441cbb 100644 --- a/src/UnitTests/Mappers/CustomMapperTests.cs +++ b/src/UnitTests/Mappers/CustomMapperTests.cs @@ -150,7 +150,7 @@ class EnumMapper : ObjectMapper public override bool IsMatch(TypePair types) { var underlyingType = Nullable.GetUnderlyingType(types.SourceType) ?? types.SourceType; - return underlyingType.IsEnum() && types.DestinationType == typeof(string); + return underlyingType.IsEnum && types.DestinationType == typeof(string); } public override string Map(object source, string destination, Type sourceType, Type destinationType, ResolutionContext context) From 0b9ad86dba3d429643d2f6fc98f2603e1905fe88 Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Wed, 15 Apr 2020 07:09:54 +0300 Subject: [PATCH 2/3] fail sooner --- src/AutoMapper/ApiCompatBaseline.txt | 31 +++++++++++++++++++ .../CtorParamConfigurationExpression.cs | 13 ++++++-- .../Configuration/MappingExpressionBase.cs | 2 +- 3 files changed, 43 insertions(+), 3 deletions(-) diff --git a/src/AutoMapper/ApiCompatBaseline.txt b/src/AutoMapper/ApiCompatBaseline.txt index bcbf4a6ea3..4f430a5f9c 100644 --- a/src/AutoMapper/ApiCompatBaseline.txt +++ b/src/AutoMapper/ApiCompatBaseline.txt @@ -23,8 +23,15 @@ InterfacesShouldHaveSameMembers : Interface member 'AutoMapper.IRuntimeMapper.Ma InterfacesShouldHaveSameMembers : Interface member 'AutoMapper.IRuntimeMapper.Map(TSource, System.Action>)' is present in the implementation but not in the contract. InterfacesShouldHaveSameMembers : Interface member 'AutoMapper.IRuntimeMapper.Map(TSource, TDestination, System.Action>)' is present in the implementation but not in the contract. CannotChangeAttribute : Attribute 'System.Runtime.CompilerServices.IteratorStateMachineAttribute' on 'AutoMapper.MapperConfiguration.GetIncludedTypeMaps(System.Collections.Generic.IEnumerable)' changed from '[IteratorStateMachineAttribute(typeof(MapperConfiguration.d__69))]' in the contract to '[IteratorStateMachineAttribute(typeof(MapperConfiguration.d__72))]' in the implementation. +<<<<<<< HEAD TypesMustExist : Type 'AutoMapper.MemberFinderVisitor' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'AutoMapper.PropertyMap.UseDestinationValue.set(System.Boolean)' does not exist in the implementation but it does exist in the contract. +======= +MembersMustExist : Member 'public System.Collections.Generic.IEnumerable AutoMapper.PropertyMap.SourceMembers.get()' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public System.Boolean AutoMapper.PropertyMap.UseDestinationValue.get()' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public void AutoMapper.PropertyMap.UseDestinationValue.set(System.Boolean)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public void AutoMapper.Configuration.CtorParamConfigurationExpression..ctor(System.String)' does not exist in the implementation but it does exist in the contract. +>>>>>>> fail sooner 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. @@ -34,6 +41,7 @@ CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'AutoMappe 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. CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'AutoMapper.Configuration.Conventions.MapToAttribute' changed from '[AttributeUsageAttribute(384)]' in the contract to '[AttributeUsageAttribute(AttributeTargets.Field | AttributeTargets.Property)]' in the implementation. +<<<<<<< HEAD MembersMustExist : Member 'AutoMapper.Execution.DelegateFactory.GenerateConstructorExpression(System.Type, AutoMapper.ProfileMap)' does not exist in the implementation but it does exist in the contract. InterfacesShouldHaveSameMembers : Interface member 'AutoMapper.QueryableExtensions.IExpressionResultConverter.CanGetExpressionResolutionResult(AutoMapper.QueryableExtensions.ExpressionResolutionResult, AutoMapper.ConstructorParameterMap)' is present in the contract but not in the implementation. MembersMustExist : Member 'AutoMapper.QueryableExtensions.IExpressionResultConverter.CanGetExpressionResolutionResult(AutoMapper.QueryableExtensions.ExpressionResolutionResult, AutoMapper.ConstructorParameterMap)' does not exist in the implementation but it does exist in the contract. @@ -54,3 +62,26 @@ MembersMustExist : Member 'AutoMapper.QueryableExtensions.Impl.MemberResolverExp MembersMustExist : Member 'AutoMapper.QueryableExtensions.Impl.MemberResolverExpressionResultConverter.GetExpressionResolutionResult(AutoMapper.QueryableExtensions.ExpressionResolutionResult, AutoMapper.ConstructorParameterMap)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'AutoMapper.QueryableExtensions.Impl.MemberResolverExpressionResultConverter.GetExpressionResolutionResult(AutoMapper.QueryableExtensions.ExpressionResolutionResult, AutoMapper.PropertyMap, AutoMapper.QueryableExtensions.LetPropertyMaps)' does not exist in the implementation but it does exist in the contract. Total Issues: 54 +======= +MembersMustExist : Member 'public System.Boolean AutoMapper.Configuration.Internal.PrimitiveHelper.IsListOrDictionaryType(System.Type)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public System.Linq.Expressions.Expression AutoMapper.Execution.DelegateFactory.GenerateConstructorExpression(System.Type, AutoMapper.ProfileMap)' does not exist in the implementation but it does exist in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public System.Boolean AutoMapper.QueryableExtensions.IExpressionResultConverter.CanGetExpressionResolutionResult(AutoMapper.QueryableExtensions.ExpressionResolutionResult, AutoMapper.ConstructorParameterMap)' is present in the contract but not in the implementation. +MembersMustExist : Member 'public System.Boolean AutoMapper.QueryableExtensions.IExpressionResultConverter.CanGetExpressionResolutionResult(AutoMapper.QueryableExtensions.ExpressionResolutionResult, AutoMapper.ConstructorParameterMap)' does not exist in the implementation but it does exist in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public System.Boolean AutoMapper.QueryableExtensions.IExpressionResultConverter.CanGetExpressionResolutionResult(AutoMapper.QueryableExtensions.ExpressionResolutionResult, AutoMapper.IMemberMap)' is present in the implementation but not in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public System.Boolean AutoMapper.QueryableExtensions.IExpressionResultConverter.CanGetExpressionResolutionResult(AutoMapper.QueryableExtensions.ExpressionResolutionResult, AutoMapper.PropertyMap)' is present in the contract but not in the implementation. +MembersMustExist : Member 'public System.Boolean AutoMapper.QueryableExtensions.IExpressionResultConverter.CanGetExpressionResolutionResult(AutoMapper.QueryableExtensions.ExpressionResolutionResult, AutoMapper.PropertyMap)' does not exist in the implementation but it does exist in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public AutoMapper.QueryableExtensions.ExpressionResolutionResult AutoMapper.QueryableExtensions.IExpressionResultConverter.GetExpressionResolutionResult(AutoMapper.QueryableExtensions.ExpressionResolutionResult, AutoMapper.ConstructorParameterMap)' is present in the contract but not in the implementation. +MembersMustExist : Member 'public AutoMapper.QueryableExtensions.ExpressionResolutionResult AutoMapper.QueryableExtensions.IExpressionResultConverter.GetExpressionResolutionResult(AutoMapper.QueryableExtensions.ExpressionResolutionResult, AutoMapper.ConstructorParameterMap)' does not exist in the implementation but it does exist in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public AutoMapper.QueryableExtensions.ExpressionResolutionResult AutoMapper.QueryableExtensions.IExpressionResultConverter.GetExpressionResolutionResult(AutoMapper.QueryableExtensions.ExpressionResolutionResult, AutoMapper.IMemberMap, AutoMapper.QueryableExtensions.LetPropertyMaps)' is present in the implementation but not in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public AutoMapper.QueryableExtensions.ExpressionResolutionResult AutoMapper.QueryableExtensions.IExpressionResultConverter.GetExpressionResolutionResult(AutoMapper.QueryableExtensions.ExpressionResolutionResult, AutoMapper.PropertyMap, AutoMapper.QueryableExtensions.LetPropertyMaps)' is present in the contract but not in the implementation. +MembersMustExist : Member 'public AutoMapper.QueryableExtensions.ExpressionResolutionResult AutoMapper.QueryableExtensions.IExpressionResultConverter.GetExpressionResolutionResult(AutoMapper.QueryableExtensions.ExpressionResolutionResult, AutoMapper.PropertyMap, AutoMapper.QueryableExtensions.LetPropertyMaps)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public System.Boolean AutoMapper.QueryableExtensions.Impl.MemberGetterExpressionResultConverter.CanGetExpressionResolutionResult(AutoMapper.QueryableExtensions.ExpressionResolutionResult, AutoMapper.ConstructorParameterMap)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public System.Boolean AutoMapper.QueryableExtensions.Impl.MemberGetterExpressionResultConverter.CanGetExpressionResolutionResult(AutoMapper.QueryableExtensions.ExpressionResolutionResult, AutoMapper.PropertyMap)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public AutoMapper.QueryableExtensions.ExpressionResolutionResult AutoMapper.QueryableExtensions.Impl.MemberGetterExpressionResultConverter.GetExpressionResolutionResult(AutoMapper.QueryableExtensions.ExpressionResolutionResult, AutoMapper.ConstructorParameterMap)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public AutoMapper.QueryableExtensions.ExpressionResolutionResult AutoMapper.QueryableExtensions.Impl.MemberGetterExpressionResultConverter.GetExpressionResolutionResult(AutoMapper.QueryableExtensions.ExpressionResolutionResult, AutoMapper.PropertyMap, AutoMapper.QueryableExtensions.LetPropertyMaps)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public System.Boolean AutoMapper.QueryableExtensions.Impl.MemberResolverExpressionResultConverter.CanGetExpressionResolutionResult(AutoMapper.QueryableExtensions.ExpressionResolutionResult, AutoMapper.ConstructorParameterMap)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public System.Boolean AutoMapper.QueryableExtensions.Impl.MemberResolverExpressionResultConverter.CanGetExpressionResolutionResult(AutoMapper.QueryableExtensions.ExpressionResolutionResult, AutoMapper.PropertyMap)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public AutoMapper.QueryableExtensions.ExpressionResolutionResult AutoMapper.QueryableExtensions.Impl.MemberResolverExpressionResultConverter.GetExpressionResolutionResult(AutoMapper.QueryableExtensions.ExpressionResolutionResult, AutoMapper.ConstructorParameterMap)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public AutoMapper.QueryableExtensions.ExpressionResolutionResult AutoMapper.QueryableExtensions.Impl.MemberResolverExpressionResultConverter.GetExpressionResolutionResult(AutoMapper.QueryableExtensions.ExpressionResolutionResult, AutoMapper.PropertyMap, AutoMapper.QueryableExtensions.LetPropertyMaps)' does not exist in the implementation but it does exist in the contract. +Total Issues: 60 +>>>>>>> fail sooner diff --git a/src/AutoMapper/Configuration/CtorParamConfigurationExpression.cs b/src/AutoMapper/Configuration/CtorParamConfigurationExpression.cs index 66940ca3bc..b979e50d26 100644 --- a/src/AutoMapper/Configuration/CtorParamConfigurationExpression.cs +++ b/src/AutoMapper/Configuration/CtorParamConfigurationExpression.cs @@ -8,9 +8,15 @@ namespace AutoMapper.Configuration public class CtorParamConfigurationExpression : ICtorParamConfigurationExpression, ICtorParameterConfiguration { public string CtorParamName { get; } + public Type SourceType { get; } + private readonly List> _ctorParamActions = new List>(); - public CtorParamConfigurationExpression(string ctorParamName) => CtorParamName = ctorParamName; + public CtorParamConfigurationExpression(string ctorParamName, Type sourceType) + { + CtorParamName = ctorParamName; + SourceType = sourceType; + } public void MapFrom(Expression> sourceMember) => _ctorParamActions.Add(cpm => cpm.CustomMapExpression = sourceMember); @@ -21,8 +27,11 @@ public void MapFrom(Func resolver) _ctorParamActions.Add(cpm => cpm.CustomMapFunction = resolverExpression); } - public void MapFrom(string sourceMemberName) => + public void MapFrom(string sourceMemberName) + { + SourceType.GetFieldOrProperty(sourceMemberName); _ctorParamActions.Add(cpm => cpm.SourceMemberName = sourceMemberName); + } public void Configure(TypeMap typeMap) { diff --git a/src/AutoMapper/Configuration/MappingExpressionBase.cs b/src/AutoMapper/Configuration/MappingExpressionBase.cs index ec0dfb9bd1..b58f37f31b 100644 --- a/src/AutoMapper/Configuration/MappingExpressionBase.cs +++ b/src/AutoMapper/Configuration/MappingExpressionBase.cs @@ -414,7 +414,7 @@ public void ConvertUsing() where TTypeConverter : ITypeConverter public TMappingExpression ForCtorParam(string ctorParamName, Action> paramOptions) { - var ctorParamExpression = new CtorParamConfigurationExpression(ctorParamName); + var ctorParamExpression = new CtorParamConfigurationExpression(ctorParamName, SourceType); paramOptions(ctorParamExpression); From 585658c903d842f9c3fa207dc53191b5335b07de Mon Sep 17 00:00:00 2001 From: Lucian Bargaoanu Date: Wed, 29 Apr 2020 15:30:43 +0300 Subject: [PATCH 3/3] rebase --- src/AutoMapper/ApiCompatBaseline.txt | 70 +++++++++------------------- 1 file changed, 23 insertions(+), 47 deletions(-) diff --git a/src/AutoMapper/ApiCompatBaseline.txt b/src/AutoMapper/ApiCompatBaseline.txt index 4f430a5f9c..fc7283ce78 100644 --- a/src/AutoMapper/ApiCompatBaseline.txt +++ b/src/AutoMapper/ApiCompatBaseline.txt @@ -1,37 +1,36 @@ 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 'AutoMapper.ConstructorMap.NewExpression(System.Linq.Expressions.Expression)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'AutoMapper.DefaultMemberMap.SourceMembers.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'AutoMapper.DefaultMemberMap.UseDestinationValue.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'AutoMapper.DefaultMemberMap.UseDestinationValue.set(System.Boolean)' does not exist in the implementation but it does exist in the contract. -InterfacesShouldHaveSameMembers : Interface member 'AutoMapper.IConfigurationProvider.RecursiveQueriesMaxDepth' is present in the implementation but not in the contract. -InterfacesShouldHaveSameMembers : Interface member 'AutoMapper.IConfigurationProvider.RecursiveQueriesMaxDepth.get()' is present in the implementation but not in the contract. +MembersMustExist : Member 'public System.Linq.Expressions.Expression AutoMapper.ConstructorMap.NewExpression(System.Linq.Expressions.Expression)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public System.Collections.Generic.IEnumerable AutoMapper.ConstructorParameterMap.SourceMembers.get()' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public System.Collections.Generic.IEnumerable AutoMapper.DefaultMemberMap.SourceMembers.get()' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public System.Boolean AutoMapper.DefaultMemberMap.UseDestinationValue.get()' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public void AutoMapper.DefaultMemberMap.UseDestinationValue.set(System.Boolean)' does not exist in the implementation but it does exist in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public System.Int32 AutoMapper.IConfigurationProvider.RecursiveQueriesMaxDepth' is present in the implementation but not in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public System.Int32 AutoMapper.IConfigurationProvider.RecursiveQueriesMaxDepth.get()' is present in the implementation but not in the contract. CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'AutoMapper.IgnoreMapAttribute' changed from '[AttributeUsageAttribute(384)]' in the contract to '[AttributeUsageAttribute(AttributeTargets.Field | AttributeTargets.Property)]' in the implementation. -InterfacesShouldHaveSameMembers : Interface member 'AutoMapper.IMapper.ProjectTo(System.Linq.IQueryable, System.Type, System.Collections.Generic.IDictionary, System.String[])' is present in the implementation but not in the contract. -InterfacesShouldHaveSameMembers : Interface member 'AutoMapper.IMemberConfigurationExpression.DontUseDestinationValue()' is present in the implementation but not in the contract. -InterfacesShouldHaveSameMembers : Interface member 'AutoMapper.IMemberMap.SourceMembers.get()' is present in the implementation but not in the contract. -InterfacesShouldHaveSameMembers : Interface member 'AutoMapper.IMemberMap.SourceMembers.get()' is present in the contract but not in the implementation. -MembersMustExist : Member 'AutoMapper.IMemberMap.SourceMembers.get()' does not exist in the implementation but it does exist in the contract. -InterfacesShouldHaveSameMembers : Interface member 'AutoMapper.IMemberMap.UseDestinationValue.get()' is present in the implementation but not in the contract. -InterfacesShouldHaveSameMembers : Interface member 'AutoMapper.IMemberMap.UseDestinationValue.get()' is present in the contract but not in the implementation. -MembersMustExist : Member 'AutoMapper.IMemberMap.UseDestinationValue.get()' does not exist in the implementation but it does exist in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public System.Linq.IQueryable AutoMapper.IMapper.ProjectTo(System.Linq.IQueryable, System.Type, System.Collections.Generic.IDictionary, System.String[])' is present in the implementation but not in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public void AutoMapper.IMemberConfigurationExpression.DontUseDestinationValue()' is present in the implementation but not in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public System.Boolean AutoMapper.IMemberMap.CanBeSet' is present in the implementation but not in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public System.Boolean AutoMapper.IMemberMap.CanBeSet.get()' is present in the implementation but not in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public System.Collections.Generic.IReadOnlyCollection AutoMapper.IMemberMap.SourceMembers.get()' is present in the implementation but not in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public System.Collections.Generic.IEnumerable AutoMapper.IMemberMap.SourceMembers.get()' is present in the contract but not in the implementation. +MembersMustExist : Member 'public System.Collections.Generic.IEnumerable AutoMapper.IMemberMap.SourceMembers.get()' does not exist in the implementation but it does exist in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public System.Nullable AutoMapper.IMemberMap.UseDestinationValue.get()' is present in the implementation but not in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public System.Boolean AutoMapper.IMemberMap.UseDestinationValue.get()' is present in the contract but not in the implementation. +MembersMustExist : Member 'public System.Boolean AutoMapper.IMemberMap.UseDestinationValue.get()' does not exist in the implementation but it does exist in the contract. CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.IsReadOnlyAttribute' exists on 'AutoMapper.IncludedMember.MemberExpression.get()' in the contract but not the implementation. CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.IsReadOnlyAttribute' exists on 'AutoMapper.IncludedMember.TypeMap.get()' in the contract but not the implementation. -InterfacesShouldHaveSameMembers : Interface member 'AutoMapper.IRuntimeMapper.Map(System.Object, System.Object, System.Type, System.Type, System.Action)' is present in the implementation but not in the contract. -InterfacesShouldHaveSameMembers : Interface member 'AutoMapper.IRuntimeMapper.Map(System.Object, System.Type, System.Type, System.Action)' is present in the implementation but not in the contract. -InterfacesShouldHaveSameMembers : Interface member 'AutoMapper.IRuntimeMapper.Map(System.Object, System.Action)' is present in the implementation but not in the contract. -InterfacesShouldHaveSameMembers : Interface member 'AutoMapper.IRuntimeMapper.Map(TSource, System.Action>)' is present in the implementation but not in the contract. -InterfacesShouldHaveSameMembers : Interface member 'AutoMapper.IRuntimeMapper.Map(TSource, TDestination, System.Action>)' is present in the implementation but not in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public System.Object AutoMapper.IRuntimeMapper.Map(System.Object, System.Object, System.Type, System.Type, System.Action)' is present in the implementation but not in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public System.Object AutoMapper.IRuntimeMapper.Map(System.Object, System.Type, System.Type, System.Action)' is present in the implementation but not in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public TDestination AutoMapper.IRuntimeMapper.Map(System.Object, System.Action)' is present in the implementation but not in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public TDestination AutoMapper.IRuntimeMapper.Map(TSource, System.Action>)' is present in the implementation but not in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public TDestination AutoMapper.IRuntimeMapper.Map(TSource, TDestination, System.Action>)' is present in the implementation but not in the contract. CannotChangeAttribute : Attribute 'System.Runtime.CompilerServices.IteratorStateMachineAttribute' on 'AutoMapper.MapperConfiguration.GetIncludedTypeMaps(System.Collections.Generic.IEnumerable)' changed from '[IteratorStateMachineAttribute(typeof(MapperConfiguration.d__69))]' in the contract to '[IteratorStateMachineAttribute(typeof(MapperConfiguration.d__72))]' in the implementation. -<<<<<<< HEAD TypesMustExist : Type 'AutoMapper.MemberFinderVisitor' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'AutoMapper.PropertyMap.UseDestinationValue.set(System.Boolean)' does not exist in the implementation but it does exist in the contract. -======= MembersMustExist : Member 'public System.Collections.Generic.IEnumerable AutoMapper.PropertyMap.SourceMembers.get()' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Boolean AutoMapper.PropertyMap.UseDestinationValue.get()' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public void AutoMapper.PropertyMap.UseDestinationValue.set(System.Boolean)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public void AutoMapper.Configuration.CtorParamConfigurationExpression..ctor(System.String)' does not exist in the implementation but it does exist in the contract. ->>>>>>> fail sooner 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. @@ -41,28 +40,6 @@ CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'AutoMappe 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. CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'AutoMapper.Configuration.Conventions.MapToAttribute' changed from '[AttributeUsageAttribute(384)]' in the contract to '[AttributeUsageAttribute(AttributeTargets.Field | AttributeTargets.Property)]' in the implementation. -<<<<<<< HEAD -MembersMustExist : Member 'AutoMapper.Execution.DelegateFactory.GenerateConstructorExpression(System.Type, AutoMapper.ProfileMap)' does not exist in the implementation but it does exist in the contract. -InterfacesShouldHaveSameMembers : Interface member 'AutoMapper.QueryableExtensions.IExpressionResultConverter.CanGetExpressionResolutionResult(AutoMapper.QueryableExtensions.ExpressionResolutionResult, AutoMapper.ConstructorParameterMap)' is present in the contract but not in the implementation. -MembersMustExist : Member 'AutoMapper.QueryableExtensions.IExpressionResultConverter.CanGetExpressionResolutionResult(AutoMapper.QueryableExtensions.ExpressionResolutionResult, AutoMapper.ConstructorParameterMap)' does not exist in the implementation but it does exist in the contract. -InterfacesShouldHaveSameMembers : Interface member 'AutoMapper.QueryableExtensions.IExpressionResultConverter.CanGetExpressionResolutionResult(AutoMapper.QueryableExtensions.ExpressionResolutionResult, AutoMapper.IMemberMap)' is present in the implementation but not in the contract. -InterfacesShouldHaveSameMembers : Interface member 'AutoMapper.QueryableExtensions.IExpressionResultConverter.CanGetExpressionResolutionResult(AutoMapper.QueryableExtensions.ExpressionResolutionResult, AutoMapper.PropertyMap)' is present in the contract but not in the implementation. -MembersMustExist : Member 'AutoMapper.QueryableExtensions.IExpressionResultConverter.CanGetExpressionResolutionResult(AutoMapper.QueryableExtensions.ExpressionResolutionResult, AutoMapper.PropertyMap)' does not exist in the implementation but it does exist in the contract. -InterfacesShouldHaveSameMembers : Interface member 'AutoMapper.QueryableExtensions.IExpressionResultConverter.GetExpressionResolutionResult(AutoMapper.QueryableExtensions.ExpressionResolutionResult, AutoMapper.ConstructorParameterMap)' is present in the contract but not in the implementation. -MembersMustExist : Member 'AutoMapper.QueryableExtensions.IExpressionResultConverter.GetExpressionResolutionResult(AutoMapper.QueryableExtensions.ExpressionResolutionResult, AutoMapper.ConstructorParameterMap)' does not exist in the implementation but it does exist in the contract. -InterfacesShouldHaveSameMembers : Interface member 'AutoMapper.QueryableExtensions.IExpressionResultConverter.GetExpressionResolutionResult(AutoMapper.QueryableExtensions.ExpressionResolutionResult, AutoMapper.IMemberMap, AutoMapper.QueryableExtensions.LetPropertyMaps)' is present in the implementation but not in the contract. -InterfacesShouldHaveSameMembers : Interface member 'AutoMapper.QueryableExtensions.IExpressionResultConverter.GetExpressionResolutionResult(AutoMapper.QueryableExtensions.ExpressionResolutionResult, AutoMapper.PropertyMap, AutoMapper.QueryableExtensions.LetPropertyMaps)' is present in the contract but not in the implementation. -MembersMustExist : Member 'AutoMapper.QueryableExtensions.IExpressionResultConverter.GetExpressionResolutionResult(AutoMapper.QueryableExtensions.ExpressionResolutionResult, AutoMapper.PropertyMap, AutoMapper.QueryableExtensions.LetPropertyMaps)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'AutoMapper.QueryableExtensions.Impl.MemberGetterExpressionResultConverter.CanGetExpressionResolutionResult(AutoMapper.QueryableExtensions.ExpressionResolutionResult, AutoMapper.ConstructorParameterMap)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'AutoMapper.QueryableExtensions.Impl.MemberGetterExpressionResultConverter.CanGetExpressionResolutionResult(AutoMapper.QueryableExtensions.ExpressionResolutionResult, AutoMapper.PropertyMap)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'AutoMapper.QueryableExtensions.Impl.MemberGetterExpressionResultConverter.GetExpressionResolutionResult(AutoMapper.QueryableExtensions.ExpressionResolutionResult, AutoMapper.ConstructorParameterMap)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'AutoMapper.QueryableExtensions.Impl.MemberGetterExpressionResultConverter.GetExpressionResolutionResult(AutoMapper.QueryableExtensions.ExpressionResolutionResult, AutoMapper.PropertyMap, AutoMapper.QueryableExtensions.LetPropertyMaps)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'AutoMapper.QueryableExtensions.Impl.MemberResolverExpressionResultConverter.CanGetExpressionResolutionResult(AutoMapper.QueryableExtensions.ExpressionResolutionResult, AutoMapper.ConstructorParameterMap)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'AutoMapper.QueryableExtensions.Impl.MemberResolverExpressionResultConverter.CanGetExpressionResolutionResult(AutoMapper.QueryableExtensions.ExpressionResolutionResult, AutoMapper.PropertyMap)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'AutoMapper.QueryableExtensions.Impl.MemberResolverExpressionResultConverter.GetExpressionResolutionResult(AutoMapper.QueryableExtensions.ExpressionResolutionResult, AutoMapper.ConstructorParameterMap)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'AutoMapper.QueryableExtensions.Impl.MemberResolverExpressionResultConverter.GetExpressionResolutionResult(AutoMapper.QueryableExtensions.ExpressionResolutionResult, AutoMapper.PropertyMap, AutoMapper.QueryableExtensions.LetPropertyMaps)' does not exist in the implementation but it does exist in the contract. -Total Issues: 54 -======= MembersMustExist : Member 'public System.Boolean AutoMapper.Configuration.Internal.PrimitiveHelper.IsListOrDictionaryType(System.Type)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Linq.Expressions.Expression AutoMapper.Execution.DelegateFactory.GenerateConstructorExpression(System.Type, AutoMapper.ProfileMap)' does not exist in the implementation but it does exist in the contract. InterfacesShouldHaveSameMembers : Interface member 'public System.Boolean AutoMapper.QueryableExtensions.IExpressionResultConverter.CanGetExpressionResolutionResult(AutoMapper.QueryableExtensions.ExpressionResolutionResult, AutoMapper.ConstructorParameterMap)' is present in the contract but not in the implementation. @@ -83,5 +60,4 @@ MembersMustExist : Member 'public System.Boolean AutoMapper.QueryableExtensions. MembersMustExist : Member 'public System.Boolean AutoMapper.QueryableExtensions.Impl.MemberResolverExpressionResultConverter.CanGetExpressionResolutionResult(AutoMapper.QueryableExtensions.ExpressionResolutionResult, AutoMapper.PropertyMap)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public AutoMapper.QueryableExtensions.ExpressionResolutionResult AutoMapper.QueryableExtensions.Impl.MemberResolverExpressionResultConverter.GetExpressionResolutionResult(AutoMapper.QueryableExtensions.ExpressionResolutionResult, AutoMapper.ConstructorParameterMap)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public AutoMapper.QueryableExtensions.ExpressionResolutionResult AutoMapper.QueryableExtensions.Impl.MemberResolverExpressionResultConverter.GetExpressionResolutionResult(AutoMapper.QueryableExtensions.ExpressionResolutionResult, AutoMapper.PropertyMap, AutoMapper.QueryableExtensions.LetPropertyMaps)' does not exist in the implementation but it does exist in the contract. -Total Issues: 60 ->>>>>>> fail sooner +Total Issues: 61