diff --git a/docs/source/13.0-Upgrade-Guide.md b/docs/source/13.0-Upgrade-Guide.md index 6c13bd5439..4cb8a67b31 100644 --- a/docs/source/13.0-Upgrade-Guide.md +++ b/docs/source/13.0-Upgrade-Guide.md @@ -6,10 +6,6 @@ ## `AddAutoMapper` is part of the core package and the DI package is discontinued -## `IMapper` has nullable annotations - -Besides the build-time impact, there is also a behaviour change. Non-generic `Map` overloads require now either a destination type or a non-null destination object. - ## `AllowAdditiveTypeMapCreation` was removed Be sure to call `CreateMap` once for a source type, destination type pair. If you want to reuse configuration, use mapping inheritance. @@ -24,4 +20,4 @@ The same pattern the framework uses to pass state to delegates. Note that `State ## Custom Equals/GetHashCode for source objects -To avoid broken implementations, we no longer call those when checking for identical source objects, we hard code to checking object references. \ No newline at end of file +To avoid broken implementations, we no longer call those when checking for identical source objects, we hard code to checking object references. diff --git a/src/AutoMapper/ApiCompatBaseline.txt b/src/AutoMapper/ApiCompatBaseline.txt index 4c9243b942..c75e43358e 100644 --- a/src/AutoMapper/ApiCompatBaseline.txt +++ b/src/AutoMapper/ApiCompatBaseline.txt @@ -1,29 +1,29 @@ 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. -InterfacesShouldHaveSameMembers : Interface member 'public System.Object AutoMapper.IMappingOperationOptions.State' is present in the implementation but not in the contract. -InterfacesShouldHaveSameMembers : Interface member 'public System.Object AutoMapper.IMappingOperationOptions.State.get()' is present in the implementation but not in the contract. -InterfacesShouldHaveSameMembers : Interface member 'public void AutoMapper.IMappingOperationOptions.State.set(System.Object)' is present in the implementation but not in the contract. -InterfacesShouldHaveSameMembers : Interface member 'public System.Collections.Generic.IReadOnlyCollection AutoMapper.IProfileConfiguration.AllPropertyMapActions.get()' is present in the implementation but not in the contract. -InterfacesShouldHaveSameMembers : Interface member 'public System.Collections.Generic.IReadOnlyCollection> AutoMapper.IProfileConfiguration.AllPropertyMapActions.get()' is present in the contract but not in the implementation. -MembersMustExist : Member 'public System.Collections.Generic.IReadOnlyCollection> AutoMapper.IProfileConfiguration.AllPropertyMapActions.get()' does not exist in the implementation but it does exist in the contract. -InterfacesShouldHaveSameMembers : Interface member 'public void AutoMapper.IProjectionMemberConfiguration.ExplicitExpansion()' is present in the contract but not in the implementation. -MembersMustExist : Member 'public void AutoMapper.IProjectionMemberConfiguration.ExplicitExpansion()' does not exist in the implementation but it does exist in the contract. -InterfacesShouldHaveSameMembers : Interface member 'public void AutoMapper.IProjectionMemberConfiguration.ExplicitExpansion(System.Boolean)' is present in the implementation but not in the contract. -CannotSealType : Type 'AutoMapper.Mapper' is actually (has the sealed modifier) sealed in the implementation but not sealed in the contract. -CannotSealType : Type 'AutoMapper.MapperConfiguration' is actually (has the sealed modifier) sealed in the implementation but not sealed in the contract. -CannotSealType : Type 'AutoMapper.MapperConfigurationExpression' is actually (has the sealed modifier) sealed in the implementation but not sealed in the contract. -CannotSealType : Type 'AutoMapper.MappingOperationOptions' is actually (has the sealed modifier) sealed in the implementation but not sealed in the contract. -MembersMustExist : Member 'protected void AutoMapper.MappingOperationOptions.AfterMapAction.set(System.Action)' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'protected void AutoMapper.MappingOperationOptions.BeforeMapAction.set(System.Action)' does not exist in the implementation but it does exist in the contract. -InterfacesShouldHaveSameMembers : Interface member 'public void AutoMapper.Configuration.ICtorParamConfigurationExpression.ExplicitExpansion(System.Boolean)' is present in the implementation but not in the contract. -CannotSealType : Type 'AutoMapper.Configuration.MappingExpression' is actually (has the sealed modifier) sealed in the implementation but not sealed in the contract. -CannotMakeMemberNonVirtual : Member 'protected void AutoMapper.Configuration.MappingExpression.IgnoreDestinationMember(System.Reflection.MemberInfo, System.Boolean)' is non-virtual in the implementation but is virtual in the contract. -CannotSealType : Type 'AutoMapper.Configuration.MemberConfigurationExpression' is actually (has the sealed modifier) sealed in the implementation but not sealed in the contract. -MembersMustExist : Member 'public void AutoMapper.Configuration.MemberConfigurationExpression.ExplicitExpansion()' does not exist in the implementation but it does exist in the contract. -CannotSealType : Type 'AutoMapper.Configuration.PathConfigurationExpression' is actually (has the sealed modifier) sealed in the implementation but not sealed in the contract. -MembersMustExist : Member 'protected System.Collections.Generic.List> AutoMapper.Configuration.PathConfigurationExpression.PathMapActions.get()' does not exist in the implementation but it does exist in the contract. -CannotSealType : Type 'AutoMapper.Configuration.SourceMappingExpression' is actually (has the sealed modifier) sealed in the implementation but not sealed in the contract. -CannotSealType : Type 'AutoMapper.Configuration.SourceMemberConfig' is actually (has the sealed modifier) sealed in the implementation but not sealed in the contract. +CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.NullableContextAttribute' exists on 'AutoMapper.IMapper' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.NullableContextAttribute' exists on 'AutoMapper.IMapper.Map(System.Object, System.Object, System.Type, System.Type, System.Action>)' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.NullableAttribute' exists on parameter 'opts' on member 'AutoMapper.IMapper.Map(System.Object, System.Object, System.Type, System.Type, System.Action>)' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.NullableContextAttribute' exists on 'AutoMapper.IMapper.Map(System.Object, System.Type, System.Type, System.Action>)' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.NullableAttribute' exists on parameter 'destinationType' on member 'AutoMapper.IMapper.Map(System.Object, System.Type, System.Type, System.Action>)' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.NullableAttribute' exists on parameter 'opts' on member 'AutoMapper.IMapper.Map(System.Object, System.Type, System.Type, System.Action>)' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.NullableContextAttribute' exists on 'AutoMapper.IMapper.Map(System.Object, System.Action>)' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.NullableAttribute' exists on parameter 'opts' on member 'AutoMapper.IMapper.Map(System.Object, System.Action>)' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.NullableContextAttribute' exists on 'AutoMapper.IMapper.Map(TSource, System.Action>)' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.NullableAttribute' exists on parameter 'opts' on member 'AutoMapper.IMapper.Map(TSource, System.Action>)' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.NullableContextAttribute' exists on 'AutoMapper.IMapper.Map(TSource, TDestination, System.Action>)' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.NullableAttribute' exists on parameter 'opts' on member 'AutoMapper.IMapper.Map(TSource, TDestination, System.Action>)' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.NullableAttribute' exists on parameter 'parameters' on member 'AutoMapper.IMapper.ProjectTo(System.Linq.IQueryable, System.Type, System.Collections.Generic.IDictionary, System.String[])' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.NullableAttribute' exists on parameter 'parameters' on member 'AutoMapper.IMapper.ProjectTo(System.Linq.IQueryable, System.Collections.Generic.IDictionary, System.String[])' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.NullableAttribute' exists on generic param 'TDestination' on member 'AutoMapper.IMapper.ProjectTo(System.Linq.IQueryable, System.Collections.Generic.IDictionary, System.String[])' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.NullableAttribute' exists on parameter 'parameters' on member 'AutoMapper.IMapper.ProjectTo(System.Linq.IQueryable, System.Object, System.Linq.Expressions.Expression>[])' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.NullableAttribute' exists on generic param 'TDestination' on member 'AutoMapper.IMapper.ProjectTo(System.Linq.IQueryable, System.Object, System.Linq.Expressions.Expression>[])' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.NullableContextAttribute' exists on 'AutoMapper.IMapperBase' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.NullableAttribute' exists on parameter 'destinationType' on member 'AutoMapper.IMapperBase.Map(System.Object, System.Type, System.Type)' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.NullableAttribute' exists on generic param 'TDestination' on member 'AutoMapper.ResolutionContext.AutoMapper.IMapperBase.Map(System.Object)' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.NullableAttribute' exists on generic param 'TSource' on member 'AutoMapper.ResolutionContext.AutoMapper.IMapperBase.Map(TSource)' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.NullableAttribute' exists on generic param 'TDestination' on member 'AutoMapper.ResolutionContext.AutoMapper.IMapperBase.Map(TSource)' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.NullableAttribute' exists on generic param 'TSource' on member 'AutoMapper.ResolutionContext.AutoMapper.IMapperBase.Map(TSource, TDestination)' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.NullableAttribute' exists on generic param 'TDestination' on member 'AutoMapper.ResolutionContext.AutoMapper.IMapperBase.Map(TSource, TDestination)' in the contract but not the implementation. 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. @@ -32,10 +32,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. -CannotSealType : Type 'AutoMapper.Configuration.Conventions.PrePostfixName' is actually (has the sealed modifier) sealed in the implementation but not sealed in the contract. -CannotSealType : Type 'AutoMapper.Configuration.Conventions.ReplaceName' is actually (has the sealed modifier) sealed in the implementation but not sealed in the contract. -TypeCannotChangeClassification : Type 'AutoMapper.Execution.TypeMapPlanBuilder' is a 'ref struct' in the implementation but is a 'struct' in the contract. -CannotSealType : Type 'AutoMapper.QueryableExtensions.MemberVisitor' is actually (has the sealed modifier) sealed in the implementation but not sealed in the contract. -CannotMakeMemberNonVirtual : Member 'protected System.Linq.Expressions.Expression AutoMapper.QueryableExtensions.MemberVisitor.VisitMember(System.Linq.Expressions.MemberExpression)' is non-virtual in the implementation but is virtual in the contract. -CannotSealType : Type 'AutoMapper.QueryableExtensions.Impl.MemberProjection' is actually (has the sealed modifier) sealed in the implementation but not sealed in the contract. -Total Issues: 39 +CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.NullableContextAttribute' exists on 'AutoMapper.QueryableExtensions.Extensions.ProjectTo(System.Linq.IQueryable, System.Type, AutoMapper.IConfigurationProvider)' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.NullableContextAttribute' exists on 'AutoMapper.QueryableExtensions.Extensions.ProjectTo(System.Linq.IQueryable, System.Type, AutoMapper.IConfigurationProvider, System.Collections.Generic.IDictionary, System.String[])' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.NullableAttribute' exists on parameter 'parameters' on member 'AutoMapper.QueryableExtensions.Extensions.ProjectTo(System.Linq.IQueryable, System.Type, AutoMapper.IConfigurationProvider, System.Collections.Generic.IDictionary, System.String[])' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.NullableContextAttribute' exists on 'AutoMapper.QueryableExtensions.Extensions.ProjectTo(System.Linq.IQueryable, AutoMapper.IConfigurationProvider, System.Collections.Generic.IDictionary, System.String[])' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.NullableAttribute' exists on parameter 'parameters' on member 'AutoMapper.QueryableExtensions.Extensions.ProjectTo(System.Linq.IQueryable, AutoMapper.IConfigurationProvider, System.Collections.Generic.IDictionary, System.String[])' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.NullableAttribute' exists on generic param 'TDestination' on member 'AutoMapper.QueryableExtensions.Extensions.ProjectTo(System.Linq.IQueryable, AutoMapper.IConfigurationProvider, System.Collections.Generic.IDictionary, System.String[])' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.NullableContextAttribute' exists on 'AutoMapper.QueryableExtensions.Extensions.ProjectTo(System.Linq.IQueryable, AutoMapper.IConfigurationProvider, System.Linq.Expressions.Expression>[])' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.NullableAttribute' exists on generic param 'TDestination' on member 'AutoMapper.QueryableExtensions.Extensions.ProjectTo(System.Linq.IQueryable, AutoMapper.IConfigurationProvider, System.Linq.Expressions.Expression>[])' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.NullableContextAttribute' exists on 'AutoMapper.QueryableExtensions.Extensions.ProjectTo(System.Linq.IQueryable, AutoMapper.IConfigurationProvider, System.Object, System.Linq.Expressions.Expression>[])' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.NullableAttribute' exists on parameter 'parameters' on member 'AutoMapper.QueryableExtensions.Extensions.ProjectTo(System.Linq.IQueryable, AutoMapper.IConfigurationProvider, System.Object, System.Linq.Expressions.Expression>[])' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.NullableAttribute' exists on generic param 'TDestination' on member 'AutoMapper.QueryableExtensions.Extensions.ProjectTo(System.Linq.IQueryable, AutoMapper.IConfigurationProvider, System.Object, System.Linq.Expressions.Expression>[])' in the contract but not the implementation. +Total Issues: 44 diff --git a/src/AutoMapper/Configuration/MapperConfigurationExpression.cs b/src/AutoMapper/Configuration/MapperConfigurationExpression.cs index e4998d49da..6c7ad6f177 100644 --- a/src/AutoMapper/Configuration/MapperConfigurationExpression.cs +++ b/src/AutoMapper/Configuration/MapperConfigurationExpression.cs @@ -177,7 +177,7 @@ private void AddMapsCore(IEnumerable assembliesToScan) { foreach (var memberConfigurationProvider in memberInfo.GetCustomAttributes().OfType()) { - mappingExpression.ForMember(memberInfo, cfg => memberConfigurationProvider.ApplyConfiguration(cfg)); + mappingExpression.ForMember(memberInfo, memberConfigurationProvider.ApplyConfiguration); } } @@ -188,5 +188,5 @@ private void AddMapsCore(IEnumerable assembliesToScan) AddProfile(autoMapAttributeProfile); } - public void ConstructServicesUsing(Func constructor) => _serviceCtor = constructor; + public void ConstructServicesUsing(Func constructor) => _serviceCtor = constructor ?? throw new ArgumentNullException(nameof(constructor)); } \ No newline at end of file diff --git a/src/AutoMapper/Mapper.cs b/src/AutoMapper/Mapper.cs index 2e3c42f997..fe823da7a0 100644 --- a/src/AutoMapper/Mapper.cs +++ b/src/AutoMapper/Mapper.cs @@ -44,7 +44,7 @@ public interface IMapperBase /// Destination object to map into /// Source type to use /// Destination type to use - /// Mapped destination object + /// The mapped destination object object Map(object source, object destination, Type sourceType, Type destinationType); } public interface IMapper : IMapperBase @@ -93,7 +93,7 @@ public interface IMapper : IMapperBase /// Source type to use /// Destination type to use /// Mapping options - /// Mapped destination object + /// The mapped destination object object Map(object source, object destination, Type sourceType, Type destinationType, Action opts); /// /// Configuration provider for performing maps @@ -166,23 +166,10 @@ public Mapper(IConfigurationProvider configuration, Factory serviceCtor) 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) - { - CheckDestination(destination, destinationType); - return MapCore(source, destination, DefaultContext, sourceType, destinationType); - } - private static void CheckDestination(object destination, Type destinationType) - { - if (destination == null) - { - ArgumentNullException.ThrowIfNull(destinationType); - } - } - public object Map(object source, object destination, Type sourceType, Type destinationType, Action opts) - { - CheckDestination(destination, destinationType); - return MapWithOptions(source, destination, opts, sourceType, destinationType); - } + 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) diff --git a/src/UnitTests/NullBehavior.cs b/src/UnitTests/NullBehavior.cs index 59faf94037..dbf8cc442b 100644 --- a/src/UnitTests/NullBehavior.cs +++ b/src/UnitTests/NullBehavior.cs @@ -5,8 +5,6 @@ public class NullDestinationType : AutoMapperSpecBase [Fact] public void Should_require_destination_object() { - new Action(() => Mapper.Map("", null, null)).ShouldThrow().ParamName.ShouldBe("destinationType"); - new Action(() => Mapper.Map("", null, null, _=>{ })).ShouldThrow().ParamName.ShouldBe("destinationType"); Mapper.Map("", "", null, null).ShouldBe(""); Mapper.Map("", null, null, typeof(string)).ShouldBe(""); Mapper.Map("", "", null, null, _ => { }).ShouldBe("");