diff --git a/src/AutoMapper/ApiCompatBaseline.txt b/src/AutoMapper/ApiCompatBaseline.txt index c75e43358e..95b0733f02 100644 --- a/src/AutoMapper/ApiCompatBaseline.txt +++ b/src/AutoMapper/ApiCompatBaseline.txt @@ -1,5 +1,9 @@ Compat issues with assembly AutoMapper: CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'AutoMapper.AutoMapAttribute' changed from '[AttributeUsageAttribute(1036, AllowMultiple=true)]' in the contract to '[AttributeUsageAttribute(AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Struct, AllowMultiple=true)]' in the implementation. +CannotSealType : Type 'AutoMapper.AutoMapperConfigurationException.TypeMapConfigErrors' is actually (has the sealed modifier) sealed in the implementation but not sealed in the contract. +TypeCannotChangeClassification : Type 'AutoMapper.AutoMapperConfigurationException.TypeMapConfigErrors' is a 'struct' in the implementation but is a 'class' in the contract. +CannotSealType : Type 'AutoMapper.DuplicateTypeMapConfigurationException.TypeMapConfigErrors' is actually (has the sealed modifier) sealed in the implementation but not sealed in the contract. +TypeCannotChangeClassification : Type 'AutoMapper.DuplicateTypeMapConfigurationException.TypeMapConfigErrors' is a 'struct' in the implementation but is a 'class' 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. @@ -24,6 +28,9 @@ CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.NullableAttri 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. +MembersMustExist : Member 'public void AutoMapper.Configuration.MappingExpression..ctor(AutoMapper.Internal.TypePair, AutoMapper.MemberList)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public void AutoMapper.Configuration.MappingExpression..ctor(AutoMapper.MemberList, System.Type, System.Type)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'protected void AutoMapper.Configuration.MappingExpressionBase..ctor(AutoMapper.MemberList, System.Type, System.Type)' does not exist in the implementation but it does exist in the contract. CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'AutoMapper.Configuration.Annotations.IgnoreAttribute' changed from '[AttributeUsageAttribute(384)]' in the contract to '[AttributeUsageAttribute(AttributeTargets.Field | AttributeTargets.Property)]' in the implementation. CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'AutoMapper.Configuration.Annotations.MapAtRuntimeAttribute' changed from '[AttributeUsageAttribute(384)]' in the contract to '[AttributeUsageAttribute(AttributeTargets.Field | AttributeTargets.Property)]' in the implementation. CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'AutoMapper.Configuration.Annotations.MappingOrderAttribute' changed from '[AttributeUsageAttribute(384)]' in the contract to '[AttributeUsageAttribute(AttributeTargets.Field | AttributeTargets.Property)]' in the implementation. @@ -32,6 +39,8 @@ CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'AutoMappe CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'AutoMapper.Configuration.Annotations.UseExistingValueAttribute' changed from '[AttributeUsageAttribute(384)]' in the contract to '[AttributeUsageAttribute(AttributeTargets.Field | AttributeTargets.Property)]' in the implementation. CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'AutoMapper.Configuration.Annotations.ValueConverterAttribute' changed from '[AttributeUsageAttribute(384)]' in the contract to '[AttributeUsageAttribute(AttributeTargets.Field | AttributeTargets.Property)]' in the implementation. CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'AutoMapper.Configuration.Annotations.ValueResolverAttribute' changed from '[AttributeUsageAttribute(384)]' in the contract to '[AttributeUsageAttribute(AttributeTargets.Field | AttributeTargets.Property)]' in the implementation. +CannotSealType : Type 'AutoMapper.Internal.Mappers.MultidimensionalArrayFiller' is actually (has the sealed modifier) sealed in the implementation but not sealed in the contract. +TypeCannotChangeClassification : Type 'AutoMapper.Internal.Mappers.MultidimensionalArrayFiller' is a 'struct' in the implementation but is a 'class' in the contract. 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. @@ -43,4 +52,4 @@ CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.NullableAttri 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 +Total Issues: 53 diff --git a/src/AutoMapper/AutoMapperMappingException.cs b/src/AutoMapper/AutoMapperMappingException.cs index e167e2927d..02f5dbca3c 100644 --- a/src/AutoMapper/AutoMapperMappingException.cs +++ b/src/AutoMapper/AutoMapperMappingException.cs @@ -67,43 +67,29 @@ public override string StackTrace { return string.Join(Environment.NewLine, base.StackTrace - .Split(new[] {Environment.NewLine}, StringSplitOptions.None) + .Split([Environment.NewLine], StringSplitOptions.None) .Where(str => !str.TrimStart().StartsWith("at AutoMapper."))); } } #endif } -public class DuplicateTypeMapConfigurationException : Exception +public class DuplicateTypeMapConfigurationException(DuplicateTypeMapConfigurationException.TypeMapConfigErrors[] errors) : Exception { - public TypeMapConfigErrors[] Errors { get; } - - public DuplicateTypeMapConfigurationException(TypeMapConfigErrors[] errors) + public TypeMapConfigErrors[] Errors { get; } = errors; + public override string Message { get; } = GetErrors(errors); + static string GetErrors(TypeMapConfigErrors[] errors) { - Errors = errors; - var builder = new StringBuilder(); + StringBuilder builder = new(); builder.AppendLine("Duplicate CreateMap calls:"); - foreach (var error in Errors) + foreach(var error in errors) { builder.AppendLine($"{error.Types.SourceType.FullName} to {error.Types.DestinationType.FullName} defined in profiles:"); builder.AppendLine(string.Join(Environment.NewLine, error.ProfileNames)); } builder.AppendLine("This can cause configuration collisions and inconsistent mappings. Use a single CreateMap call per type pair."); - Message = builder.ToString(); - } - - public class TypeMapConfigErrors - { - public string[] ProfileNames { get; } - public TypePair Types { get; } - - public TypeMapConfigErrors(TypePair types, string[] profileNames) - { - Types = types; - ProfileNames = profileNames; - } + return builder.ToString(); } - - public override string Message { get; } + public readonly record struct TypeMapConfigErrors(TypePair Types, string[] ProfileNames); } public class AutoMapperConfigurationException : Exception { @@ -111,19 +97,7 @@ public class AutoMapperConfigurationException : Exception public TypePair? Types { get; } public MemberMap MemberMap { get; set; } - public class TypeMapConfigErrors - { - public TypeMap TypeMap { get; } - public string[] UnmappedPropertyNames { get; } - public bool CanConstruct { get; } - - public TypeMapConfigErrors(TypeMap typeMap, string[] unmappedPropertyNames, bool canConstruct) - { - TypeMap = typeMap; - UnmappedPropertyNames = unmappedPropertyNames; - CanConstruct = canConstruct; - } - } + public readonly record struct TypeMapConfigErrors(TypeMap TypeMap, string[] UnmappedPropertyNames, bool CanConstruct); public AutoMapperConfigurationException(string message) : base(message) @@ -170,8 +144,7 @@ public override string Message } if (Errors != null) { - var message = - new StringBuilder( + StringBuilder message = new( "\nUnmapped members were found. Review the types and members below.\nAdd a custom mapping expression, ignore, add a custom resolver, or modify the source/destination type\nFor no matching constructor, add a no-arg ctor, add optional arguments, or map all of the constructor parameters\n"); foreach (var error in Errors) @@ -179,7 +152,7 @@ public override string Message var len = error.TypeMap.SourceType.FullName.Length + error.TypeMap.DestinationType.FullName.Length + 5; - message.AppendLine(new string('=', len)); + message.AppendLine(new('=', len)); message.AppendLine(error.TypeMap.SourceType.Name + " -> " + error.TypeMap.DestinationType.Name + " (" + error.TypeMap.ConfiguredMemberList + " member list)"); @@ -214,7 +187,7 @@ public override string StackTrace if (Errors != null) return string.Join(Environment.NewLine, base.StackTrace - .Split(new[] { Environment.NewLine }, StringSplitOptions.None) + .Split([Environment.NewLine], StringSplitOptions.None) .Where(str => !str.TrimStart().StartsWith("at AutoMapper.")) .ToArray()); diff --git a/src/AutoMapper/Configuration/Annotations/AutoMapAttribute.cs b/src/AutoMapper/Configuration/Annotations/AutoMapAttribute.cs index 903867d05f..c73db236f4 100644 --- a/src/AutoMapper/Configuration/Annotations/AutoMapAttribute.cs +++ b/src/AutoMapper/Configuration/Annotations/AutoMapAttribute.cs @@ -5,12 +5,9 @@ /// Discovered during scanning assembly scanning for configuration when calling /// [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Struct, AllowMultiple = true)] -public sealed class AutoMapAttribute : Attribute +public sealed class AutoMapAttribute(Type sourceType) : Attribute { - public AutoMapAttribute(Type sourceType) - => SourceType = sourceType; - - public Type SourceType { get; } + public Type SourceType { get; } = sourceType; public bool ReverseMap { get; set; } /// diff --git a/src/AutoMapper/Configuration/IMemberConfigurationProvider.cs b/src/AutoMapper/Configuration/Annotations/IMemberConfigurationProvider.cs similarity index 100% rename from src/AutoMapper/Configuration/IMemberConfigurationProvider.cs rename to src/AutoMapper/Configuration/Annotations/IMemberConfigurationProvider.cs diff --git a/src/AutoMapper/Configuration/Annotations/MappingOrderAttribute.cs b/src/AutoMapper/Configuration/Annotations/MappingOrderAttribute.cs index d028b1e906..2dbb536762 100644 --- a/src/AutoMapper/Configuration/Annotations/MappingOrderAttribute.cs +++ b/src/AutoMapper/Configuration/Annotations/MappingOrderAttribute.cs @@ -7,14 +7,9 @@ /// Must be used in combination with /// [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] -public sealed class MappingOrderAttribute : Attribute, IMemberConfigurationProvider +public sealed class MappingOrderAttribute(int value) : Attribute, IMemberConfigurationProvider { - public int Value { get; } - - public MappingOrderAttribute(int value) - { - Value = value; - } + public int Value { get; } = value; public void ApplyConfiguration(IMemberConfigurationExpression memberConfigurationExpression) { diff --git a/src/AutoMapper/Configuration/Annotations/NullSubstituteAttribute.cs b/src/AutoMapper/Configuration/Annotations/NullSubstituteAttribute.cs index 9de69f389c..0a30f3949e 100644 --- a/src/AutoMapper/Configuration/Annotations/NullSubstituteAttribute.cs +++ b/src/AutoMapper/Configuration/Annotations/NullSubstituteAttribute.cs @@ -7,17 +7,12 @@ /// Must be used in combination with /// [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] -public sealed class NullSubstituteAttribute : Attribute, IMemberConfigurationProvider +public sealed class NullSubstituteAttribute(object value) : Attribute, IMemberConfigurationProvider { /// /// Value to use if source value is null /// - public object Value { get; } - - public NullSubstituteAttribute(object value) - { - Value = value; - } + public object Value { get; } = value; public void ApplyConfiguration(IMemberConfigurationExpression memberConfigurationExpression) { diff --git a/src/AutoMapper/Configuration/Annotations/SourceMemberAttribute.cs b/src/AutoMapper/Configuration/Annotations/SourceMemberAttribute.cs index a73ac3756a..daca85749f 100644 --- a/src/AutoMapper/Configuration/Annotations/SourceMemberAttribute.cs +++ b/src/AutoMapper/Configuration/Annotations/SourceMemberAttribute.cs @@ -7,11 +7,9 @@ /// Must be used in combination with /// [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] -public sealed class SourceMemberAttribute : Attribute, IMemberConfigurationProvider +public sealed class SourceMemberAttribute(string name) : Attribute, IMemberConfigurationProvider { - public string Name { get; } - - public SourceMemberAttribute(string name) => Name = name; + public string Name { get; } = name; public void ApplyConfiguration(IMemberConfigurationExpression memberConfigurationExpression) { diff --git a/src/AutoMapper/Configuration/Annotations/ValueConverterAttribute.cs b/src/AutoMapper/Configuration/Annotations/ValueConverterAttribute.cs index bf0a87e552..dda9d6230a 100644 --- a/src/AutoMapper/Configuration/Annotations/ValueConverterAttribute.cs +++ b/src/AutoMapper/Configuration/Annotations/ValueConverterAttribute.cs @@ -8,17 +8,12 @@ /// Must be used in combination with /// [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] -public sealed class ValueConverterAttribute : Attribute, IMemberConfigurationProvider +public sealed class ValueConverterAttribute(Type type) : Attribute, IMemberConfigurationProvider { /// /// type /// - public Type Type { get; } - - public ValueConverterAttribute(Type type) - { - Type = type; - } + public Type Type { get; } = type; public void ApplyConfiguration(IMemberConfigurationExpression memberConfigurationExpression) { diff --git a/src/AutoMapper/Configuration/Annotations/ValueResolverAttribute.cs b/src/AutoMapper/Configuration/Annotations/ValueResolverAttribute.cs index dea7196d35..8d6f9c911a 100644 --- a/src/AutoMapper/Configuration/Annotations/ValueResolverAttribute.cs +++ b/src/AutoMapper/Configuration/Annotations/ValueResolverAttribute.cs @@ -8,17 +8,12 @@ /// Must be used in combination with /// [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] -public sealed class ValueResolverAttribute : Attribute, IMemberConfigurationProvider +public sealed class ValueResolverAttribute(Type type) : Attribute, IMemberConfigurationProvider { /// /// or type /// - public Type Type { get; } - - public ValueResolverAttribute(Type type) - { - Type = type; - } + public Type Type { get; } = type; public void ApplyConfiguration(IMemberConfigurationExpression memberConfigurationExpression) { diff --git a/src/AutoMapper/Configuration/ConfigurationValidator.cs b/src/AutoMapper/Configuration/ConfigurationValidator.cs index 9a9448bb01..bd34f5968e 100644 --- a/src/AutoMapper/Configuration/ConfigurationValidator.cs +++ b/src/AutoMapper/Configuration/ConfigurationValidator.cs @@ -1,6 +1,5 @@ using AutoMapper.Internal.Mappers; namespace AutoMapper.Configuration; - [EditorBrowsable(EditorBrowsableState.Never)] public readonly record struct ConfigurationValidator(IGlobalConfigurationExpression Expression) { @@ -11,7 +10,7 @@ private void Validate(ValidationContext context) validator(context); } } - public void AssertConfigurationExpressionIsValid(IGlobalConfiguration config, IEnumerable typeMaps) + public void AssertConfigurationExpressionIsValid(IGlobalConfiguration config, TypeMap[] typeMaps) { var duplicateTypeMapConfigs = Expression.Profiles.Append((Profile)Expression) .SelectMany(p => p.TypeMapConfigs, (profile, typeMap) => (profile, typeMap)) @@ -26,25 +25,23 @@ public void AssertConfigurationExpressionIsValid(IGlobalConfiguration config, IE } AssertConfigurationIsValid(config, typeMaps); } - public void AssertConfigurationIsValid(IGlobalConfiguration config, IEnumerable typeMaps) + public void AssertConfigurationIsValid(IGlobalConfiguration config, TypeMap[] typeMaps) { - var maps = typeMaps as TypeMap[] ?? typeMaps.ToArray(); var badTypeMaps = - (from typeMap in maps + (from typeMap in typeMaps where typeMap.ShouldCheckForValid let unmappedPropertyNames = typeMap.GetUnmappedPropertyNames() let canConstruct = typeMap.PassesCtorValidation where unmappedPropertyNames.Length > 0 || !canConstruct select new AutoMapperConfigurationException.TypeMapConfigErrors(typeMap, unmappedPropertyNames, canConstruct) ).ToArray(); - - if (badTypeMaps.Any()) + if (badTypeMaps.Length > 0) { throw new AutoMapperConfigurationException(badTypeMaps); } - var typeMapsChecked = new HashSet(); - var configExceptions = new List(); - foreach (var typeMap in maps) + HashSet typeMapsChecked = []; + List configExceptions = []; + foreach (var typeMap in typeMaps) { try { @@ -81,8 +78,7 @@ private void DryRunTypeMap(IGlobalConfiguration config, HashSet typeMap return; } typeMapsChecked.Add(typeMap); - var context = new ValidationContext(types, memberMap, typeMap); - Validate(context); + Validate(new(types, memberMap, typeMap)); if(!typeMap.ShouldCheckForValid) { return; @@ -96,8 +92,7 @@ private void DryRunTypeMap(IGlobalConfiguration config, HashSet typeMap { throw new AutoMapperConfigurationException(memberMap.TypeMap.Types) { MemberMap = memberMap }; } - var context = new ValidationContext(types, memberMap, ObjectMapper: mapperToUse); - Validate(context); + Validate(new(types, memberMap, ObjectMapper: mapperToUse)); if (mapperToUse.GetAssociatedTypes(types) is TypePair newTypes && newTypes != types) { DryRunTypeMap(config, typeMapsChecked, newTypes, null, memberMap); diff --git a/src/AutoMapper/Configuration/Conventions.cs b/src/AutoMapper/Configuration/Conventions.cs index 191861472f..08cb6f6684 100644 --- a/src/AutoMapper/Configuration/Conventions.cs +++ b/src/AutoMapper/Configuration/Conventions.cs @@ -8,9 +8,9 @@ public interface ISourceToDestinationNameMapper public sealed class MemberConfiguration { NameSplitMember _nameSplitMember; - public INamingConvention SourceNamingConvention { get; set; } = PascalCaseNamingConvention.Instance; - public INamingConvention DestinationNamingConvention { get; set; } = PascalCaseNamingConvention.Instance; - public List NameToMemberMappers { get; } = new(); + public INamingConvention SourceNamingConvention { get; set; } + public INamingConvention DestinationNamingConvention { get; set; } + public List NameToMemberMappers { get; } = []; public bool IsMatch(ProfileMap options, TypeDetails sourceTypeDetails, Type destType, Type destMemberType, string nameToSearch, List resolvers, bool isReverseMap) { var matchingMemberInfo = GetSourceMember(sourceTypeDetails, destType, destMemberType, nameToSearch); @@ -45,10 +45,6 @@ public void Seal() } public void Merge(MemberConfiguration other) { - if (other == null) - { - return; - } var initialCount = NameToMemberMappers.Count; for (int index = 0; index < other.NameToMemberMappers.Count; index++) { @@ -64,12 +60,14 @@ public void Merge(MemberConfiguration other) } NameToMemberMappers.Add(otherMapper); } + SourceNamingConvention ??= other.SourceNamingConvention; + DestinationNamingConvention ??= other.DestinationNamingConvention; } } public sealed class PrePostfixName : ISourceToDestinationNameMapper { - public List DestinationPrefixes { get; } = new(); - public List DestinationPostfixes { get; } = new(); + public List DestinationPrefixes { get; } = []; + public List DestinationPostfixes { get; } = []; public MemberInfo GetSourceMember(TypeDetails sourceTypeDetails, Type destType, Type destMemberType, string nameToSearch) { MemberInfo member; @@ -91,15 +89,15 @@ public void Merge(ISourceToDestinationNameMapper other) } public sealed class ReplaceName : ISourceToDestinationNameMapper { - public List MemberNameReplacers { get; } = new(); + public List MemberNameReplacers { get; } = []; public MemberInfo GetSourceMember(TypeDetails sourceTypeDetails, Type destType, Type destMemberType, string nameToSearch) { var possibleSourceNames = PossibleNames(nameToSearch); - if (possibleSourceNames.Length == 0) + if (possibleSourceNames.Count == 0) { return null; } - var possibleDestNames = sourceTypeDetails.ReadAccessors.Select(mi => (mi, possibles : PossibleNames(mi.Name))).ToArray(); + var possibleDestNames = Array.ConvertAll(sourceTypeDetails.ReadAccessors, mi => (mi, possibles : PossibleNames(mi.Name))); foreach (var sourceName in possibleSourceNames) { foreach (var (mi, possibles) in possibleDestNames) @@ -112,15 +110,9 @@ public MemberInfo GetSourceMember(TypeDetails sourceTypeDetails, Type destType, } return null; } - public void Merge(ISourceToDestinationNameMapper other) - { - var typedOther = (ReplaceName)other; - MemberNameReplacers.TryAdd(typedOther.MemberNameReplacers); - } - private string[] PossibleNames(string nameToSearch) => - MemberNameReplacers.Select(r => nameToSearch.Replace(r.OriginalValue, r.NewValue)) - .Concat(new[] { MemberNameReplacers.Aggregate(nameToSearch, (s, r) => s.Replace(r.OriginalValue, r.NewValue)), nameToSearch }) - .ToArray(); + public void Merge(ISourceToDestinationNameMapper other) => MemberNameReplacers.TryAdd(((ReplaceName)other).MemberNameReplacers); + private List PossibleNames(string nameToSearch) => [..MemberNameReplacers.Select(r => nameToSearch.Replace(r.OriginalValue, r.NewValue)), + MemberNameReplacers.Aggregate(nameToSearch, (s, r) => s.Replace(r.OriginalValue, r.NewValue)), nameToSearch]; } [EditorBrowsable(EditorBrowsableState.Never)] public readonly record struct MemberNameReplacer(string OriginalValue, string NewValue); diff --git a/src/AutoMapper/Configuration/CtorParamConfigurationExpression.cs b/src/AutoMapper/Configuration/CtorParamConfigurationExpression.cs index 4fa6876714..0cca9fcf35 100644 --- a/src/AutoMapper/Configuration/CtorParamConfigurationExpression.cs +++ b/src/AutoMapper/Configuration/CtorParamConfigurationExpression.cs @@ -34,36 +34,24 @@ public interface ICtorParameterConfiguration void Configure(TypeMap typeMap); } [EditorBrowsable(EditorBrowsableState.Never)] -public sealed class CtorParamConfigurationExpression : ICtorParamConfigurationExpression, ICtorParameterConfiguration +public sealed class CtorParamConfigurationExpression(string ctorParamName, Type sourceType) : ICtorParamConfigurationExpression, ICtorParameterConfiguration { - public string CtorParamName { get; } - public Type SourceType { get; } - - private readonly List> _ctorParamActions = new List>(); - - public CtorParamConfigurationExpression(string ctorParamName, Type sourceType) - { - CtorParamName = ctorParamName; - SourceType = sourceType; - } - + public string CtorParamName { get; } = ctorParamName; + public Type SourceType { get; } = sourceType; + private readonly List> _ctorParamActions = []; public void MapFrom(Expression> sourceMember) => _ctorParamActions.Add(cpm => cpm.MapFrom(sourceMember)); - public void MapFrom(Func resolver) { Expression> resolverExpression = (src, dest, destMember, ctxt) => resolver(src, ctxt); _ctorParamActions.Add(cpm => cpm.SetResolver(new FuncResolver(resolverExpression))); } - public void MapFrom(string sourceMembersPath) { var sourceMembers = ReflectionHelper.GetMemberPath(SourceType, sourceMembersPath); _ctorParamActions.Add(cpm => cpm.MapFrom(sourceMembersPath, sourceMembers)); } - public void ExplicitExpansion(bool value) => _ctorParamActions.Add(cpm => cpm.ExplicitExpansion = value); - public void Configure(TypeMap typeMap) { var ctorMap = typeMap.ConstructorMap; diff --git a/src/AutoMapper/Configuration/IMappingOperationOptions.cs b/src/AutoMapper/Configuration/IMappingOperationOptions.cs index 471f92b8d8..f4c1b81022 100644 --- a/src/AutoMapper/Configuration/IMappingOperationOptions.cs +++ b/src/AutoMapper/Configuration/IMappingOperationOptions.cs @@ -45,10 +45,9 @@ public interface IMappingOperationOptions : IMappingOpera /// Callback for the source/destination types void AfterMap(Action afterFunction); } -public sealed class MappingOperationOptions : IMappingOperationOptions +public sealed class MappingOperationOptions(Func serviceCtor) : IMappingOperationOptions { - public MappingOperationOptions(Func serviceCtor) => ServiceCtor = serviceCtor; - public Func ServiceCtor { get; private set; } + public Func ServiceCtor { get; private set; } = serviceCtor; public StringDictionary Items => (StringDictionary) (State ??= new StringDictionary()); public object State { get; set; } public Action BeforeMapAction { get; private set; } diff --git a/src/AutoMapper/Configuration/INamingConvention.cs b/src/AutoMapper/Configuration/INamingConvention.cs index 4059b9a12a..46e3c93cb3 100644 --- a/src/AutoMapper/Configuration/INamingConvention.cs +++ b/src/AutoMapper/Configuration/INamingConvention.cs @@ -11,7 +11,7 @@ public interface INamingConvention public sealed class ExactMatchNamingConvention : INamingConvention { public static readonly ExactMatchNamingConvention Instance = new(); - public string[] Split(string _) => Array.Empty(); + public string[] Split(string _) => []; public string SeparatorCharacter => null; } public sealed class PascalCaseNamingConvention : INamingConvention @@ -26,17 +26,17 @@ public string[] Split(string input) { if (char.IsUpper(input[index])) { - result ??= new(); + result ??= []; result.Add(input[lower..index]); lower = index; } } if (result == null) { - return Array.Empty(); + return []; } result.Add(input[lower..]); - return result.ToArray(); + return [..result]; } } public sealed class LowerUnderscoreNamingConvention : INamingConvention diff --git a/src/AutoMapper/Configuration/MapperConfiguration.cs b/src/AutoMapper/Configuration/MapperConfiguration.cs index 0a1f7115e6..2255b0c09e 100644 --- a/src/AutoMapper/Configuration/MapperConfiguration.cs +++ b/src/AutoMapper/Configuration/MapperConfiguration.cs @@ -46,16 +46,16 @@ public sealed class MapperConfiguration : IGlobalConfiguration private readonly ConfigurationValidator _validator; private readonly Features _features = new(); private readonly bool _hasOpenMaps; - private readonly HashSet _typeMapsPath = new(); - private readonly List _sourceMembers = new(); - private readonly List _variables = new(); - private readonly ParameterExpression[] _parameters = new[] { null, null, ContextParameter }; - private readonly CatchBlock[] _catches = new CatchBlock[1]; - private readonly List _expressions = new(); + private readonly HashSet _typeMapsPath = []; + private readonly List _sourceMembers = []; + private readonly List _variables = []; + private readonly ParameterExpression[] _parameters = [null, null, ContextParameter]; + private readonly CatchBlock[] _catches = [null]; + private readonly List _expressions = []; private readonly Dictionary _defaults; private readonly ParameterReplaceVisitor _parameterReplaceVisitor = new(); private readonly ConvertParameterReplaceVisitor _convertParameterReplaceVisitor = new(); - private readonly List _typesInheritance = new(); + private readonly List _typesInheritance = []; public MapperConfiguration(MapperConfigurationExpression configurationExpression) { var configuration = (IGlobalConfigurationExpression)configurationExpression; @@ -63,7 +63,7 @@ public MapperConfiguration(MapperConfigurationExpression configurationExpression { configuration.IncludeSourceExtensionMethods(typeof(Enumerable)); } - _mappers = configuration.Mappers.ToArray(); + _mappers = [..configuration.Mappers]; _executionPlans = new(CompileExecutionPlan); _validator = new(configuration); _projectionBuilder = new(CreateProjectionBuilder); @@ -75,7 +75,7 @@ public MapperConfiguration(MapperConfigurationExpression configurationExpression int index = 1; foreach (var profile in configuration.Profiles) { - var profileMap = new ProfileMap(profile, configuration); + ProfileMap profileMap = new(profile, configuration); Profiles[index++] = profileMap; typeMapsCount += profileMap.TypeMapsCount; openTypeMapsCount += profileMap.OpenTypeMapsCount; @@ -117,7 +117,7 @@ void Seal() profile.Configure(this); } IGlobalConfiguration globalConfiguration = this; - var derivedMaps = new List(); + List derivedMaps = []; foreach (var typeMap in _configuredMaps.Values) { _resolvedMaps[typeMap.Types] = typeMap; @@ -125,8 +125,7 @@ void Seal() GetDerivedTypeMaps(typeMap, derivedMaps); foreach (var derivedMap in derivedMaps) { - var includedPair = new TypePair(derivedMap.SourceType, typeMap.DestinationType); - _resolvedMaps.TryAdd(includedPair, derivedMap); + _resolvedMaps.TryAdd(new(derivedMap.SourceType, typeMap.DestinationType), derivedMap); } } foreach (var typeMap in _configuredMaps.Values) @@ -156,21 +155,17 @@ static MapperConfigurationExpression Build(Action _validator.AssertConfigurationExpressionIsValid(this, _configuredMaps.Values); + public void AssertConfigurationIsValid() => _validator.AssertConfigurationExpressionIsValid(this, [.._configuredMaps.Values]); public IMapper CreateMapper() => new Mapper(this); public IMapper CreateMapper(Func serviceCtor) => new Mapper(this, serviceCtor); public void CompileMappings() { - foreach (var request in _resolvedMaps.Keys.Where(t => !t.ContainsGenericParameters).Select(types => new MapRequest(types, types, MemberMap.Instance)).ToArray()) + foreach (var request in _resolvedMaps.Keys.Where(t => !t.ContainsGenericParameters).Select(types => new MapRequest(types)).ToArray()) { GetExecutionPlan(request); } } - public LambdaExpression BuildExecutionPlan(Type sourceType, Type destinationType) - { - var typePair = new TypePair(sourceType, destinationType); - return this.Internal().BuildExecutionPlan(new(typePair, typePair, MemberMap.Instance)); - } + public LambdaExpression BuildExecutionPlan(Type sourceType, Type destinationType) => this.Internal().BuildExecutionPlan(new(new(sourceType, destinationType))); LambdaExpression IGlobalConfiguration.BuildExecutionPlan(in MapRequest mapRequest) { var typeMap = ResolveTypeMap(mapRequest.RuntimeTypes) ?? ResolveTypeMap(mapRequest.RequestedTypes); @@ -204,7 +199,7 @@ LambdaExpression GenerateObjectMapperExpression(in MapRequest mapRequest, IObjec Expression fullExpression; if (mapper == null) { - var exception = new AutoMapperMappingException("Missing type map configuration or unsupported mapping.", null, mapRequest.RuntimeTypes) + AutoMapperMappingException exception = new("Missing type map configuration or unsupported mapping.", null, mapRequest.RuntimeTypes) { MemberMap = mapRequest.MemberMap }; @@ -224,7 +219,7 @@ LambdaExpression GenerateObjectMapperExpression(in MapRequest mapRequest, IObjec } } IGlobalConfigurationExpression ConfigurationExpression => _validator.Expression; - ProjectionBuilder CreateProjectionBuilder() => new(this, ConfigurationExpression.ProjectionMappers.ToArray()); + ProjectionBuilder CreateProjectionBuilder() => new(this, [..ConfigurationExpression.ProjectionMappers]); IProjectionBuilder IGlobalConfiguration.ProjectionBuilder => _projectionBuilder.Value; Func IGlobalConfiguration.ServiceCtor => ConfigurationExpression.ServiceCtor; bool IGlobalConfiguration.EnableNullPropagationForQueryMapping => ConfigurationExpression.EnableNullPropagationForQueryMapping.GetValueOrDefault(); @@ -320,7 +315,7 @@ private TypeMap GetTypeMap(TypePair initialTypes) List typesInheritance; if (_typesInheritance == null) { - typesInheritance = new(); + typesInheritance = []; } else { @@ -340,7 +335,7 @@ private TypeMap GetTypeMap(TypePair initialTypes) { continue; } - var types = new TypePair(sourceType, destinationType); + TypePair types = new(sourceType, destinationType); if (_resolvedMaps.TryGetValue(types, out typeMap)) { if(typeMap == null) @@ -432,7 +427,7 @@ TypeMap[] IGlobalConfiguration.GetIncludedTypeMaps(IReadOnlyCollection { if (includedTypes.Count == 0) { - return Array.Empty(); + return []; } var typeMaps = new TypeMap[includedTypes.Count]; int index = 0; @@ -476,23 +471,22 @@ IObjectMapper FindMapper(TypePair types) return null; } void IGlobalConfiguration.RegisterTypeMap(TypeMap typeMap) => _configuredMaps[typeMap.Types] = typeMap; - void IGlobalConfiguration.AssertConfigurationIsValid(TypeMap typeMap) => _validator.AssertConfigurationIsValid(this, new[] { typeMap }); + void IGlobalConfiguration.AssertConfigurationIsValid(TypeMap typeMap) => _validator.AssertConfigurationIsValid(this, [typeMap]); void IGlobalConfiguration.AssertConfigurationIsValid(string profileName) { if (Array.TrueForAll(Profiles, x => x.Name != profileName)) { throw new ArgumentOutOfRangeException(nameof(profileName), $"Cannot find any profiles with the name '{profileName}'."); } - _validator.AssertConfigurationIsValid(this, _configuredMaps.Values.Where(typeMap => typeMap.Profile.Name == profileName)); + _validator.AssertConfigurationIsValid(this, _configuredMaps.Values.Where(typeMap => typeMap.Profile.Name == profileName).ToArray()); } void IGlobalConfiguration.AssertConfigurationIsValid() => this.Internal().AssertConfigurationIsValid(typeof(TProfile).FullName); void IGlobalConfiguration.RegisterAsMap(TypeMapConfiguration typeMapConfiguration) => _resolvedMaps[typeMapConfiguration.Types] = GetIncludedTypeMap(new(typeMapConfiguration.SourceType, typeMapConfiguration.DestinationTypeOverride)); } -struct LazyValue where T : class +struct LazyValue(Func factory) where T : class { - readonly Func _factory; + readonly Func _factory = factory; T _value = null; public T Value => LazyInitializer.EnsureInitialized(ref _value, _factory); - public LazyValue(Func factory) => _factory = factory; } \ No newline at end of file diff --git a/src/AutoMapper/Configuration/MapperConfigurationExpression.cs b/src/AutoMapper/Configuration/MapperConfigurationExpression.cs index 6c7ad6f177..2335e2d5e5 100644 --- a/src/AutoMapper/Configuration/MapperConfigurationExpression.cs +++ b/src/AutoMapper/Configuration/MapperConfigurationExpression.cs @@ -87,14 +87,10 @@ public interface IMapperConfigurationExpression : IProfileExpression } public sealed class MapperConfigurationExpression : Profile, IGlobalConfigurationExpression { - private readonly List _profiles = new(); - private readonly List _validators = new(); - private readonly List _mappers; + private readonly List _profiles = []; + private readonly List _validators = []; private Func _serviceCtor = Activator.CreateInstance; private List _projectionMappers; - - public MapperConfigurationExpression() : base() => _mappers = MapperRegistry.Mappers(); - /// /// Add an action to be called when validating the configuration. /// @@ -123,9 +119,9 @@ void IGlobalConfigurationExpression.Validator(Validator validator) => public void CreateProfile(string profileName, Action config) => AddProfile(new Profile(profileName, config)); - List IGlobalConfigurationExpression.Mappers => _mappers; + List IGlobalConfigurationExpression.Mappers { get; } = MapperRegistry.Mappers(); - Features IGlobalConfigurationExpression.Features { get; } = new Features(); + Features IGlobalConfigurationExpression.Features { get; } = new(); public void AddProfile(Profile profile) => _profiles.Add(profile); @@ -161,7 +157,7 @@ public void AddMaps(params Type[] typesFromAssembliesContainingMappingDefinition private void AddMapsCore(IEnumerable assembliesToScan) { - var autoMapAttributeProfile = new Profile(nameof(AutoMapAttribute)); + Profile autoMapAttributeProfile = new(nameof(AutoMapAttribute)); foreach (var type in assembliesToScan.Where(a => !a.IsDynamic && a != typeof(Profile).Assembly).SelectMany(a => a.GetTypes())) { if (typeof(Profile).IsAssignableFrom(type) && !type.IsAbstract && !type.ContainsGenericParameters) diff --git a/src/AutoMapper/Configuration/MappingExpression.cs b/src/AutoMapper/Configuration/MappingExpression.cs index 427308c0f9..30676f4cf9 100644 --- a/src/AutoMapper/Configuration/MappingExpression.cs +++ b/src/AutoMapper/Configuration/MappingExpression.cs @@ -1,16 +1,11 @@ namespace AutoMapper.Configuration; -public sealed class MappingExpression : MappingExpressionBase, IMappingExpression +public sealed class MappingExpression(MemberList memberList, TypePair types) : MappingExpressionBase(memberList, types), IMappingExpression { - public MappingExpression(TypePair types, MemberList memberList) : base(memberList, types){} - public MappingExpression(TypeMap typeMap) : this(typeMap.Types, typeMap.ConfiguredMemberList) => Projection = typeMap.Projection; - public string[] IncludedMembersNames { get; internal set; } = Array.Empty(); + public MappingExpression(TypeMap typeMap) : this(typeMap.ConfiguredMemberList, typeMap.Types) => Projection = typeMap.Projection; + public string[] IncludedMembersNames { get; internal set; } = []; public IMappingExpression ReverseMap() { - var reversedTypes = new TypePair(DestinationType, SourceType); - var reverseMap = new MappingExpression(reversedTypes, MemberList.None) - { - IsReverseMap = true - }; + MappingExpression reverseMap = new(MemberList.None, Types.Reverse()) { IsReverseMap = true }; ReverseMapCore(reverseMap); reverseMap.IncludeMembers(MapToSourceMembers().Select(m => m.DestinationMember.Name).ToArray()); foreach (var includedMemberName in IncludedMembersNames) @@ -48,7 +43,7 @@ public IMappingExpression ForMember(string name, Action ForMember(property, o=>o.Ignore()); internal MemberConfigurationExpression ForMember(MemberInfo destinationProperty, Action memberOptions) { - var expression = new MemberConfigurationExpression(destinationProperty, SourceType); + MemberConfigurationExpression expression = new(destinationProperty, SourceType); MemberConfigurations.Add(expression); memberOptions(expression); return expression; @@ -57,8 +52,8 @@ internal MemberConfigurationExpression ForMember(MemberInfo destinationProperty, public class MappingExpression : MappingExpressionBase>, IMappingExpression, IProjectionExpression { - public MappingExpression(MemberList memberList, bool projection = false) : base(memberList) => Projection = projection; - public MappingExpression(MemberList memberList, Type sourceType, Type destinationType) : base(memberList, sourceType, destinationType) { } + public MappingExpression(MemberList memberList, bool projection) : base(memberList) => Projection = projection; + public MappingExpression(MemberList memberList, TypePair types) : base(memberList, types) { } public IMappingExpression ForPath(Expression> destinationMember, Action> memberOptions) { @@ -66,7 +61,7 @@ public IMappingExpression ForPath(Expression(destinationMember, chain); + PathConfigurationExpression expression = new(destinationMember, chain); var firstMember = expression.MemberPath.First; var firstMemberConfig = GetDestinationMemberConfiguration(firstMember); if(firstMemberConfig == null) @@ -119,7 +114,7 @@ public IMappingExpression Include ForSourceMember(Expression> sourceMember, Action memberOptions) { var memberInfo = ReflectionHelper.FindProperty(sourceMember); - var srcConfig = new SourceMappingExpression(memberInfo); + SourceMappingExpression srcConfig = new(memberInfo); memberOptions(srcConfig); SourceMemberConfigurations.Add(srcConfig); return this; @@ -127,20 +122,20 @@ public IMappingExpression ForSourceMember(Expression() where T : TDestination => As(typeof(T)); public IMappingExpression AddTransform(Expression> transformer) { - var config = new ValueTransformerConfiguration(typeof(TValue), transformer); + ValueTransformerConfiguration config = new(typeof(TValue), transformer); ValueTransformers.Add(config); return this; } public IMappingExpression ReverseMap() { - var reverseMap = new MappingExpression(MemberList.None, DestinationType, SourceType){ IsReverseMap = true }; + MappingExpression reverseMap = new(MemberList.None, Types.Reverse()){ IsReverseMap = true }; ReverseMapCore(reverseMap); reverseMap.IncludeMembersCore(MapToSourceMembers().Select(m => m.GetDestinationExpression()).ToArray()); return reverseMap; } private IMappingExpression ForDestinationMember(MemberInfo destinationProperty, Action> memberOptions) { - var expression = new MemberConfigurationExpression(destinationProperty, SourceType); + MemberConfigurationExpression expression = new(destinationProperty, SourceType); MemberConfigurations.Add(expression); memberOptions(expression); return this; diff --git a/src/AutoMapper/Configuration/MemberConfigurationExpression.cs b/src/AutoMapper/Configuration/MemberConfigurationExpression.cs index 46006fe492..3a2cd60c6d 100644 --- a/src/AutoMapper/Configuration/MemberConfigurationExpression.cs +++ b/src/AutoMapper/Configuration/MemberConfigurationExpression.cs @@ -8,17 +8,12 @@ public interface IPropertyMapConfiguration IPropertyMapConfiguration Reverse(); bool Ignored => false; } -public class MemberConfigurationExpression : IMemberConfigurationExpression, IPropertyMapConfiguration +public class MemberConfigurationExpression(MemberInfo destinationMember, Type sourceType) : IMemberConfigurationExpression, IPropertyMapConfiguration { private MemberInfo[] _sourceMembers; - private readonly Type _sourceType; - protected List> PropertyMapActions { get; } = new(); - public MemberConfigurationExpression(MemberInfo destinationMember, Type sourceType) - { - DestinationMember = destinationMember; - _sourceType = sourceType; - } - public MemberInfo DestinationMember { get; } + private readonly Type _sourceType = sourceType; + protected List> PropertyMapActions { get; } = []; + public MemberInfo DestinationMember { get; } = destinationMember; public void MapAtRuntime() => PropertyMapActions.Add(pm => pm.Inline = false); public void NullSubstitute(object nullSubstitute) => PropertyMapActions.Add(pm => pm.NullSubstitute = nullSubstitute); public void MapFrom() where TValueResolver : IValueResolver => @@ -31,9 +26,8 @@ public void MapFrom(Expression(string sourceMemberName) where TValueResolver : IMemberValueResolver => MapFromCore(null, sourceMemberName); private void MapFromCore(Expression> sourceMember, string sourceMemberName = null) where TValueResolver : IMemberValueResolver => - MapFromCore(new(typeof(TValueResolver), typeof(IMemberValueResolver)) + MapFromCore(new(typeof(TValueResolver), typeof(IMemberValueResolver), sourceMemberName) { - SourceMemberName = sourceMemberName, SourceMemberLambda = sourceMember }); public void MapFrom(IValueResolver valueResolver) => @@ -112,18 +106,16 @@ public void ConvertUsing(IValueConverter public void ConvertUsing(IValueConverter valueConverter, string sourceMemberName) => ConvertUsingCore(valueConverter, null, sourceMemberName); private void ConvertUsingCore(Expression> sourceMember = null, string sourceMemberName = null) => - ConvertUsingCore(new(typeof(TValueConverter), typeof(IValueConverter)) + ConvertUsingCore(new(typeof(TValueConverter), typeof(IValueConverter), sourceMemberName) { SourceMemberLambda = sourceMember, - SourceMemberName = sourceMemberName }); protected void ConvertUsingCore(ValueConverter converter) => SetResolver(converter); private void ConvertUsingCore(IValueConverter valueConverter, Expression> sourceMember = null, string sourceMemberName = null) => - ConvertUsingCore(new(valueConverter, typeof(IValueConverter)) + ConvertUsingCore(new(valueConverter, typeof(IValueConverter), sourceMemberName) { SourceMemberLambda = sourceMember, - SourceMemberName = sourceMemberName }); public void Configure(TypeMap typeMap) { @@ -154,7 +146,7 @@ public IPropertyMapConfiguration Reverse() { return null; } - var reversedMemberConfiguration = new MemberConfigurationExpression(_sourceMembers[0], destinationType); + MemberConfigurationExpression reversedMemberConfiguration = new(_sourceMembers[0], destinationType); reversedMemberConfiguration.MapFrom(DestinationMember.Name); return reversedMemberConfiguration; } @@ -166,30 +158,17 @@ public IPropertyMapConfiguration Reverse() } public void DoNotUseDestinationValue() => SetUseDestinationValue(false); } -public sealed class MemberConfigurationExpression : MemberConfigurationExpression, IMemberConfigurationExpression +public sealed class MemberConfigurationExpression(MemberInfo destinationMember, Type sourceType) : MemberConfigurationExpression(destinationMember, sourceType), IMemberConfigurationExpression { - public MemberConfigurationExpression(MemberInfo destinationMember, Type sourceType) : base(destinationMember, sourceType){} public void MapFrom(Type valueResolverType) => MapFromCore(new(valueResolverType, valueResolverType.GetGenericInterface(typeof(IValueResolver<,,>)))); public void MapFrom(Type valueResolverType, string sourceMemberName) => - MapFromCore(new(valueResolverType, valueResolverType.GetGenericInterface(typeof(IMemberValueResolver<,,,>))) - { - SourceMemberName = sourceMemberName - }); + MapFromCore(new(valueResolverType, valueResolverType.GetGenericInterface(typeof(IMemberValueResolver<,,,>)), sourceMemberName)); public void MapFrom(IMemberValueResolver resolver, string sourceMemberName) => - MapFromCore(new(resolver, typeof(IMemberValueResolver)) - { - SourceMemberName = sourceMemberName - }); + MapFromCore(new(resolver, typeof(IMemberValueResolver), sourceMemberName)); public void ConvertUsing(Type valueConverterType) => ConvertUsingCore(valueConverterType); public void ConvertUsing(Type valueConverterType, string sourceMemberName) => ConvertUsingCore(valueConverterType, sourceMemberName); public void ConvertUsing(IValueConverter valueConverter, string sourceMemberName) => - base.ConvertUsingCore(new(valueConverter, typeof(IValueConverter)) - { - SourceMemberName = sourceMemberName - }); + base.ConvertUsingCore(new(valueConverter, typeof(IValueConverter), sourceMemberName)); private void ConvertUsingCore(Type valueConverterType, string sourceMemberName = null) => - base.ConvertUsingCore(new(valueConverterType, valueConverterType.GetGenericInterface(typeof(IValueConverter<,>))) - { - SourceMemberName = sourceMemberName - }); + base.ConvertUsingCore(new(valueConverterType, valueConverterType.GetGenericInterface(typeof(IValueConverter<,>)), sourceMemberName)); } \ No newline at end of file diff --git a/src/AutoMapper/Configuration/PathConfigurationExpression.cs b/src/AutoMapper/Configuration/PathConfigurationExpression.cs index e20514ec46..ed6f944451 100644 --- a/src/AutoMapper/Configuration/PathConfigurationExpression.cs +++ b/src/AutoMapper/Configuration/PathConfigurationExpression.cs @@ -21,17 +21,12 @@ public interface IPathConfigurationExpression void Condition(Func, bool> condition); } public readonly record struct ConditionParameters(TSource Source, TDestination Destination, TMember SourceMember, TMember DestinationMember, ResolutionContext Context); -public sealed class PathConfigurationExpression : IPathConfigurationExpression, IPropertyMapConfiguration +public sealed class PathConfigurationExpression(LambdaExpression destinationExpression, Stack chain) : IPathConfigurationExpression, IPropertyMapConfiguration { - private readonly LambdaExpression _destinationExpression; + private readonly LambdaExpression _destinationExpression = destinationExpression; private LambdaExpression _sourceExpression; - List> PathMapActions { get; } = new(); - public PathConfigurationExpression(LambdaExpression destinationExpression, Stack chain) - { - _destinationExpression = destinationExpression; - MemberPath = new MemberPath(chain); - } - public MemberPath MemberPath { get; } + List> PathMapActions { get; } = []; + public MemberPath MemberPath { get; } = new(chain); public MemberInfo DestinationMember => MemberPath.Last; public void MapFrom(Expression> sourceExpression) => MapFromUntyped(sourceExpression); public void Ignore() => PathMapActions.Add(pm => pm.Ignored = true); @@ -58,10 +53,10 @@ internal static IPropertyMapConfiguration Create(LambdaExpression destination, L { return null; } - var reversed = new PathConfigurationExpression(destination, chain); + PathConfigurationExpression reversed = new(destination, chain); if (reversed.MemberPath.Length == 1) { - var reversedMemberExpression = new MemberConfigurationExpression(reversed.DestinationMember, typeof(TSource)); + MemberConfigurationExpression reversedMemberExpression = new(reversed.DestinationMember, typeof(TSource)); reversedMemberExpression.MapFromExpression(source); return reversedMemberExpression; } @@ -75,8 +70,7 @@ public void Condition(Func, PathMapActions.Add(pm => { Expression> expr = - (src, dest, srcMember, destMember, ctxt) => - condition(new ConditionParameters(src, dest, srcMember, destMember, ctxt)); + (src, dest, srcMember, destMember, ctxt) => condition(new(src, dest, srcMember, destMember, ctxt)); pm.Condition = expr; }); } \ No newline at end of file diff --git a/src/AutoMapper/Configuration/Profile.cs b/src/AutoMapper/Configuration/Profile.cs index 30b1f51899..ce79b32b0b 100644 --- a/src/AutoMapper/Configuration/Profile.cs +++ b/src/AutoMapper/Configuration/Profile.cs @@ -54,9 +54,9 @@ public interface IProfileConfiguration /// public class Profile : IProfileExpressionInternal, IProfileConfiguration { - private readonly List _prefixes = new() { "Get" }; - private readonly List _postfixes = new(); - private readonly List _typeMapConfigs = new(); + private readonly List _prefixes = ["Get"]; + private readonly List _postfixes = []; + private readonly List _typeMapConfigs = []; private readonly PrePostfixName _prePostfixName = new(); private ReplaceName _replaceName; private readonly MemberConfiguration _memberConfiguration; @@ -108,20 +108,20 @@ public INamingConvention DestinationMemberNamingConvention get => _memberConfiguration.DestinationNamingConvention; set => _memberConfiguration.DestinationNamingConvention = value; } - public List ValueTransformers => _valueTransformerConfigs ??= new(); + public List ValueTransformers => _valueTransformerConfigs ??= []; List IProfileExpressionInternal.Prefixes => _prefixes; List IProfileExpressionInternal.Postfixes => _postfixes; public void DisableConstructorMapping() => _constructorMappingEnabled = false; void IProfileExpressionInternal.ForAllMaps(Action configuration) { - _allTypeMapActions ??= new(); + _allTypeMapActions ??= []; _allTypeMapActions.Add(configuration); } void IProfileExpressionInternal.ForAllPropertyMaps(Func condition, Action configuration) { - _allPropertyMapActions ??= new(); + _allPropertyMapActions ??= []; _allPropertyMapActions.Add(new(condition, configuration)); } public IProjectionExpression CreateProjection() => @@ -134,7 +134,7 @@ public IMappingExpression CreateMap(memberList); private IMappingExpression CreateMapCore(MemberList memberList, bool projection = false) { - var mappingExp = new MappingExpression(memberList, projection); + MappingExpression mappingExp = new(memberList, projection); _typeMapConfigs.Add(mappingExp); return mappingExp; } @@ -144,12 +144,12 @@ public IMappingExpression CreateMap(Type sourceType, Type destinationType) => public IMappingExpression CreateMap(Type sourceType, Type destinationType, MemberList memberList) { - var types = new TypePair(sourceType, destinationType); - var map = new MappingExpression(types, memberList); + TypePair types = new(sourceType, destinationType); + MappingExpression map = new(memberList, types); _typeMapConfigs.Add(map); if (types.ContainsGenericParameters) { - _openTypeMapConfigs ??= new(); + _openTypeMapConfigs ??= []; _openTypeMapConfigs.Add(map); } return map; @@ -170,12 +170,12 @@ public void ReplaceMemberName(string original, string newValue) public void RecognizeDestinationPostfixes(params string[] postfixes) => _prePostfixName.DestinationPostfixes.TryAdd(postfixes); public void AddGlobalIgnore(string propertyNameStartingWith) { - _globalIgnores ??= new(); + _globalIgnores ??= []; _globalIgnores.Add(propertyNameStartingWith); } public void IncludeSourceExtensionMethods(Type type) { - _sourceExtensionMethods ??= new(); + _sourceExtensionMethods ??= []; _sourceExtensionMethods.AddRange( type.GetMethods(Internal.TypeExtensions.StaticFlags).Where(m => m.Has() && m.GetParameters().Length == 1)); } diff --git a/src/AutoMapper/Configuration/SourceMappingExpression.cs b/src/AutoMapper/Configuration/SourceMappingExpression.cs index e08b54fd42..dc42c755bf 100644 --- a/src/AutoMapper/Configuration/SourceMappingExpression.cs +++ b/src/AutoMapper/Configuration/SourceMappingExpression.cs @@ -1,5 +1,4 @@ namespace AutoMapper.Configuration; - public interface ISourceMemberConfiguration { void Configure(TypeMap typeMap); @@ -15,19 +14,14 @@ public interface ISourceMemberConfigurationExpression /// void DoNotValidate(); } -public sealed class SourceMappingExpression : ISourceMemberConfigurationExpression, ISourceMemberConfiguration +public sealed class SourceMappingExpression(MemberInfo sourceMember) : ISourceMemberConfigurationExpression, ISourceMemberConfiguration { - private readonly MemberInfo _sourceMember; - private readonly List> _sourceMemberActions = new List>(); - - public SourceMappingExpression(MemberInfo sourceMember) => _sourceMember = sourceMember; - - public void DoNotValidate() => _sourceMemberActions.Add(smc => smc.Ignore()); - + private readonly MemberInfo _sourceMember = sourceMember; + private readonly List> _sourceMemberActions = []; + public void DoNotValidate() => _sourceMemberActions.Add(smc => smc.Ignored = true); public void Configure(TypeMap typeMap) { var sourcePropertyConfig = typeMap.FindOrCreateSourceMemberConfigFor(_sourceMember); - foreach (var action in _sourceMemberActions) { action(sourcePropertyConfig); @@ -37,15 +31,9 @@ public void Configure(TypeMap typeMap) /// /// Contains member configuration relating to source members /// -public sealed class SourceMemberConfig +[EditorBrowsable(EditorBrowsableState.Never)] +public sealed class SourceMemberConfig(MemberInfo sourceMember) { - private bool _ignored; - - public SourceMemberConfig(MemberInfo sourceMember) => SourceMember = sourceMember; - - public MemberInfo SourceMember { get; } - - public void Ignore() => _ignored = true; - - public bool IsIgnored() => _ignored; + public MemberInfo SourceMember { get; } = sourceMember; + public bool Ignored { get; set; } } \ No newline at end of file diff --git a/src/AutoMapper/Configuration/TypeMapConfiguration.cs b/src/AutoMapper/Configuration/TypeMapConfiguration.cs index 173eecd099..c86f539bfa 100644 --- a/src/AutoMapper/Configuration/TypeMapConfiguration.cs +++ b/src/AutoMapper/Configuration/TypeMapConfiguration.cs @@ -1,23 +1,15 @@ using AutoMapper.Features; namespace AutoMapper.Configuration; [EditorBrowsable(EditorBrowsableState.Never)] -public abstract class TypeMapConfiguration +public abstract class TypeMapConfiguration(MemberList memberList, TypePair types) { private List _valueTransformers; private Features _features; private List _sourceMemberConfigurations; private List _ctorParamConfigurations; private List _memberConfigurations; - private readonly MemberList _memberList; - private readonly TypePair _types; - protected TypeMapConfiguration(MemberList memberList, Type sourceType, Type destinationType) : this(memberList, new TypePair(sourceType, destinationType)) - { - } - protected TypeMapConfiguration(MemberList memberList, TypePair types) - { - _memberList = memberList; - _types = types; - } + private readonly MemberList _memberList = memberList; + private readonly TypePair _types = types; public Type DestinationTypeOverride { get; protected set; } protected bool Projection { get; set; } public TypePair Types => _types; @@ -28,12 +20,12 @@ protected TypeMapConfiguration(MemberList memberList, TypePair types) public Type DestinationType => _types.DestinationType; public Features Features => _features ??= new(); public TypeMapConfiguration ReverseTypeMap => ReverseMapExpression; - public List ValueTransformers => _valueTransformers ??= new(); + public List ValueTransformers => _valueTransformers ??= []; protected TypeMapConfiguration ReverseMapExpression { get; set; } - protected List> TypeMapActions { get; } = new List>(); - protected List MemberConfigurations => _memberConfigurations ??= new(); - protected List SourceMemberConfigurations => _sourceMemberConfigurations ??= new(); - protected List CtorParamConfigurations => _ctorParamConfigurations ??= new(); + protected List> TypeMapActions { get; } = []; + protected List MemberConfigurations => _memberConfigurations ??= []; + protected List SourceMemberConfigurations => _sourceMemberConfigurations ??= []; + protected List CtorParamConfigurations => _ctorParamConfigurations ??= []; public void Configure(TypeMap typeMap, List sourceMembers) { TypeMap = typeMap; @@ -124,7 +116,7 @@ private void ConfigureReverseMap(TypeMap typeMap) } private void MapDestinationCtorToSource(TypeMap typeMap, List sourceMembers) { - sourceMembers ??= new(); + sourceMembers ??= []; ConstructorMap ctorMap = new(); typeMap.ConstructorMap = ctorMap; foreach (var destCtor in typeMap.DestinationConstructors) @@ -158,25 +150,28 @@ private void MapDestinationCtorToSource(TypeMap typeMap, List source bool IsConfigured(ParameterInfo parameter) => _ctorParamConfigurations?.Any(c => c.CtorParamName == parameter.Name) is true; } protected IEnumerable MapToSourceMembers() => - _memberConfigurations?.Where(m => m.SourceExpression != null && m.SourceExpression.Body == m.SourceExpression.Parameters[0]) ?? Array.Empty(); + _memberConfigurations?.Where(m => m.SourceExpression != null && m.SourceExpression.Body == m.SourceExpression.Parameters[0]) ?? []; private void ReverseIncludedMembers(TypeMap typeMap) { Stack chain = null; foreach (var includedMember in typeMap.IncludedMembers.Where(i => i.IsMemberPath(out chain))) { - var memberPath = new MemberPath(chain); var newSource = Parameter(typeMap.DestinationType, "source"); var customExpression = Lambda(newSource, newSource); - ReverseSourceMembers(memberPath, customExpression); + ReverseSourceMembers(new(chain), customExpression); } } private void ReverseSourceMembers(TypeMap typeMap) { - foreach (var propertyMap in typeMap.PropertyMaps.Where(p => p.SourceMembers.Length > 1 && !p.SourceMembers.Any(s => s is MethodInfo))) + foreach (var propertyMap in typeMap.PropertyMaps) { - var memberPath = new MemberPath(propertyMap.SourceMembers); + var sourceMembers = propertyMap.SourceMembers; + if(sourceMembers.Length <= 1 || Array.Exists(sourceMembers, m => m is MethodInfo)) + { + continue; + } var customExpression = propertyMap.DestinationMember.Lambda(); - ReverseSourceMembers(memberPath, customExpression); + ReverseSourceMembers(new(sourceMembers), customExpression); } } private void ReverseSourceMembers(MemberPath memberPath, LambdaExpression customExpression) @@ -186,9 +181,7 @@ private void ReverseSourceMembers(MemberPath memberPath, LambdaExpression custom var newDestination = Parameter(reverseTypeMap.DestinationType, "destination"); var path = memberPath.Members.Chain(newDestination); var forPathLambda = Lambda(path, newDestination); - var pathMap = reverseTypeMap.FindOrCreatePathMapFor(forPathLambda, memberPath, reverseTypeMap); - pathMap.MapFrom(customExpression); }); } @@ -199,19 +192,19 @@ protected void ForSourceMemberCore(string sourceMemberName, Action memberOptions) { - var srcConfig = new SourceMappingExpression(memberInfo); + SourceMappingExpression srcConfig = new(memberInfo); memberOptions(srcConfig); SourceMemberConfigurations.Add(srcConfig); } protected void IncludeCore(Type derivedSourceType, Type derivedDestinationType) { - var derivedTypes = new TypePair(derivedSourceType, derivedDestinationType); + TypePair derivedTypes = new(derivedSourceType, derivedDestinationType); derivedTypes.CheckIsDerivedFrom(_types); TypeMapActions.Add(tm => tm.IncludeDerivedTypes(derivedTypes)); } protected void IncludeBaseCore(Type sourceBase, Type destinationBase) { - var baseTypes = new TypePair(sourceBase, destinationBase); + TypePair baseTypes = new(sourceBase, destinationBase); _types.CheckIsDerivedFrom(baseTypes); TypeMapActions.Add(tm => tm.IncludeBaseTypes(baseTypes)); } @@ -232,12 +225,10 @@ public IPropertyMapConfiguration GetDestinationMemberConfiguration(MemberInfo de } protected abstract void IgnoreDestinationMember(MemberInfo property, bool ignorePaths = true); } -public abstract class MappingExpressionBase : TypeMapConfiguration, IMappingExpressionBase +public abstract class MappingExpressionBase(MemberList memberList, TypePair types) : TypeMapConfiguration(memberList, types), IMappingExpressionBase where TMappingExpression : class, IMappingExpressionBase { - protected MappingExpressionBase(MemberList memberList) : base(memberList, typeof(TSource), typeof(TDestination)){ } - protected MappingExpressionBase(MemberList memberList, Type sourceType, Type destinationType) : base(memberList, sourceType, destinationType){} - protected MappingExpressionBase(MemberList memberList, TypePair types) : base(memberList, types){} + protected MappingExpressionBase(MemberList memberList) : this(memberList, new(typeof(TSource), typeof(TDestination))){ } public void As(Type typeOverride) { if (typeOverride == DestinationType) @@ -351,7 +342,7 @@ public void ConvertUsing() where TTypeConverter : ITypeConverter SetTypeConverter(new ClassTypeConverter(typeof(TTypeConverter), typeof(ITypeConverter))); public TMappingExpression ForCtorParam(string ctorParamName, Action> paramOptions) { - var ctorParamExpression = new CtorParamConfigurationExpression(ctorParamName, SourceType); + CtorParamConfigurationExpression ctorParamExpression = new(ctorParamName, SourceType); paramOptions(ctorParamExpression); CtorParamConfigurations.Add(ctorParamExpression); return this as TMappingExpression; diff --git a/src/AutoMapper/ConstructorMap.cs b/src/AutoMapper/ConstructorMap.cs index 53d5d711ee..c8e990b967 100644 --- a/src/AutoMapper/ConstructorMap.cs +++ b/src/AutoMapper/ConstructorMap.cs @@ -3,7 +3,7 @@ public sealed class ConstructorMap { private bool? _canResolve; - private readonly List _ctorParams = new(); + private readonly List _ctorParams = []; public ConstructorInfo Ctor { get; private set; } public IReadOnlyCollection CtorParams => _ctorParams; public void Reset(ConstructorInfo ctor) @@ -76,7 +76,7 @@ public ConstructorParameterMap(TypeMap typeMap, ParameterInfo parameter, MemberI } else { - SourceMembers = Array.Empty(); + SourceMembers = []; } } public ParameterInfo Parameter { get; } diff --git a/src/AutoMapper/Execution/ExpressionBuilder.cs b/src/AutoMapper/Execution/ExpressionBuilder.cs index 46d55c34a8..3b30971569 100644 --- a/src/AutoMapper/Execution/ExpressionBuilder.cs +++ b/src/AutoMapper/Execution/ExpressionBuilder.cs @@ -6,7 +6,7 @@ namespace AutoMapper.Execution; [EditorBrowsable(EditorBrowsableState.Never)] public static class ExpressionBuilder { - public static readonly MethodInfo ObjectToString = typeof(object).GetMethod(nameof(object.ToString)); + public static readonly MethodInfo ObjectToString = typeof(object).GetMethod(nameof(ToString)); public static readonly Expression True = Constant(true, typeof(bool)); public static readonly Expression Null = Expression.Default(typeof(object)); public static readonly Expression Empty = Empty(); @@ -42,7 +42,7 @@ public static (List Variables, List Expressions var variables = configuration?.Variables; if (variables == null) { - variables = new(); + variables = []; } else { @@ -51,7 +51,7 @@ public static (List Variables, List Expressions var expressions = configuration?.Expressions; if (expressions == null) { - expressions = new(); + expressions = []; } else { @@ -180,12 +180,8 @@ public static Expression ApplyTransformers(this MemberMap memberMap, Expression var perMember = memberMap.ValueTransformers; var perMap = memberMap.TypeMap.ValueTransformers; var perProfile = memberMap.Profile.ValueTransformers; - var result = source; - if (perMember.Count > 0 || perMap.Count > 0 || perProfile.Count > 0) - { - result = memberMap.ApplyTransformers(source, configuration, perMember.Concat(perMap).Concat(perProfile)); - } - return result; + return perMember.Count > 0 || perMap.Count > 0 || perProfile.Count > 0 ? + memberMap.ApplyTransformers(source, configuration, perMember.Concat(perMap).Concat(perProfile)) : source; } static Expression ApplyTransformers(this MemberMap memberMap, Expression result, IGlobalConfiguration configuration, IEnumerable transformers) { @@ -234,7 +230,7 @@ public static MemberInfo[] ToMemberInfos(this Stack chain) } public static Stack GetChain(this Expression expression) { - var stack = new Stack(); + Stack stack = []; while (expression != null) { var member = expression switch @@ -256,14 +252,8 @@ public static Stack GetChain(this Expression expression) } return stack; } - public static IEnumerable GetMemberExpressions(this Expression expression) - { - if (expression is not MemberExpression memberExpression) - { - return Array.Empty(); - } - return expression.GetChain().Select(m => m.Expression as MemberExpression).TakeWhile(m => m != null); - } + public static IEnumerable GetMemberExpressions(this Expression expression) => expression is MemberExpression ? + expression.GetChain().Select(m => m.Expression as MemberExpression).TakeWhile(m => m != null) : []; public static bool IsMemberPath(this LambdaExpression lambda, out Stack members) { Expression currentExpression = null; diff --git a/src/AutoMapper/Execution/ObjectFactory.cs b/src/AutoMapper/Execution/ObjectFactory.cs index d66f8d450b..9ae8ae5c78 100644 --- a/src/AutoMapper/Execution/ObjectFactory.cs +++ b/src/AutoMapper/Execution/ObjectFactory.cs @@ -19,7 +19,7 @@ private static Func GenerateConstructor(Type type) => }; private static Expression CallConstructor(Type type, IGlobalConfiguration configuration) { - var defaultCtor = type.GetConstructor(Internal.TypeExtensions.InstanceFlags, null, Type.EmptyTypes, null); + var defaultCtor = type.GetConstructor(Internal.TypeExtensions.InstanceFlags, []); if (defaultCtor != null) { return New(defaultCtor); @@ -39,7 +39,7 @@ private static Expression CreateInterfaceExpression(Type type) => type.IsGenericType(typeof(ISet<>)) ? CreateCollection(type, typeof(HashSet<>)) : type.IsCollection() ? CreateCollection(type, typeof(List<>), GetIEnumerableArguments(type)) : InvalidType(type, $"Cannot create an instance of interface type {type}."); - private static Type[] GetIEnumerableArguments(Type type) => type.GetIEnumerableType()?.GenericTypeArguments ?? new[] { typeof(object) }; + private static Type[] GetIEnumerableArguments(Type type) => type.GetIEnumerableType()?.GenericTypeArguments ?? [typeof(object)]; private static Expression CreateCollection(Type type, Type collectionType, Type[] genericArguments = null) => ToType(New(collectionType.MakeGenericType(genericArguments ?? type.GenericTypeArguments)), type); private static Expression CreateReadOnlyDictionary(Type[] typeArguments) diff --git a/src/AutoMapper/Execution/ProxyGenerator.cs b/src/AutoMapper/Execution/ProxyGenerator.cs index 9b793db086..64956af715 100644 --- a/src/AutoMapper/Execution/ProxyGenerator.cs +++ b/src/AutoMapper/Execution/ProxyGenerator.cs @@ -4,10 +4,10 @@ namespace AutoMapper.Execution; public static class ProxyGenerator { - private static readonly MethodInfo DelegateCombine = typeof(Delegate).GetMethod(nameof(Delegate.Combine), new[] { typeof(Delegate), typeof(Delegate) }); + private static readonly MethodInfo DelegateCombine = typeof(Delegate).GetMethod(nameof(Delegate.Combine), [typeof(Delegate), typeof(Delegate)]); private static readonly MethodInfo DelegateRemove = typeof(Delegate).GetMethod(nameof(Delegate.Remove)); private static readonly EventInfo PropertyChanged = typeof(INotifyPropertyChanged).GetEvent(nameof(INotifyPropertyChanged.PropertyChanged)); - private static readonly ConstructorInfo ProxyBaseCtor = typeof(ProxyBase).GetConstructor(Type.EmptyTypes); + private static readonly ConstructorInfo ProxyBaseCtor = typeof(ProxyBase).GetConstructor([]); private static readonly ModuleBuilder ProxyModule = CreateProxyModule(); private static readonly LockingConcurrentDictionary ProxyTypes = new(EmitProxy); private static ModuleBuilder CreateProxyModule() @@ -34,11 +34,11 @@ TypeBuilder GenerateType() var propertyNames = string.Join("_", typeDescription.AdditionalProperties.Select(p => p.Name)); var typeName = $"Proxy_{interfaceType.FullName}_{typeDescription.GetHashCode()}_{propertyNames}"; const int MaxTypeNameLength = 1023; - typeName = typeName.Substring(0, Math.Min(MaxTypeNameLength, typeName.Length)); + typeName = typeName[..Math.Min(MaxTypeNameLength, typeName.Length)]; Debug.WriteLine(typeName, "Emitting proxy type"); return ProxyModule.DefineType(typeName, TypeAttributes.Class | TypeAttributes.Sealed | TypeAttributes.Public, typeof(ProxyBase), - interfaceType.IsInterface ? new[] { interfaceType } : Type.EmptyTypes); + interfaceType.IsInterface ? [interfaceType] : []); } void GeneratePropertyChanged() { @@ -65,7 +65,7 @@ void EventAccessor(MethodInfo method, MethodInfo delegateMethod) } void GenerateFields() { - var fieldBuilders = new Dictionary(); + Dictionary fieldBuilders = []; foreach (var property in PropertiesToImplement()) { if (fieldBuilders.TryGetValue(property.Name, out var propertyEmitter)) @@ -83,8 +83,8 @@ void GenerateFields() } List PropertiesToImplement() { - var propertiesToImplement = new List(); - var allInterfaces = new List(interfaceType.GetInterfaces()) { interfaceType }; + List propertiesToImplement = []; + List allInterfaces = [..interfaceType.GetInterfaces(), interfaceType]; // first we collect all properties, those with setters before getters in order to enable less specific redundant getters foreach (var property in allInterfaces.Where(intf => intf != typeof(INotifyPropertyChanged)) @@ -105,16 +105,16 @@ List PropertiesToImplement() } void GenerateConstructor() { - var constructorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, Type.EmptyTypes); + var constructorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, []); var ctorIl = constructorBuilder.GetILGenerator(); ctorIl.Emit(OpCodes.Ldarg_0); ctorIl.Emit(OpCodes.Call, ProxyBaseCtor); ctorIl.Emit(OpCodes.Ret); } } - public static Type GetProxyType(Type interfaceType) => ProxyTypes.GetOrAdd(new(interfaceType, Array.Empty())); + public static Type GetProxyType(Type interfaceType) => ProxyTypes.GetOrAdd(new(interfaceType, [])); public static Type GetSimilarType(Type sourceType, IEnumerable additionalProperties) => - ProxyTypes.GetOrAdd(new(sourceType, additionalProperties.OrderBy(p=>p.Name).ToArray())); + ProxyTypes.GetOrAdd(new(sourceType, [..additionalProperties.OrderBy(p => p.Name)])); class PropertyEmitter { private static readonly MethodInfo ProxyBaseNotifyPropertyChanged = typeof(ProxyBase).GetInstanceMethod("NotifyPropertyChanged"); @@ -142,7 +142,7 @@ public PropertyEmitter(TypeBuilder owner, PropertyDescription property, FieldBui } _setterBuilder = owner.DefineMethod($"set_{name}", MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig | - MethodAttributes.SpecialName, typeof(void), new[] { propertyType }); + MethodAttributes.SpecialName, typeof(void), [propertyType]); ILGenerator setterIl = _setterBuilder.GetILGenerator(); setterIl.Emit(OpCodes.Ldarg_0); setterIl.Emit(OpCodes.Ldarg_1); @@ -164,8 +164,7 @@ public PropertyEmitter(TypeBuilder owner, PropertyDescription property, FieldBui public abstract class ProxyBase { public ProxyBase() { } - protected void NotifyPropertyChanged(PropertyChangedEventHandler handler, string method) => - handler?.Invoke(this, new PropertyChangedEventArgs(method)); + protected void NotifyPropertyChanged(PropertyChangedEventHandler handler, string method) => handler?.Invoke(this, new(method)); } public readonly record struct TypeDescription(Type Type, PropertyDescription[] AdditionalProperties) { diff --git a/src/AutoMapper/Execution/TypeMapPlanBuilder.cs b/src/AutoMapper/Execution/TypeMapPlanBuilder.cs index 6cfc920c9b..6de44c6fcb 100644 --- a/src/AutoMapper/Execution/TypeMapPlanBuilder.cs +++ b/src/AutoMapper/Execution/TypeMapPlanBuilder.cs @@ -1,32 +1,20 @@ namespace AutoMapper.Execution; -public ref struct TypeMapPlanBuilder +public ref struct TypeMapPlanBuilder(IGlobalConfiguration configuration, TypeMap typeMap) { static readonly MethodInfo MappingError = typeof(TypeMapPlanBuilder).GetStaticMethod(nameof(MemberMappingError)); static readonly MethodInfo IncTypeDepthInfo = typeof(ResolutionContext).GetInstanceMethod(nameof(ResolutionContext.IncrementTypeDepth)); static readonly MethodInfo DecTypeDepthInfo = typeof(ResolutionContext).GetInstanceMethod(nameof(ResolutionContext.DecrementTypeDepth)); static readonly MethodInfo CacheDestinationMethod = typeof(ResolutionContext).GetInstanceMethod(nameof(ResolutionContext.CacheDestination)); static readonly MethodInfo GetDestinationMethod = typeof(ResolutionContext).GetInstanceMethod(nameof(ResolutionContext.GetDestination)); - readonly IGlobalConfiguration _configuration; - readonly ParameterExpression _destination; - readonly ParameterExpression _initialDestination; - readonly ParameterExpression[] _parameters; - readonly TypeMap _typeMap; - readonly ParameterExpression _source; - List _variables; - List _expressions; - CatchBlock[] _catches; - public TypeMapPlanBuilder(IGlobalConfiguration configuration, TypeMap typeMap) - { - _configuration = configuration; - _typeMap = typeMap; - _source = Parameter(typeMap.SourceType, "source"); - _initialDestination = Parameter(typeMap.DestinationType, "destination"); - _destination = Variable(typeMap.DestinationType, "typeMapDestination"); - _variables = configuration.Variables; - _expressions = configuration.Expressions; - _catches = configuration.Catches; - _parameters = _configuration.Parameters ?? new ParameterExpression[] { null, null, ContextParameter }; - } + readonly IGlobalConfiguration _configuration = configuration; + readonly ParameterExpression _destination = Variable(typeMap.DestinationType, "typeMapDestination"); + readonly ParameterExpression _initialDestination = Parameter(typeMap.DestinationType, "destination"); + readonly ParameterExpression[] _parameters = configuration.Parameters ?? [null, null, ContextParameter]; + readonly TypeMap _typeMap = typeMap; + readonly ParameterExpression _source = Parameter(typeMap.SourceType, "source"); + List _variables = configuration.Variables; + List _expressions = configuration.Expressions; + CatchBlock[] _catches = configuration.Catches; public Type DestinationType => _destination.Type; private static AutoMapperMappingException MemberMappingError(Exception innerException, MemberMap memberMap) => new("Error mapping types.", innerException, memberMap); ParameterExpression[] GetParameters(ParameterExpression first = null, ParameterExpression second = null) @@ -43,9 +31,9 @@ public LambdaExpression CreateMapperLambda() { return Lambda(customExpression, parameters); } - _variables ??= new(); - _expressions ??= new(); - _catches ??= new CatchBlock[1]; + _variables ??= []; + _expressions ??= []; + _catches ??= [null]; var typeMapsPath = _configuration.TypeMapsPath; Clear(ref typeMapsPath); CheckForCycles(_configuration, _typeMap, typeMapsPath); @@ -71,7 +59,7 @@ static void Clear(ref HashSet typeMapsPath) { if (typeMapsPath == null) { - typeMapsPath = new HashSet(); + typeMapsPath = []; } else { @@ -169,7 +157,7 @@ private Expression CreateDestinationFunc() Expression ReplaceParameters(LambdaExpression lambda) => _configuration.ReplaceParameters(lambda, GetParameters()); private Expression CreateAssignmentFunc(Expression createDestination) { - List actions = new() { createDestination }; + List actions = [createDestination]; Expression typeMapExpression = null; var hasMaxDepth = _typeMap.MaxDepth > 0; if (hasMaxDepth) @@ -299,8 +287,8 @@ private Expression CheckReferencesCache(Expression valueBuilder) }; private Expression ConstructorMapping(ConstructorMap constructorMap) { - List variables = new(); - List body = new(); + List variables = []; + List body = []; foreach (var parameter in constructorMap.CtorParams) { var variable = Variable(parameter.DestinationType, parameter.DestinationName); @@ -357,7 +345,7 @@ private Expression CreatePropertyMapFunc(MemberMap memberMap, Expression destina if (memberMap.Condition != null) { _expressions.Add(IfThen( - _configuration.ConvertReplaceParameters(memberMap.Condition, new[] { customSource, _destination, mappedMemberVariable, destinationMemberGetter, ContextParameter }), + _configuration.ConvertReplaceParameters(memberMap.Condition, [customSource, _destination, mappedMemberVariable, destinationMemberGetter, ContextParameter]), mapperExpr)); } else if (!destinationMemberReadOnly) @@ -443,10 +431,9 @@ public interface IValueResolver LambdaExpression ProjectToExpression => null; IValueResolver CloseGenerics(TypeMap typeMap) => this; } -public class MemberPathResolver : IValueResolver +public class MemberPathResolver(MemberInfo[] members) : IValueResolver { - private readonly MemberInfo[] _members; - public MemberPathResolver(MemberInfo[] members) => _members = members; + private readonly MemberInfo[] _members = members; public Type ResolvedType => _members?[^1].GetMemberType(); public Expression GetExpression(IGlobalConfiguration configuration, MemberMap memberMap, Expression source, Expression destination, Expression destinationMember) { @@ -458,22 +445,19 @@ public Expression GetExpression(IGlobalConfiguration configuration, MemberMap me public IValueResolver CloseGenerics(TypeMap typeMap) => _members[0].DeclaringType.ContainsGenericParameters ? new MemberPathResolver(ReflectionHelper.GetMemberPath(typeMap.SourceType, Array.ConvertAll(_members, m => m.Name), typeMap)) : this; } -public abstract class LambdaValueResolver +public abstract class LambdaValueResolver(LambdaExpression lambda) { - public LambdaExpression Lambda { get; } + public LambdaExpression Lambda { get; } = lambda; public Type ResolvedType => Lambda.ReturnType; - protected LambdaValueResolver(LambdaExpression lambda) => Lambda = lambda; } -public class FuncResolver : LambdaValueResolver, IValueResolver +public class FuncResolver(LambdaExpression lambda) : LambdaValueResolver(lambda), IValueResolver { - public FuncResolver(LambdaExpression lambda) : base(lambda) { } public Expression GetExpression(IGlobalConfiguration configuration, MemberMap memberMap, Expression source, Expression destination, Expression destinationMember) => - configuration.ConvertReplaceParameters(Lambda, new[] { source, destination, destinationMember, ContextParameter }); + configuration.ConvertReplaceParameters(Lambda, [source, destination, destinationMember, ContextParameter]); public MemberInfo GetSourceMember(MemberMap _) => null; } -public class ExpressionResolver : LambdaValueResolver, IValueResolver +public class ExpressionResolver(LambdaExpression lambda) : LambdaValueResolver(lambda), IValueResolver { - public ExpressionResolver(LambdaExpression lambda) : base(lambda) { } public Expression GetExpression(IGlobalConfiguration configuration, MemberMap memberMap, Expression source, Expression _, Expression destinationMember) { var mapFrom = configuration.ReplaceParameters(Lambda, source); @@ -488,30 +472,22 @@ public Expression GetExpression(IGlobalConfiguration configuration, MemberMap me public MemberInfo GetSourceMember(MemberMap _) => Lambda.GetMember(); public LambdaExpression ProjectToExpression => Lambda; } -public abstract class ValueResolverConfig +[EditorBrowsable(EditorBrowsableState.Never)] +public abstract class ValueResolverConfig(Type concreteType, Type interfaceType, Expression instance, string sourceMemberName) { - private protected readonly Expression _instance; - public Type ConcreteType { get; } - public Type InterfaceType { get; } + private protected readonly Expression _instance = instance; + public Type ConcreteType { get; } = concreteType; + public Type InterfaceType { get; } = interfaceType; public LambdaExpression SourceMemberLambda { get; init; } - protected ValueResolverConfig(Type concreteType, Type interfaceType, Expression instance = null) - { - ConcreteType = concreteType; - InterfaceType = interfaceType; - _instance = instance; - } - protected ValueResolverConfig(object instance, Type interfaceType) - { - _instance = Constant(instance); - InterfaceType = interfaceType; - } - public string SourceMemberName { get; init; } + protected ValueResolverConfig(object instance, Type interfaceType, string sourceMemberName) : this(null, interfaceType, Constant(instance), sourceMemberName) { } + public string SourceMemberName { get; } = sourceMemberName; public Type ResolvedType => InterfaceType.GenericTypeArguments[^1]; } +[EditorBrowsable(EditorBrowsableState.Never)] public class ValueConverter : ValueResolverConfig, IValueResolver { - public ValueConverter(Type concreteType, Type interfaceType) : base(concreteType, interfaceType, ServiceLocator(concreteType)) { } - public ValueConverter(object instance, Type interfaceType) : base(instance, interfaceType) { } + public ValueConverter(Type concreteType, Type interfaceType, string sourceMemberName) : base(concreteType, interfaceType, ServiceLocator(concreteType), sourceMemberName) { } + public ValueConverter(object instance, Type interfaceType, string sourceMemberName) : base(instance, interfaceType, sourceMemberName) { } public Expression GetExpression(IGlobalConfiguration configuration, MemberMap memberMap, Expression source, Expression _, Expression destinationMember) { var sourceMemberType = InterfaceType.GenericTypeArguments[0]; @@ -533,10 +509,11 @@ AutoMapperConfigurationException BuildExceptionMessage() _ => memberMap.SourceMembers.Length == 1 ? memberMap.SourceMembers[0] : null }; } +[EditorBrowsable(EditorBrowsableState.Never)] public class ClassValueResolver : ValueResolverConfig, IValueResolver { - public ClassValueResolver(Type concreteType, Type interfaceType) : base(concreteType, interfaceType) { } - public ClassValueResolver(object instance, Type interfaceType) : base(instance, interfaceType) { } + public ClassValueResolver(Type concreteType, Type interfaceType, string sourceMemberName = null) : base(concreteType, interfaceType, null, sourceMemberName) { } + public ClassValueResolver(object instance, Type interfaceType, string sourceMemberName = null) : base(instance, interfaceType, sourceMemberName) { } public Expression GetExpression(IGlobalConfiguration configuration, MemberMap memberMap, Expression source, Expression destination, Expression destinationMember) { var typeMap = memberMap.TypeMap; @@ -572,34 +549,27 @@ public abstract class TypeConverter public virtual void CloseGenerics(TypeMapConfiguration openMapConfig, TypePair closedTypes) { } public virtual LambdaExpression ProjectToExpression => null; } -public class LambdaTypeConverter : TypeConverter +public class LambdaTypeConverter(LambdaExpression lambda) : TypeConverter { - public LambdaTypeConverter(LambdaExpression lambda) => Lambda = lambda; - public LambdaExpression Lambda { get; } + public LambdaExpression Lambda { get; } = lambda; public override Expression GetExpression(IGlobalConfiguration configuration, ParameterExpression[] parameters) => configuration.ConvertReplaceParameters(Lambda, parameters); } -public class ExpressionTypeConverter : LambdaTypeConverter +public class ExpressionTypeConverter(LambdaExpression lambda) : LambdaTypeConverter(lambda) { - public ExpressionTypeConverter(LambdaExpression lambda) : base(lambda){} public override LambdaExpression ProjectToExpression => Lambda; } -public class ClassTypeConverter : TypeConverter +public class ClassTypeConverter(Type converterType, Type converterInterface) : TypeConverter { - public ClassTypeConverter(Type converterType, Type converterInterface) - { - ConverterType = converterType; - ConverterInterface = converterInterface; - } - public Type ConverterType { get; private set; } - public Type ConverterInterface { get; } + public Type ConverterType { get; private set; } = converterType; + public Type ConverterInterface { get; } = converterInterface; public override Expression GetExpression(IGlobalConfiguration configuration, ParameterExpression[] parameters) => Call(ToType(ServiceLocator(ConverterType), ConverterInterface), "Convert", parameters); public override void CloseGenerics(TypeMapConfiguration openMapConfig, TypePair closedTypes) { - var typeParams = (openMapConfig.SourceType.IsGenericTypeDefinition ? closedTypes.SourceType.GenericTypeArguments : Type.EmptyTypes) - .Concat(openMapConfig.DestinationType.IsGenericTypeDefinition ? closedTypes.DestinationType.GenericTypeArguments : Type.EmptyTypes); + var typeParams = (openMapConfig.SourceType.IsGenericTypeDefinition ? closedTypes.SourceType.GenericTypeArguments : []) + .Concat(openMapConfig.DestinationType.IsGenericTypeDefinition ? closedTypes.DestinationType.GenericTypeArguments : []); var neededParameters = ConverterType.GenericParametersCount(); - ConverterType = ConverterType.MakeGenericType(typeParams.Take(neededParameters).ToArray()); + ConverterType = ConverterType.MakeGenericType([..typeParams.Take(neededParameters)]); } } \ No newline at end of file diff --git a/src/AutoMapper/Features.cs b/src/AutoMapper/Features.cs index 5af0626f09..d2672bf5f1 100644 --- a/src/AutoMapper/Features.cs +++ b/src/AutoMapper/Features.cs @@ -39,7 +39,7 @@ public void Set(TFeature feature) } else { - _features ??= new(); + _features ??= []; _features.Add(feature); } } diff --git a/src/AutoMapper/Internal/LockingConcurrentDictionary.cs b/src/AutoMapper/Internal/LockingConcurrentDictionary.cs index f88b58055f..5570e5b84c 100644 --- a/src/AutoMapper/Internal/LockingConcurrentDictionary.cs +++ b/src/AutoMapper/Internal/LockingConcurrentDictionary.cs @@ -1,14 +1,9 @@ using System.Collections.Concurrent; namespace AutoMapper.Internal; -public readonly struct LockingConcurrentDictionary +public readonly struct LockingConcurrentDictionary(Func valueFactory, int capacity = 31) { - private readonly Func> _valueFactory; - private readonly ConcurrentDictionary> _dictionary; - public LockingConcurrentDictionary(Func valueFactory, int capacity = 31) - { - _valueFactory = key => new(()=>valueFactory(key)); - _dictionary = new(Environment.ProcessorCount, capacity); - } + private readonly Func> _valueFactory = key => new(() => valueFactory(key)); + private readonly ConcurrentDictionary> _dictionary = new(Environment.ProcessorCount, capacity); public TValue GetOrAdd(in TKey key) => _dictionary.GetOrAdd(key, _valueFactory).Value; public bool IsDefault => _dictionary == null; } \ No newline at end of file diff --git a/src/AutoMapper/Internal/MemberPath.cs b/src/AutoMapper/Internal/MemberPath.cs index 5c87b3c43c..697060455a 100644 --- a/src/AutoMapper/Internal/MemberPath.cs +++ b/src/AutoMapper/Internal/MemberPath.cs @@ -2,7 +2,7 @@ [EditorBrowsable(EditorBrowsableState.Never)] public readonly record struct MemberPath(MemberInfo[] Members) { - public static readonly MemberPath Empty = new(Array.Empty()); + public static readonly MemberPath Empty = new(Members: []); public MemberPath(Stack members) : this(members.ToMemberInfos()){} public MemberInfo Last => Members[^1]; public MemberInfo First => Members[0]; @@ -10,7 +10,7 @@ public MemberPath(Stack members) : this(members.ToMemberInfos()){} public bool Equals(MemberPath other) => Members.SequenceEqual(other.Members); public override int GetHashCode() { - var hashCode = new HashCode(); + HashCode hashCode = new(); foreach(var member in Members) { hashCode.Add(member); @@ -33,5 +33,5 @@ public bool StartsWith(MemberPath path) } return true; } - public MemberPath Concat(IEnumerable memberInfos) => new(Members.Concat(memberInfos).ToArray()); + public MemberPath Concat(IEnumerable memberInfos) => new([..Members.Concat(memberInfos)]); } \ No newline at end of file diff --git a/src/AutoMapper/Internal/PrimitiveHelper.cs b/src/AutoMapper/Internal/PrimitiveHelper.cs index 7f1dd6b922..f71720b898 100644 --- a/src/AutoMapper/Internal/PrimitiveHelper.cs +++ b/src/AutoMapper/Internal/PrimitiveHelper.cs @@ -23,7 +23,7 @@ public static List TryAdd(this List list, IEnumerable values) return list; } public static ReadOnlyCollection ToReadOnly(this T item) where T : Expression => new ReadOnlyCollectionBuilder{ item }.ToReadOnlyCollection(); - public static IReadOnlyCollection NullCheck(this IReadOnlyCollection source) => source ?? Array.Empty(); + public static IReadOnlyCollection NullCheck(this IReadOnlyCollection source) => source ?? []; public static IEnumerable Concat(this IReadOnlyCollection collection, IReadOnlyCollection otherCollection) { if (otherCollection == null || otherCollection.Count == 0) diff --git a/src/AutoMapper/Internal/ReflectionHelper.cs b/src/AutoMapper/Internal/ReflectionHelper.cs index 8035ff856b..7d788f0db2 100644 --- a/src/AutoMapper/Internal/ReflectionHelper.cs +++ b/src/AutoMapper/Internal/ReflectionHelper.cs @@ -52,7 +52,7 @@ public static MemberInfo[] GetMemberPath(Type type, string[] memberNames, TypeMa var sourceDetails = typeMap?.SourceTypeDetails; if (sourceDetails != null && memberNames.Length == 1) { - return new[] { sourceDetails.GetMember(memberNames[0]) }; + return [sourceDetails.GetMember(memberNames[0])]; } var members = new MemberInfo[memberNames.Length]; Type previousType = type; diff --git a/src/AutoMapper/Internal/TypeDetails.cs b/src/AutoMapper/Internal/TypeDetails.cs index c3c07bbc90..d0d3cdb004 100644 --- a/src/AutoMapper/Internal/TypeDetails.cs +++ b/src/AutoMapper/Internal/TypeDetails.cs @@ -4,17 +4,14 @@ namespace AutoMapper.Internal; /// [DebuggerDisplay("{Type}")] [EditorBrowsable(EditorBrowsableState.Never)] -public sealed class TypeDetails +public sealed class TypeDetails(Type type, ProfileMap config) { + public Type Type { get; } = type; + public ProfileMap Config { get; } = config; private Dictionary _nameToMember; private ConstructorParameters[] _constructors; private MemberInfo[] _readAccessors; private MemberInfo[] _writeAccessors; - public TypeDetails(Type type, ProfileMap config) - { - Type = type; - Config = config; - } private ConstructorParameters[] GetConstructors() => GetConstructors(Type, Config).Where(c=>c.ParametersCount > 0).OrderByDescending(c => c.ParametersCount).ToArray(); public static IEnumerable GetConstructors(Type type, ProfileMap profileMap) => @@ -88,16 +85,11 @@ where targetType.IsInterface && targetType.ContainsGenericParameters select new GenericMethod(method, genericInterface)); } } - sealed class GenericMethod : MemberInfo + sealed class GenericMethod(MethodInfo genericMethod, Type genericInterface) : MemberInfo { - readonly MethodInfo _genericMethod; - readonly Type _genericInterface; + readonly MethodInfo _genericMethod = genericMethod; + readonly Type _genericInterface = genericInterface; MethodInfo _closedMethod = ObjectToString; - public GenericMethod(MethodInfo genericMethod, Type genericInterface) - { - _genericMethod = genericMethod; - _genericInterface = genericInterface; - } public MethodInfo Close() { if (_closedMethod == ObjectToString) @@ -135,12 +127,12 @@ public static string[] PossibleNames(string memberName, List prefixes, L continue; } var withoutPrefix = memberName[prefix.Length..]; - result ??= new(); + result ??= []; result.Add(withoutPrefix); PostFixes(ref result, postfixes, withoutPrefix); } PostFixes(ref result, postfixes, memberName); - return result == null ? Array.Empty() : result.ToArray(); + return result == null ? [] : [..result]; static void PostFixes(ref List result, List postfixes, string name) { foreach (var postfix in postfixes) @@ -149,13 +141,11 @@ static void PostFixes(ref List result, List postfixes, string na { continue; } - result ??= new(); + result ??= []; result.Add(name[..^postfix.Length]); } } } - public Type Type { get; } - public ProfileMap Config { get; } public MemberInfo[] ReadAccessors => _readAccessors ??= BuildReadAccessors(); public MemberInfo[] WriteAccessors => _writeAccessors ??= BuildWriteAccessors(); public ConstructorParameters[] Constructors => _constructors ??= GetConstructors(); @@ -169,7 +159,7 @@ private MemberInfo[] BuildReadAccessors() { members = members.Concat(GetFields(FieldReadable)); } - return members.ToArray(); + return [..members]; } private MemberInfo[] BuildWriteAccessors() { @@ -181,7 +171,7 @@ private MemberInfo[] BuildWriteAccessors() { members = members.Concat(GetFields(FieldWritable)); } - return members.ToArray(); + return [..members]; } private static bool PropertyReadable(PropertyInfo propertyInfo) => propertyInfo.CanRead; private static bool FieldReadable(FieldInfo fieldInfo) => true; diff --git a/src/AutoMapper/Internal/TypePair.cs b/src/AutoMapper/Internal/TypePair.cs index 039ebb78a5..5cd2506573 100644 --- a/src/AutoMapper/Internal/TypePair.cs +++ b/src/AutoMapper/Internal/TypePair.cs @@ -1,8 +1,8 @@ namespace AutoMapper.Internal; - [DebuggerDisplay("{RequestedTypes.SourceType.Name}, {RequestedTypes.DestinationType.Name} : {RuntimeTypes.SourceType.Name}, {RuntimeTypes.DestinationType.Name}")] public readonly record struct MapRequest(TypePair RequestedTypes, TypePair RuntimeTypes, MemberMap MemberMap) { + public MapRequest(TypePair types) : this(types, types, MemberMap.Instance) { } public bool Equals(MapRequest other) => RequestedTypes.Equals(other.RequestedTypes) && RuntimeTypes.Equals(other.RuntimeTypes); public override int GetHashCode() => HashCode.Combine(RequestedTypes, RuntimeTypes); } @@ -25,9 +25,10 @@ public TypePair CloseGenericTypes(TypePair closedTypes) } var closedSourceType = SourceType.IsGenericTypeDefinition ? SourceType.MakeGenericType(sourceArguments) : SourceType; var closedDestinationType = DestinationType.IsGenericTypeDefinition ? DestinationType.MakeGenericType(destinationArguments) : DestinationType; - return new TypePair(closedSourceType, closedDestinationType); + return new(closedSourceType, closedDestinationType); } + public TypePair Reverse() => new(DestinationType, SourceType); public Type ITypeConverter() => ContainsGenericParameters ? null : typeof(ITypeConverter<,>).MakeGenericType(SourceType, DestinationType); public TypePair GetTypeDefinitionIfGeneric() => new(GetTypeDefinitionIfGeneric(SourceType), GetTypeDefinitionIfGeneric(DestinationType)); - private static Type GetTypeDefinitionIfGeneric(Type type) => type.IsGenericType ? type.GetGenericTypeDefinition() : type; + static Type GetTypeDefinitionIfGeneric(Type type) => type.IsGenericType ? type.GetGenericTypeDefinition() : type; } \ No newline at end of file diff --git a/src/AutoMapper/Mapper.cs b/src/AutoMapper/Mapper.cs index fe823da7a0..a56b375786 100644 --- a/src/AutoMapper/Mapper.cs +++ b/src/AutoMapper/Mapper.cs @@ -141,6 +141,7 @@ public sealed class Mapper : IMapper, IInternalRuntimeMapper { private readonly IGlobalConfiguration _configuration; private readonly Factory _serviceCtor; + private readonly ResolutionContext _defaultContext; public Mapper(IConfigurationProvider configuration) : this(configuration, configuration.Internal().ServiceCtor) { } public Mapper(IConfigurationProvider configuration, Factory serviceCtor) { @@ -148,10 +149,9 @@ public Mapper(IConfigurationProvider configuration, Factory serviceCtor) ArgumentNullException.ThrowIfNull(serviceCtor); _configuration = (IGlobalConfiguration)configuration; _serviceCtor = serviceCtor; - DefaultContext = new(this); + _defaultContext = new(this); } - internal ResolutionContext DefaultContext { get; } - ResolutionContext IInternalRuntimeMapper.DefaultContext => DefaultContext; + ResolutionContext IInternalRuntimeMapper.DefaultContext => _defaultContext; Factory IInternalRuntimeMapper.ServiceCtor => _serviceCtor; public IConfigurationProvider ConfigurationProvider => _configuration; public TDestination Map(object source) => Map(source, default(TDestination)); @@ -160,14 +160,14 @@ public Mapper(IConfigurationProvider configuration, Factory serviceCtor) public TDestination Map(TSource source, Action> opts) => Map(source, default, opts); public TDestination Map(TSource source, TDestination destination) => - MapCore(source, destination, DefaultContext); + MapCore(source, destination, _defaultContext); public TDestination Map(TSource source, TDestination destination, Action> opts) => MapWithOptions(source, destination, opts); public object Map(object source, Type sourceType, Type destinationType) => Map(source, null, sourceType, destinationType); public object Map(object source, Type sourceType, Type destinationType, Action opts) => Map(source, null, sourceType, destinationType, opts); public object Map(object source, object destination, Type sourceType, Type destinationType) => - MapCore(source, destination, DefaultContext, sourceType, destinationType); + 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) diff --git a/src/AutoMapper/Mappers/CollectionMapper.cs b/src/AutoMapper/Mappers/CollectionMapper.cs index d53a9fb585..94be40d56d 100644 --- a/src/AutoMapper/Mappers/CollectionMapper.cs +++ b/src/AutoMapper/Mappers/CollectionMapper.cs @@ -54,7 +54,7 @@ Expression MapCollectionCore(Expression destExpression) Throw(Constant(new NotSupportedException($"Unknown collection. Consider a custom type converter from {sourceType} to {destinationType}.")), destinationType); } var itemParam = Parameter(sourceElementType, "item"); - var itemExpr = configuration.MapExpression(profileMap, new TypePair(sourceElementType, destinationElementType), itemParam); + var itemExpr = configuration.MapExpression(profileMap, new(sourceElementType, destinationElementType), itemParam); Expression destination, assignNewExpression; UseDestinationValue(); var (variables, statements) = configuration.Scratchpad(); @@ -141,11 +141,11 @@ Expression CheckContext() } } private static Expression CreateNameValueCollection(Expression sourceExpression) => - New(typeof(NameValueCollection).GetConstructor(new[] { typeof(NameValueCollection) }), sourceExpression); + New(typeof(NameValueCollection).GetConstructor([typeof(NameValueCollection)]), sourceExpression); static class ArrayMapper { private static readonly MethodInfo ToArrayMethod = typeof(Enumerable).GetStaticMethod("ToArray"); - private static readonly MethodInfo CopyToMethod = typeof(Array).GetMethod("CopyTo", new[] { typeof(Array), typeof(int) }); + private static readonly MethodInfo CopyToMethod = typeof(Array).GetMethod("CopyTo", [typeof(Array), typeof(int)]); private static readonly MethodInfo CountMethod = typeof(Enumerable).StaticGenericMethod("Count", parametersCount: 1); private static readonly MethodInfo MapMultidimensionalMethod = typeof(ArrayMapper).GetStaticMethod(nameof(MapMultidimensional)); private static readonly ParameterExpression Index = Variable(typeof(int), "destinationArrayIndex"); @@ -155,7 +155,7 @@ private static Array MapMultidimensional(Array source, Type destinationElementTy { var sourceElementType = source.GetType().GetElementType(); var destinationArray = Array.CreateInstance(destinationElementType, Enumerable.Range(0, source.Rank).Select(source.GetLength).ToArray()); - var filler = new MultidimensionalArrayFiller(destinationArray); + MultidimensionalArrayFiller filler = new(destinationArray); foreach (var item in source) { filler.NewValue(context.Map(item, null, sourceElementType, destinationElementType, null)); @@ -194,7 +194,7 @@ public static Expression MapToArray(IGlobalConfiguration configuration, ProfileM createDestination = Assign(destination, NewArrayBounds(destinationElementType, statements)); } var itemParam = Parameter(sourceElementType, "sourceItem"); - var itemExpr = configuration.MapExpression(profileMap, new TypePair(sourceElementType, destinationElementType), itemParam); + var itemExpr = configuration.MapExpression(profileMap, new(sourceElementType, destinationElementType), itemParam); var setItem = Assign(ArrayAccess(destination, IncrementIndex), itemExpr); variables.Clear(); statements.Clear(); @@ -239,15 +239,10 @@ bool MustMap(Type sourceType, Type destinationType) => !destinationType.IsAssign } } } -public class MultidimensionalArrayFiller +public readonly struct MultidimensionalArrayFiller(Array destination) { - private readonly int[] _indices; - private readonly Array _destination; - public MultidimensionalArrayFiller(Array destination) - { - _indices = new int[destination.Rank]; - _destination = destination; - } + private readonly int[] _indices = new int[destination.Rank]; + private readonly Array _destination = destination; public void NewValue(object value) { var dimension = _destination.Rank - 1; diff --git a/src/AutoMapper/Mappers/ConstructorMapper.cs b/src/AutoMapper/Mappers/ConstructorMapper.cs index 325214a724..23a5b70f83 100644 --- a/src/AutoMapper/Mappers/ConstructorMapper.cs +++ b/src/AutoMapper/Mappers/ConstructorMapper.cs @@ -3,7 +3,7 @@ public class ConstructorMapper : IObjectMapper { public bool IsMatch(TypePair context) => GetConstructor(context.SourceType, context.DestinationType) != null; private static ConstructorInfo GetConstructor(Type sourceType, Type destinationType) => - destinationType.GetConstructor(TypeExtensions.InstanceFlags, null, new[] { sourceType }, null); + destinationType.GetConstructor(TypeExtensions.InstanceFlags, null, [sourceType], null); public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) { var constructor = GetConstructor(sourceExpression.Type, destExpression.Type); diff --git a/src/AutoMapper/Mappers/ConversionOperatorMapper.cs b/src/AutoMapper/Mappers/ConversionOperatorMapper.cs index f5d38535ff..af727dd964 100644 --- a/src/AutoMapper/Mappers/ConversionOperatorMapper.cs +++ b/src/AutoMapper/Mappers/ConversionOperatorMapper.cs @@ -13,7 +13,7 @@ private MethodInfo GetConversionOperator(Type sourceType, Type destinationType) return sourceMethod; } } - return destinationType.GetMethod(_operatorName, TypeExtensions.StaticFlags, null, new[] { sourceType }, null); + return destinationType.GetMethod(_operatorName, TypeExtensions.StaticFlags, null, [sourceType], null); } public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) { diff --git a/src/AutoMapper/Mappers/ConvertMapper.cs b/src/AutoMapper/Mappers/ConvertMapper.cs index 1c3536e0d2..dfa8a9a24e 100644 --- a/src/AutoMapper/Mappers/ConvertMapper.cs +++ b/src/AutoMapper/Mappers/ConvertMapper.cs @@ -7,7 +7,7 @@ public bool IsMatch(TypePair types) => (types.SourceType == typeof(string) && ty public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) { - var convertMethod = typeof(Convert).GetMethod("To" + destExpression.Type.Name, new[] { sourceExpression.Type }); + var convertMethod = typeof(Convert).GetMethod("To" + destExpression.Type.Name, [sourceExpression.Type]); return Call(convertMethod, sourceExpression); } } \ No newline at end of file diff --git a/src/AutoMapper/Mappers/FromDynamicMapper.cs b/src/AutoMapper/Mappers/FromDynamicMapper.cs index b4056bb6ce..fabb11cd5f 100644 --- a/src/AutoMapper/Mappers/FromDynamicMapper.cs +++ b/src/AutoMapper/Mappers/FromDynamicMapper.cs @@ -27,8 +27,7 @@ private static object Map(object source, object destination, Type destinationTyp } private static object GetDynamically(string memberName, object target) { - var binder = Binder.GetMember(CSharpBinderFlags.None, memberName, null, - new[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) }); + var binder = Binder.GetMember(CSharpBinderFlags.None, memberName, null, [CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)]); var callsite = CallSite>.Create(binder); return callsite.Target(callsite, target); } diff --git a/src/AutoMapper/Mappers/KeyValueMapper.cs b/src/AutoMapper/Mappers/KeyValueMapper.cs index 70a867639c..2ab2eb447c 100644 --- a/src/AutoMapper/Mappers/KeyValueMapper.cs +++ b/src/AutoMapper/Mappers/KeyValueMapper.cs @@ -8,8 +8,8 @@ public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap p var sourceArguments = sourceExpression.Type.GenericTypeArguments; var destinationType = destExpression.Type; var destinationArguments = destinationType.GenericTypeArguments; - var keys = new TypePair(sourceArguments[0], destinationArguments[0]); - var values = new TypePair(sourceArguments[1], destinationArguments[1]); + TypePair keys = new(sourceArguments[0], destinationArguments[0]); + TypePair values = new(sourceArguments[1], destinationArguments[1]); var mapKeys = configuration.MapExpression(profileMap, keys, ExpressionBuilder.Property(sourceExpression, "Key")); var mapValues = configuration.MapExpression(profileMap, values, ExpressionBuilder.Property(sourceExpression, "Value")); return New(destinationType.GetConstructor(destinationArguments), mapKeys, mapValues); diff --git a/src/AutoMapper/Mappers/MapperRegistry.cs b/src/AutoMapper/Mappers/MapperRegistry.cs index 876dffd3a7..7d80eec611 100644 --- a/src/AutoMapper/Mappers/MapperRegistry.cs +++ b/src/AutoMapper/Mappers/MapperRegistry.cs @@ -2,8 +2,8 @@ namespace AutoMapper.Internal.Mappers; internal static class MapperRegistry { - public static List Mappers() => new(capacity: 18) - { + public static List Mappers() => + [ new CollectionMapper(),// matches IEnumerable, requires a setter, ICollection<> or IList new AssignableMapper(),// except collections, which are copied; most likely match new NullableSourceMapper(),// map from the underlying type @@ -18,9 +18,9 @@ internal static class MapperRegistry new ConstructorMapper(),// new Destination(source) new ConversionOperatorMapper("op_Implicit"),// implicit operator Destination or implicit operator Source new ConversionOperatorMapper("op_Explicit"),// explicit operator Destination or explicit operator Source - new FromStringDictionaryMapper(),// property values to typed object - new ToStringDictionaryMapper(),// typed object to property values new FromDynamicMapper(),// dynamic to typed object new ToDynamicMapper(),// typed object to dynamic - }; + new FromStringDictionaryMapper(),// property values to typed object + new ToStringDictionaryMapper(),// typed object to property values + ]; } \ No newline at end of file diff --git a/src/AutoMapper/Mappers/ParseStringMapper.cs b/src/AutoMapper/Mappers/ParseStringMapper.cs index 93cd16b351..7026d4d5d7 100644 --- a/src/AutoMapper/Mappers/ParseStringMapper.cs +++ b/src/AutoMapper/Mappers/ParseStringMapper.cs @@ -5,5 +5,5 @@ public class ParseStringMapper : IObjectMapper public bool IsMatch(TypePair context) => context.SourceType == typeof(string) && HasParse(context.DestinationType); static bool HasParse(Type type) => type == typeof(Guid) || type == typeof(TimeSpan) || type == typeof(DateTimeOffset); public Expression MapExpression(IGlobalConfiguration configuration, ProfileMap profileMap, MemberMap memberMap, Expression sourceExpression, Expression destExpression) => - Call(destExpression.Type.GetMethod("Parse", new[] { typeof(string) }), sourceExpression); + Call(destExpression.Type.GetMethod("Parse", [typeof(string)]), sourceExpression); } \ No newline at end of file diff --git a/src/AutoMapper/Mappers/StringToEnumMapper.cs b/src/AutoMapper/Mappers/StringToEnumMapper.cs index 4b13286e56..9044dd78be 100644 --- a/src/AutoMapper/Mappers/StringToEnumMapper.cs +++ b/src/AutoMapper/Mappers/StringToEnumMapper.cs @@ -28,7 +28,7 @@ internal static Expression CheckEnumMember(Expression sourceExpression, Type enu var enumToObject = Constant(Enum.ToObject(enumType, memberInfo.GetValue(null))); var attributeConstant = Constant(attributeValue); var (body, testValue) = comparison == null ? (attributeConstant, enumToObject) : (ToType(enumToObject, enumType), attributeConstant); - switchCases ??= new(); + switchCases ??= []; switchCases.Add(SwitchCase(body, testValue)); } return switchCases == null ? defaultExpression : Switch(sourceExpression, defaultExpression, comparison, switchCases); diff --git a/src/AutoMapper/Mappers/ToDynamicMapper.cs b/src/AutoMapper/Mappers/ToDynamicMapper.cs index 4fdae9eeba..4bf8c6c457 100644 --- a/src/AutoMapper/Mappers/ToDynamicMapper.cs +++ b/src/AutoMapper/Mappers/ToDynamicMapper.cs @@ -28,10 +28,10 @@ private static object Map(object source, object destination, Type destinationTyp private static void SetDynamically(string memberName, object target, object value) { var binder = Binder.SetMember(CSharpBinderFlags.None, memberName, null, - new[]{ + [ CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null), CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) - }); + ]); var callsite = CallSite>.Create(binder); callsite.Target(callsite, target, value); } diff --git a/src/AutoMapper/MemberMap.cs b/src/AutoMapper/MemberMap.cs index 2944a415ba..6a281f8c8a 100644 --- a/src/AutoMapper/MemberMap.cs +++ b/src/AutoMapper/MemberMap.cs @@ -6,8 +6,8 @@ namespace AutoMapper; public class MemberMap : IValueResolver { private protected Type _sourceType; - protected MemberMap(TypeMap typeMap = null) => TypeMap = typeMap; - internal static readonly MemberMap Instance = new(); + protected MemberMap(TypeMap typeMap) => TypeMap = typeMap; + internal static readonly MemberMap Instance = new(null); public TypeMap TypeMap { get; protected set; } public LambdaExpression CustomMapExpression => Resolver?.ProjectToExpression; public bool IsResolveConfigured => Resolver != null && Resolver != this; @@ -19,7 +19,7 @@ public void SetResolver(IValueResolver resolver) Ignored = false; } public virtual Type SourceType => _sourceType ??= GetSourceType(); - public virtual MemberInfo[] SourceMembers { get => Array.Empty(); set { } } + public virtual MemberInfo[] SourceMembers { get => []; set { } } public virtual IncludedMember IncludedMember { get => default; protected set { } } public virtual string DestinationName => default; public virtual Type DestinationType { get => default; protected set { } } @@ -36,7 +36,7 @@ public void SetResolver(IValueResolver resolver) public virtual LambdaExpression PreCondition { get => default; set { } } public virtual LambdaExpression Condition { get => default; set { } } public IValueResolver Resolver { get; protected set; } - public virtual IReadOnlyCollection ValueTransformers => Array.Empty(); + public virtual IReadOnlyCollection ValueTransformers => []; public MemberInfo SourceMember => Resolver?.GetSourceMember(this); public string GetSourceMemberName() => Resolver?.SourceMemberName ?? SourceMember?.Name; public bool MustUseDestination => UseDestinationValue is true || !CanBeSet; @@ -106,5 +106,5 @@ public static class ValueTransformerConfigurationExtensions /// Value transformer list /// Transformation expression public static void Add(this List valueTransformers, Expression> transformer) => - valueTransformers.Add(new ValueTransformerConfiguration(typeof(TValue), transformer)); + valueTransformers.Add(new(typeof(TValue), transformer)); } \ No newline at end of file diff --git a/src/AutoMapper/PathMap.cs b/src/AutoMapper/PathMap.cs index fef27fdd07..1f5f74afe6 100644 --- a/src/AutoMapper/PathMap.cs +++ b/src/AutoMapper/PathMap.cs @@ -1,7 +1,7 @@ namespace AutoMapper; [DebuggerDisplay("{DestinationExpression}")] [EditorBrowsable(EditorBrowsableState.Never)] -public sealed class PathMap : MemberMap +public sealed class PathMap(LambdaExpression destinationExpression, MemberPath memberPath, TypeMap typeMap) : MemberMap(typeMap) { public PathMap(PathMap pathMap, TypeMap typeMap, IncludedMember includedMember) : this(pathMap.DestinationExpression, pathMap.MemberPath, typeMap) { @@ -10,14 +10,9 @@ public PathMap(PathMap pathMap, TypeMap typeMap, IncludedMember includedMember) Condition = pathMap.Condition; Ignored = pathMap.Ignored; } - public PathMap(LambdaExpression destinationExpression, MemberPath memberPath, TypeMap typeMap) : base(typeMap) - { - MemberPath = memberPath; - DestinationExpression = destinationExpression; - } public override Type SourceType => Resolver.ResolvedType; - public LambdaExpression DestinationExpression { get; } - public MemberPath MemberPath { get; } + public LambdaExpression DestinationExpression { get; } = destinationExpression; + public MemberPath MemberPath { get; } = memberPath; public override Type DestinationType => MemberPath.Last.GetMemberType(); public override string DestinationName => MemberPath.ToString(); public override bool CanBeSet => ReflectionHelper.CanBeSet(MemberPath.Last); diff --git a/src/AutoMapper/ProfileMap.cs b/src/AutoMapper/ProfileMap.cs index 5b0ae92417..477892d079 100644 --- a/src/AutoMapper/ProfileMap.cs +++ b/src/AutoMapper/ProfileMap.cs @@ -5,7 +5,7 @@ namespace AutoMapper; [EditorBrowsable(EditorBrowsableState.Never)] public sealed class ProfileMap { - private static readonly HashSet EmptyHashSet = new(); + private static readonly HashSet EmptyHashSet = []; private TypeMapConfiguration[] _typeMapConfigs; private Dictionary _openTypeMapConfigs; private Dictionary _typeDetails; @@ -27,9 +27,17 @@ public ProfileMap(IProfileConfiguration profile, IGlobalConfigurationExpression ValueTransformers = profile.ValueTransformers.Concat(configuration?.ValueTransformers).ToArray(); var profileInternal = (IProfileExpressionInternal)profile; MemberConfiguration = profileInternal.MemberConfiguration; - MemberConfiguration.Merge(configuration.Internal()?.MemberConfiguration); + if(configuration == null) + { + MemberConfiguration.SourceNamingConvention ??= PascalCaseNamingConvention.Instance; + MemberConfiguration.DestinationNamingConvention ??= PascalCaseNamingConvention.Instance; + } + else + { + MemberConfiguration.Merge(configuration.Internal().MemberConfiguration); + } var globalIgnores = profile.GlobalIgnores.Concat(globalProfile?.GlobalIgnores); - GlobalIgnores = globalIgnores == Array.Empty() ? EmptyHashSet : new HashSet(globalIgnores); + GlobalIgnores = globalIgnores == Array.Empty() ? EmptyHashSet : [..globalIgnores]; SourceExtensionMethods = profile.SourceExtensionMethods.Concat(globalProfile?.SourceExtensionMethods).ToArray(); AllPropertyMapActions = profile.AllPropertyMapActions.Concat(globalProfile?.AllPropertyMapActions).ToArray(); AllTypeMapActions = profile.AllTypeMapActions.Concat(globalProfile?.AllTypeMapActions).ToArray(); @@ -93,8 +101,8 @@ internal void Clear() public HashSet GlobalIgnores { get; } public MemberConfiguration MemberConfiguration { get; } public IEnumerable SourceExtensionMethods { get; } - public List Prefixes { get; } = new(); - public List Postfixes { get; } = new(); + public List Prefixes { get; } = []; + public List Postfixes { get; } = []; public IReadOnlyCollection ValueTransformers { get; } public TypeDetails CreateTypeDetails(Type type) { @@ -129,7 +137,7 @@ public void Register(IGlobalConfiguration configuration) private void BuildTypeMap(IGlobalConfiguration configuration, TypeMapConfiguration config) { var sourceMembers = configuration.SourceMembers; - var typeMap = new TypeMap(config.SourceType, config.DestinationType, this, config, sourceMembers); + TypeMap typeMap = new(config.SourceType, config.DestinationType, this, config, sourceMembers); config.Configure(typeMap, sourceMembers); configuration.RegisterTypeMap(typeMap); } @@ -182,25 +190,26 @@ private void Configure(TypeMap typeMap, IGlobalConfiguration configuration) if (typeMap.HasTypeConverter) { return; - } - foreach (var action in AllTypeMapActions) + } + MappingExpression expression = new(typeMap); + foreach(var action in AllTypeMapActions) { - var expression = new MappingExpression(typeMap); action(typeMap, expression); - expression.Configure(typeMap, configuration.SourceMembers); - } - foreach (var action in AllPropertyMapActions) - { - foreach (var propertyMap in typeMap.PropertyMaps) + } + expression.Configure(typeMap, configuration.SourceMembers); + foreach(var propertyMap in typeMap.PropertyMaps) + { + MemberConfigurationExpression memberExpression = null; + foreach(var action in AllPropertyMapActions) { if (!action.Condition(propertyMap)) { continue; - } - var memberExpression = new MemberConfigurationExpression(propertyMap.DestinationMember, typeMap.SourceType); + } + memberExpression ??= new(propertyMap.DestinationMember, typeMap.SourceType); action.Action(propertyMap, memberExpression); - memberExpression.Configure(typeMap); - } + } + memberExpression?.Configure(typeMap); } ApplyBaseMaps(typeMap, typeMap, configuration); ApplyDerivedMaps(typeMap, typeMap, configuration); @@ -211,7 +220,7 @@ public TypeMap CreateClosedGenericTypeMap(TypeMapConfiguration openMapConfig, Ty TypeMap closedMap; lock (configuration) { - closedMap = new TypeMap(closedTypes.SourceType, closedTypes.DestinationType, this, openMapConfig); + closedMap = new(closedTypes.SourceType, closedTypes.DestinationType, this, openMapConfig); } openMapConfig.Configure(closedMap, configuration.SourceMembers); Configure(closedMap, configuration); @@ -236,7 +245,7 @@ private void ApplyMemberMaps(TypeMap currentMap, IGlobalConfiguration configurat foreach (var includedMemberExpression in currentMap.GetAllIncludedMembers()) { var includedMap = configuration.GetIncludedTypeMap(includedMemberExpression.Body.Type, currentMap.DestinationType); - var includedMember = new IncludedMember(includedMap, includedMemberExpression); + IncludedMember includedMember = new(includedMap, includedMemberExpression); if (currentMap.AddMemberMap(includedMember)) { ApplyMemberMaps(includedMap, configuration); @@ -262,19 +271,10 @@ public bool MapDestinationPropertyToSource(TypeDetails sourceTypeDetails, Type d } [EditorBrowsable(EditorBrowsableState.Never)] [DebuggerDisplay("{MemberExpression}, {TypeMap}")] -public class IncludedMember : IEquatable +public sealed record IncludedMember(TypeMap TypeMap, LambdaExpression MemberExpression, ParameterExpression Variable, LambdaExpression ProjectToCustomSource) { public IncludedMember(TypeMap typeMap, LambdaExpression memberExpression) : this(typeMap, memberExpression, - Variable(memberExpression.Body.Type, string.Join("", memberExpression.GetMembersChain().Select(m => m.Name))), memberExpression) - { - } - private IncludedMember(TypeMap typeMap, LambdaExpression memberExpression, ParameterExpression variable, LambdaExpression projectToCustomSource) - { - TypeMap = typeMap; - MemberExpression = memberExpression; - Variable = variable; - ProjectToCustomSource = projectToCustomSource; - } + Expression.Variable(memberExpression.Body.Type, string.Join("", memberExpression.GetMembersChain().Select(m => m.Name))), memberExpression){} public IncludedMember Chain(IncludedMember other, IGlobalConfiguration configuration = null) { if (other == null) @@ -285,12 +285,8 @@ public IncludedMember Chain(IncludedMember other, IGlobalConfiguration configura } public static LambdaExpression Chain(LambdaExpression customSource, LambdaExpression lambda) => Lambda(lambda.ReplaceParameters(customSource.Body), customSource.Parameters); - public TypeMap TypeMap { get; } - public LambdaExpression MemberExpression { get; } - public ParameterExpression Variable { get; } - public LambdaExpression ProjectToCustomSource { get; } public LambdaExpression Chain(LambdaExpression lambda) => Chain(lambda, null, null); - public LambdaExpression Chain(LambdaExpression lambda, IncludedMember includedMember, IGlobalConfiguration configuration) => + LambdaExpression Chain(LambdaExpression lambda, IncludedMember includedMember, IGlobalConfiguration configuration) => Lambda(lambda.ReplaceParameters(Variable).NullCheck(configuration, includedMember: includedMember), lambda.Parameters); public bool Equals(IncludedMember other) => TypeMap == other?.TypeMap; public override int GetHashCode() => TypeMap.GetHashCode(); diff --git a/src/AutoMapper/PropertyMap.cs b/src/AutoMapper/PropertyMap.cs index 6ac0ee9598..617bd98f04 100644 --- a/src/AutoMapper/PropertyMap.cs +++ b/src/AutoMapper/PropertyMap.cs @@ -30,7 +30,7 @@ public PropertyMap(PropertyMap includedMemberMap, TypeMap typeMap, IncludedMembe public MemberInfo DestinationMember { get; } public override string DestinationName => DestinationMember?.Name; public override Type DestinationType { get; protected set; } - public override MemberInfo[] SourceMembers { get; set; } = Array.Empty(); + public override MemberInfo[] SourceMembers { get; set; } = []; public override bool CanBeSet => DestinationMember.CanBeSet(); public override bool Ignored { get; set; } public void ApplyInheritedPropertyMap(PropertyMap inheritedMap) @@ -73,13 +73,13 @@ public void ApplyInheritedPropertyMap(MemberMapDetails inheritedMappedProperty) ExplicitExpansion ??= inheritedMappedProperty.ExplicitExpansion; if (inheritedMappedProperty.ValueTransformers != null) { - ValueTransformers ??= new(); + ValueTransformers ??= []; ValueTransformers.InsertRange(0, inheritedMappedProperty.ValueTransformers); } } public void AddValueTransformation(ValueTransformerConfiguration valueTransformerConfiguration) { - ValueTransformers ??= new(); + ValueTransformers ??= []; ValueTransformers.Add(valueTransformerConfiguration); } } diff --git a/src/AutoMapper/QueryableExtensions/Extensions.cs b/src/AutoMapper/QueryableExtensions/Extensions.cs index 6ecb99e1fa..c1d3b276e6 100644 --- a/src/AutoMapper/QueryableExtensions/Extensions.cs +++ b/src/AutoMapper/QueryableExtensions/Extensions.cs @@ -74,12 +74,12 @@ static IQueryable ToCore(this IQueryable source, Type destinationType, IConfigur } public sealed class MemberVisitor : ExpressionVisitor { - private readonly List _members = new(); + private readonly List _members = []; public static MemberInfo[] GetMemberPath(Expression expression) { - var memberVisitor = new MemberVisitor(); + MemberVisitor memberVisitor = new(); memberVisitor.Visit(expression); - return memberVisitor._members.ToArray(); + return [.. memberVisitor._members]; } protected override Expression VisitMember(MemberExpression node) { diff --git a/src/AutoMapper/QueryableExtensions/ProjectionBuilder.cs b/src/AutoMapper/QueryableExtensions/ProjectionBuilder.cs index eddd8224b9..835b69e1a2 100644 --- a/src/AutoMapper/QueryableExtensions/ProjectionBuilder.cs +++ b/src/AutoMapper/QueryableExtensions/ProjectionBuilder.cs @@ -18,14 +18,7 @@ public interface IProjectionMapper public sealed class ProjectionBuilder : IProjectionBuilder { internal static List DefaultProjectionMappers() => - new(capacity: 5) - { - new AssignableProjectionMapper(), - new EnumerableProjectionMapper(), - new NullableSourceProjectionMapper(), - new StringProjectionMapper(), - new EnumProjectionMapper(), - }; + [new AssignableProjectionMapper(), new EnumerableProjectionMapper(), new NullableSourceProjectionMapper(), new StringProjectionMapper(), new EnumProjectionMapper()]; readonly LockingConcurrentDictionary _projectionCache; readonly IGlobalConfiguration _configuration; readonly IProjectionMapper[] _projectionMappers; @@ -37,7 +30,7 @@ public ProjectionBuilder(IGlobalConfiguration configuration, IProjectionMapper[] } public QueryExpressions GetProjection(Type sourceType, Type destinationType, object parameters, MemberPath[] membersToExpand) { - var projectionRequest = new ProjectionRequest(sourceType, destinationType, membersToExpand, Array.Empty()); + ProjectionRequest projectionRequest = new(sourceType, destinationType, membersToExpand, []); var cachedExpressions = _projectionCache.GetOrAdd(projectionRequest); if (parameters == null && !_configuration.EnableNullPropagationForQueryMapping) { @@ -48,7 +41,7 @@ public QueryExpressions GetProjection(Type sourceType, Type destinationType, obj QueryExpressions CreateProjection(ProjectionRequest request) { var (typeMap, polymorphicMaps) = PolymorphicMaps(request); - var letPropertyMaps = polymorphicMaps.Length > 0 ? new LetPropertyMaps(_configuration, MemberPath.Empty, new()) : new FirstPassLetPropertyMaps(_configuration, MemberPath.Empty, new()); + var letPropertyMaps = polymorphicMaps.Length > 0 ? new LetPropertyMaps(_configuration, MemberPath.Empty, []) : new FirstPassLetPropertyMaps(_configuration, MemberPath.Empty, []); return CreateProjection(request, letPropertyMaps, typeMap, polymorphicMaps); } (TypeMap, TypeMap[]) PolymorphicMaps(in ProjectionRequest request) @@ -88,7 +81,7 @@ Expression CreateProjectionCore(ProjectionRequest request, LetPropertyMaps letPr { return customProjection; } - var propertiesProjections = new List(); + List propertiesProjections = []; int depth; if(OverMaxDepth()) { @@ -126,7 +119,7 @@ void ProjectProperties() } Expression TryProjectMember(MemberMap memberMap, Expression defaultSource = null) { - var memberProjection = new MemberProjection(memberMap); + MemberProjection memberProjection = new(memberMap); letPropertyMaps.Push(memberProjection); var memberExpression = ShouldExpand() ? ProjectMemberCore() : null; letPropertyMaps.Pop(); @@ -225,13 +218,12 @@ IProjectionMapper GetProjectionMapper() $"Unable to create a map expression from {memberMap.SourceMember?.DeclaringType?.Name}.{memberMap.SourceMember?.Name} ({sourceType}) to {memberMap.DestinationType.Name}.{memberMap.DestinationName} ({memberMap.DestinationType})", null, memberMap); [EditorBrowsable(EditorBrowsableState.Never)] - sealed class FirstPassLetPropertyMaps : LetPropertyMaps + sealed class FirstPassLetPropertyMaps(IGlobalConfiguration configuration, MemberPath parentPath, TypePairCount builtProjections) : LetPropertyMaps(configuration, parentPath, builtProjections) { - readonly List _savedPaths = new(); - public FirstPassLetPropertyMaps(IGlobalConfiguration configuration, MemberPath parentPath, TypePairCount builtProjections) : base(configuration, parentPath, builtProjections) { } + readonly List _savedPaths = []; public override Expression GetSubQueryMarker(LambdaExpression letExpression) { - var subQueryPath = new SubQueryPath(_currentPath.Reverse().ToArray(), letExpression); + SubQueryPath subQueryPath = new([.._currentPath.Reverse()], letExpression); var existingPath = _savedPaths.SingleOrDefault(s => s.IsEquivalentTo(subQueryPath)); if (existingPath.Marker != null) { @@ -259,7 +251,7 @@ public override QueryExpressions GetSubQueryExpression(ProjectionBuilder builder } var secondParameter = Parameter(letType, "dtoLet"); ReplaceSubQueries(); - var letClause = builder.CreateProjection(request, base.New(), letTypeMap, Array.Empty(), instanceParameter); + var letClause = builder.CreateProjection(request, base.New(), letTypeMap, [], instanceParameter); return new(Lambda(projection, secondParameter), Lambda(letClause, instanceParameter)); void ReplaceSubQueries() { @@ -290,11 +282,10 @@ public Expression GetSourceExpression(Expression parameter) internal bool IsEquivalentTo(SubQueryPath other) => LetExpression == other.LetExpression && Members.Length == other.Members.Length && Members.Take(Members.Length - 1).Zip(other.Members, (left, right) => left.MemberMap == right.MemberMap).All(item => item); } - sealed class GePropertiesVisitor : ExpressionVisitor + sealed class GePropertiesVisitor(Expression target) : ExpressionVisitor { - readonly Expression _target; - public List Members { get; } = new(); - public GePropertiesVisitor(Expression target) => _target = target; + readonly Expression _target = target; + public List Members { get; } = []; protected override Expression VisitMember(MemberExpression node) { if(node.Expression == _target) @@ -305,19 +296,14 @@ protected override Expression VisitMember(MemberExpression node) } public static IEnumerable Retrieve(Expression expression, Expression target) { - var visitor = new GePropertiesVisitor(target); + GePropertiesVisitor visitor = new(target); visitor.Visit(expression); return visitor.Members.Select(member => new PropertyDescription(member.Name, member.GetMemberType())); } } - sealed class ReplaceMemberAccessesVisitor : ExpressionVisitor + sealed class ReplaceMemberAccessesVisitor(Expression oldObject, Expression newObject) : ExpressionVisitor { - readonly Expression _oldObject, _newObject; - public ReplaceMemberAccessesVisitor(Expression oldObject, Expression newObject) - { - _oldObject = oldObject; - _newObject = newObject; - } + readonly Expression _oldObject = oldObject, _newObject = newObject; protected override Expression VisitMember(MemberExpression node) { if(node.Expression != _oldObject) @@ -332,7 +318,7 @@ protected override Expression VisitMember(MemberExpression node) [EditorBrowsable(EditorBrowsableState.Never)] public class LetPropertyMaps { - protected private readonly Stack _currentPath = new(); + protected private readonly Stack _currentPath = []; readonly MemberPath _parentPath; protected internal LetPropertyMaps(IGlobalConfiguration configuration, MemberPath parentPath, TypePairCount builtProjections) { @@ -373,7 +359,7 @@ internal QueryExpressions Prepare(bool enableNullPropagationForQueryMapping, obj return new(Prepare(Projection), Prepare(LetClause)); LambdaExpression Prepare(Expression cachedExpression) { - var result = parameters == null ? cachedExpression : ParameterExpressionVisitor.SetParameters(parameters, cachedExpression); + var result = parameters == null ? cachedExpression : ParameterVisitor.SetParameters(parameters, cachedExpression); return (LambdaExpression)(enableNullPropagationForQueryMapping ? NullsafeQueryRewriter.NullCheck(result) : result); } } @@ -382,11 +368,11 @@ public sealed record MemberProjection(MemberMap MemberMap) { public Expression Expression { get; set; } } -abstract class ParameterExpressionVisitor : ExpressionVisitor +abstract class ParameterVisitor : ExpressionVisitor { public static Expression SetParameters(object parameters, Expression expression) { - ParameterExpressionVisitor visitor = parameters is ParameterBag dictionary ? new ConstantExpressionReplacementVisitor(dictionary) : new ObjectParameterExpressionReplacementVisitor(parameters); + ParameterVisitor visitor = parameters is ParameterBag dictionary ? new ConstantVisitor(dictionary) : new PropertyVisitor(parameters); return visitor.Visit(expression); } protected abstract Expression GetValue(string name); @@ -409,20 +395,18 @@ protected override Expression VisitMember(MemberExpression node) } return ToType(parameterValue, member.GetMemberType()); } - sealed class ObjectParameterExpressionReplacementVisitor : ParameterExpressionVisitor + sealed class PropertyVisitor(object parameters) : ParameterVisitor { - readonly object _parameters; - public ObjectParameterExpressionReplacementVisitor(object parameters) => _parameters = parameters; + readonly object _parameters = parameters; protected override Expression GetValue(string name) { var matchingMember = _parameters.GetType().GetProperty(name); return matchingMember != null ? Property(Constant(_parameters), matchingMember) : null; } } - sealed class ConstantExpressionReplacementVisitor : ParameterExpressionVisitor + sealed class ConstantVisitor(ParameterBag paramValues) : ParameterVisitor { - readonly ParameterBag _paramValues; - public ConstantExpressionReplacementVisitor(ParameterBag paramValues) => _paramValues = paramValues; + readonly ParameterBag _paramValues = paramValues; protected override Expression GetValue(string name) => _paramValues.TryGetValue(name, out object parameterValue) ? Constant(parameterValue) : null; } } @@ -441,7 +425,7 @@ public bool Equals(ProjectionRequest other) => SourceType == other.SourceType && MembersToExpand.SequenceEqual(other.MembersToExpand); public override int GetHashCode() { - var hashCode = new HashCode(); + HashCode hashCode = new(); hashCode.Add(SourceType); hashCode.Add(DestinationType); foreach (var member in MembersToExpand) diff --git a/src/AutoMapper/QueryableExtensions/ProjectionMappers/EnumerableProjectionMapper.cs b/src/AutoMapper/QueryableExtensions/ProjectionMappers/EnumerableProjectionMapper.cs index 16b9a3ed6e..a2cbbe2a6a 100644 --- a/src/AutoMapper/QueryableExtensions/ProjectionMappers/EnumerableProjectionMapper.cs +++ b/src/AutoMapper/QueryableExtensions/ProjectionMappers/EnumerableProjectionMapper.cs @@ -33,7 +33,7 @@ public Expression Project(IGlobalConfiguration configuration, in ProjectionReque } else { - var ctorInfo = destinationType.GetConstructor(new[] { sourceExpression.Type }); + var ctorInfo = destinationType.GetConstructor([sourceExpression.Type]); if (ctorInfo is not null) { sourceExpression = New(ctorInfo, sourceExpression); diff --git a/src/AutoMapper/ResolutionContext.cs b/src/AutoMapper/ResolutionContext.cs index 88465994bd..9f411f1264 100644 --- a/src/AutoMapper/ResolutionContext.cs +++ b/src/AutoMapper/ResolutionContext.cs @@ -51,7 +51,7 @@ public Dictionary InstanceCache get { CheckDefault(); - return _instanceCache ??= new(); + return _instanceCache ??= []; } } /// @@ -62,7 +62,7 @@ private Dictionary TypeDepth get { CheckDefault(); - return _typeDepth ??= new(); + return _typeDepth ??= []; } } TDestination IMapperBase.Map(object source) => ((IMapperBase)this).Map(source, default(TDestination)); diff --git a/src/AutoMapper/ServiceCollectionExtensions.cs b/src/AutoMapper/ServiceCollectionExtensions.cs index a2cb48bdc5..2b3640fedb 100644 --- a/src/AutoMapper/ServiceCollectionExtensions.cs +++ b/src/AutoMapper/ServiceCollectionExtensions.cs @@ -21,6 +21,7 @@ /// public static class ServiceCollectionExtensions { + static readonly Type[] AmTypes = [typeof(IValueResolver<,,>), typeof(IMemberValueResolver<,,,>), typeof(ITypeConverter<,>), typeof(IValueConverter<,>), typeof(IMappingAction<,>)]; public static IServiceCollection AddAutoMapper(this IServiceCollection services, Action configAction) => AddAutoMapperClasses(services, (sp, cfg) => configAction?.Invoke(cfg), null); @@ -68,18 +69,9 @@ private static IServiceCollection AddAutoMapperClasses(IServiceCollection servic } if (assembliesToScan != null) { - assembliesToScan = new HashSet(assembliesToScan.Where(a => !a.IsDynamic && a != typeof(Mapper).Assembly)); + assembliesToScan = assembliesToScan.Where(a => !a.IsDynamic && a != typeof(Mapper).Assembly).Distinct(); services.Configure(options => options.AddMaps(assembliesToScan)); - var openTypes = new[] - { - typeof(IValueResolver<,,>), - typeof(IMemberValueResolver<,,,>), - typeof(ITypeConverter<,>), - typeof(IValueConverter<,>), - typeof(IMappingAction<,>) - }; - foreach (var type in assembliesToScan.SelectMany(a => a.GetTypes().Where(type => type.IsClass && !type.IsAbstract && Array.Exists(openTypes, - openType => type.GetGenericInterface(openType) != null)))) + foreach (var type in assembliesToScan.SelectMany(a => a.GetTypes().Where(type => type.IsClass && !type.IsAbstract && IsAmType(type)))) { // use try add to avoid double-registration services.TryAddTransient(type); @@ -96,7 +88,8 @@ private static IServiceCollection AddAutoMapperClasses(IServiceCollection servic var options = sp.GetRequiredService>(); return new MapperConfiguration(options.Value); }); - services.Add(new ServiceDescriptor(typeof(IMapper), sp => new Mapper(sp.GetRequiredService(), sp.GetService), serviceLifetime)); + services.Add(new(typeof(IMapper), sp => new Mapper(sp.GetRequiredService(), sp.GetService), serviceLifetime)); return services; + bool IsAmType(Type type) => Array.Exists(AmTypes, openType => type.GetGenericInterface(openType) != null); } } \ No newline at end of file diff --git a/src/AutoMapper/TypeMap.cs b/src/AutoMapper/TypeMap.cs index e2059385ca..29de901144 100644 --- a/src/AutoMapper/TypeMap.cs +++ b/src/AutoMapper/TypeMap.cs @@ -24,7 +24,7 @@ public TypeMap(Type sourceType, Type destinationType, ProfileMap profile, TypeMa } SourceTypeDetails = profile.CreateTypeDetails(sourceType); DestinationTypeDetails = profile.CreateTypeDetails(destinationType); - sourceMembers ??= new(); + sourceMembers ??= []; var isReverseMap = typeMapConfiguration?.IsReverseMap is true; foreach (var destinationProperty in DestinationTypeDetails.WriteAccessors) { @@ -72,7 +72,7 @@ internal bool CanConstructorMap() => Profile.ConstructorMappingEnabled && !Desti public ProfileMap Profile { get; } public LambdaExpression CustomMapExpression => TypeConverter?.ProjectToExpression; public LambdaExpression CustomCtorFunction { get => _details?.CustomCtorFunction; set => Details.CustomCtorFunction = value; } - public LambdaExpression CustomCtorExpression => CustomCtorFunction?.Parameters.Count == 1 ? CustomCtorFunction : null; + public LambdaExpression CustomCtorExpression => CustomCtorFunction is { Parameters: [_] } ? CustomCtorFunction : null; public bool IncludeAllDerivedTypes { get => (_details?.IncludeAllDerivedTypes).GetValueOrDefault(); set => Details.IncludeAllDerivedTypes = value; } public MemberList ConfiguredMemberList { @@ -122,8 +122,8 @@ public IEnumerable MemberMaps public bool HasTypeConverter => TypeConverter != null; public Execution.TypeConverter TypeConverter { get; set; } public bool ShouldCheckForValid => ConfiguredMemberList != MemberList.None && !HasTypeConverter; - public LambdaExpression[] IncludedMembers { get => _details?.IncludedMembers ?? Array.Empty(); set => Details.IncludedMembers = value; } - public string[] IncludedMembersNames { get => _details?.IncludedMembersNames ?? Array.Empty(); set => Details.IncludedMembersNames = value; } + public LambdaExpression[] IncludedMembers { get => _details?.IncludedMembers ?? []; set => Details.IncludedMembers = value; } + public string[] IncludedMembersNames { get => _details?.IncludedMembersNames ?? []; set => Details.IncludedMembersNames = value; } public IReadOnlyCollection IncludedMembersTypeMaps => (_details?.IncludedMembersTypeMaps).NullCheck(); public Type MakeGenericType(Type type) => type.IsGenericTypeDefinition ? type.MakeGenericType(SourceType.GenericTypeArguments.Concat(DestinationType.GenericTypeArguments).Take(type.GenericParametersCount()).ToArray()) : @@ -134,13 +134,13 @@ public IEnumerable GetAllIncludedMembers() => IncludedMembersN public bool ConstructorParameterMatches(string destinationPropertyName) => ConstructorMapping && ConstructorMap[destinationPropertyName] != null; private void AddPropertyMap(MemberInfo destProperty, Type destinationPropertyType, List sourceMembers) { - var propertyMap = new PropertyMap(destProperty, destinationPropertyType, this); - propertyMap.MapByConvention(sourceMembers.ToArray()); + PropertyMap propertyMap = new(destProperty, destinationPropertyType, this); + propertyMap.MapByConvention([..sourceMembers]); AddPropertyMap(propertyMap); } private void AddPropertyMap(PropertyMap propertyMap) { - _propertyMaps ??= new(); + _propertyMaps ??= []; _propertyMaps.Add(propertyMap); } public string[] GetUnmappedPropertyNames() @@ -157,14 +157,14 @@ public string[] GetUnmappedPropertyNames() else { var ignoredSourceMembers = _details?.SourceMemberConfigs? - .Where(smc => smc.IsIgnored()) + .Where(smc => smc.Ignored) .Select(pm => pm.SourceMember.Name); properties = Profile.CreateTypeDetails(SourceType).ReadAccessors .Select(p => p.Name) .Except(MappedMembers().Select(m => m.GetSourceMemberName())) .Except(IncludedMembersNames) .Except(IncludedMembers.Select(m => m.GetMember()?.Name)) - .Except(ignoredSourceMembers ?? Array.Empty()); + .Except(ignoredSourceMembers ?? []); } return properties.Where(memberName => !Profile.GlobalIgnores.Any(memberName.StartsWith)).ToArray(); IEnumerable MappedMembers() => MemberMaps.Where(pm => pm.IsMapped); @@ -310,7 +310,7 @@ public void Seal(IGlobalConfiguration configuration, TypeMap thisMap) var includedMaps = inheritedTypeMap._details?.IncludedMembersTypeMaps; if (includedMaps != null) { - IncludedMembersTypeMaps ??= new(); + IncludedMembersTypeMaps ??= []; IncludedMembersTypeMaps.TryAdd(includedMaps); } } @@ -334,27 +334,27 @@ public void Seal(IGlobalConfiguration configuration, TypeMap thisMap) } public void IncludeDerivedTypes(TypePair derivedTypes) { - IncludedDerivedTypes ??= new(); + IncludedDerivedTypes ??= []; IncludedDerivedTypes.TryAdd(derivedTypes); } public void AddBeforeMapAction(LambdaExpression beforeMap) { - BeforeMapActions ??= new(); + BeforeMapActions ??= []; BeforeMapActions.TryAdd(beforeMap); } public void AddAfterMapAction(LambdaExpression afterMap) { - AfterMapActions ??= new(); + AfterMapActions ??= []; AfterMapActions.TryAdd(afterMap); } public void AddValueTransformation(ValueTransformerConfiguration valueTransformerConfiguration) { - ValueTransformerConfigs ??= new(); + ValueTransformerConfigs ??= []; ValueTransformerConfigs.Add(valueTransformerConfiguration); } public PathMap FindOrCreatePathMapFor(LambdaExpression destinationExpression, MemberPath path, TypeMap typeMap) { - PathMaps ??= new(); + PathMaps ??= []; var pathMap = GetPathMap(path); if (pathMap == null) { @@ -381,22 +381,22 @@ private PathMap GetPathMap(MemberPath memberPath) private void AddPathMap(PathMap pathMap) => PathMaps.Add(pathMap); public void IncludeBaseTypes(TypePair baseTypes) { - IncludedBaseTypes ??= new(); + IncludedBaseTypes ??= []; IncludedBaseTypes.TryAdd(baseTypes); } internal void CopyInheritedMapsTo(TypeMap typeMap) { - typeMap.Details.InheritedTypeMaps ??= new(); + typeMap.Details.InheritedTypeMaps ??= []; typeMap._details.InheritedTypeMaps.TryAdd(InheritedTypeMaps); } public bool AddMemberMap(IncludedMember includedMember) { - IncludedMembersTypeMaps ??= new(); + IncludedMembersTypeMaps ??= []; return IncludedMembersTypeMaps.TryAdd(includedMember); } public SourceMemberConfig FindOrCreateSourceMemberConfigFor(MemberInfo sourceMember) { - SourceMemberConfigs ??= new(); + SourceMemberConfigs ??= []; var config = GetSourceMemberConfig(sourceMember); if (config == null) { @@ -418,7 +418,7 @@ private SourceMemberConfig GetSourceMemberConfig(MemberInfo sourceMember) } public void AddInheritedMap(TypeMap inheritedTypeMap) { - InheritedTypeMaps ??= new(); + InheritedTypeMaps ??= []; InheritedTypeMaps.TryAdd(inheritedTypeMap); } private void ApplyIncludedMemberTypeMap(IncludedMember includedMember, TypeMap thisMap) @@ -476,7 +476,7 @@ private void ApplyInheritedTypeMap(TypeMap inheritedTypeMap, TypeMap thisMap) } if (inheritedDetails.ValueTransformerConfigs != null) { - ValueTransformerConfigs ??= new(); + ValueTransformerConfigs ??= []; ValueTransformerConfigs.InsertRange(0, inheritedDetails.ValueTransformerConfigs); } return; @@ -501,7 +501,7 @@ void ApplyInheritedPropertyMaps(TypeMap inheritedTypeMap, TypeMap thisMap) } void ApplyInheritedSourceMembers(TypeMapDetails inheritedTypeMap) { - SourceMemberConfigs ??= new(); + SourceMemberConfigs ??= []; foreach (var inheritedSourceConfig in inheritedTypeMap.SourceMemberConfigs) { if (GetSourceMemberConfig(inheritedSourceConfig.SourceMember) == null) @@ -515,12 +515,12 @@ void ApplyInheritedMapActions(IEnumerable beforeMap, IEnumerab { if (beforeMap != null) { - BeforeMapActions ??= new(); + BeforeMapActions ??= []; BeforeMapActions.TryAdd(beforeMap); } if (afterMap != null) { - AfterMapActions ??= new(); + AfterMapActions ??= []; AfterMapActions.TryAdd(afterMap); } } @@ -528,9 +528,9 @@ private PathMap[] NotOverridenPathMaps(TypeMap inheritedTypeMap) { if (inheritedTypeMap.PathMaps.Count == 0) { - return Array.Empty(); + return []; } - PathMaps ??= new(); + PathMaps ??= []; return inheritedTypeMap.PathMaps.Where(baseConfig => GetPathMap(baseConfig.MemberPath) == null).ToArray(); } } diff --git a/src/UnitTests/Bug/NamingConventions.cs b/src/UnitTests/Bug/NamingConventions.cs index b10629bb0a..1344b0c8d8 100644 --- a/src/UnitTests/Bug/NamingConventions.cs +++ b/src/UnitTests/Bug/NamingConventions.cs @@ -67,7 +67,7 @@ public class Dario public string JaSeZovemImenom { get; set; } } -public class When_mapping_with_lowercae_naming_conventions_two_ways_in_profiles : AutoMapperSpecBase +public class When_mapping_with_lowercase_naming_conventions_two_ways_in_profiles : AutoMapperSpecBase { private Dario _dario; private Neda _neda; @@ -98,6 +98,46 @@ public void Should_map_from_lower_to_pascal() _neda.ja_se_zovem_imenom.ShouldBe("foo"); } + [Fact] + public void Should_map_from_pascal_to_lower() + { + _dario.JaSeZovemImenom.ShouldBe("foo"); + } +} + +public class When_mapping_with_lowercase_naming_conventions_two_ways : AutoMapperSpecBase +{ + private Dario _dario; + private Neda _neda; + + protected override MapperConfiguration CreateConfiguration() => new(cfg => + { + cfg.SourceMemberNamingConvention = new LowerUnderscoreNamingConvention(); + cfg.DestinationMemberNamingConvention = new LowerUnderscoreNamingConvention(); + cfg.CreateProfile("MyMapperProfile", prf => + { + prf.DestinationMemberNamingConvention = PascalCaseNamingConvention.Instance; + prf.CreateMap(); + }); + cfg.CreateProfile("MyMapperProfile2", prf => + { + prf.SourceMemberNamingConvention = PascalCaseNamingConvention.Instance; + prf.CreateMap(); + }); + }); + + protected override void Because_of() + { + _dario = Mapper.Map(new Neda { ja_se_zovem_imenom = "foo" }); + _neda = Mapper.Map(_dario); + } + + [Fact] + public void Should_map_from_lower_to_pascal() + { + _neda.ja_se_zovem_imenom.ShouldBe("foo"); + } + [Fact] public void Should_map_from_pascal_to_lower() { diff --git a/src/UnitTests/Mappers/DynamicMapperTests.cs b/src/UnitTests/Mappers/DynamicMapperTests.cs index b16a0fa0a2..36bae7ed1c 100644 --- a/src/UnitTests/Mappers/DynamicMapperTests.cs +++ b/src/UnitTests/Mappers/DynamicMapperTests.cs @@ -67,6 +67,18 @@ public void Should_map_source_properties() Assert.Equal(12, _destination.Baz); ((int[])_destination.Data).SequenceEqual(data).ShouldBeTrue(); } + [Fact] + public void Should_map_to_ExpandoObject() + { + var config = new MapperConfiguration(cfg => { }); + var data = new[] { 1, 2, 3 }; + _destination = config.CreateMapper().Map(new Destination { Foo = "Foo", Bar = "Bar", Data = data, Baz = 12 }); + ((IDictionary)_destination).Count.ShouldBe(4); + Assert.Equal("Foo", _destination.Foo); + Assert.Equal("Bar", _destination.Bar); + Assert.Equal(12, _destination.Baz); + ((int[])_destination.Data).SequenceEqual(data).ShouldBeTrue(); + } } public class When_mapping_from_dynamic