Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
After discussion with Lucian, I have moved MapDestinationCtorToSource…
… from TypeMapFactory to MappingExpressionBase.Configure.
  • Loading branch information
Mark Quennell committed Jul 9, 2019
commit cb4d5c07c4c03c33accc15e58226d7dfb9825d9e
4 changes: 1 addition & 3 deletions src/AutoMapper/ApiCompatBaseline.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
Compat issues with assembly AutoMapper:
MembersMustExist : Member 'AutoMapper.AutoMapperConfigurationException.PropertyMap.get()' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'AutoMapper.AutoMapperConfigurationException.PropertyMap.set(AutoMapper.PropertyMap)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'AutoMapper.ConstructorMap..ctor(System.Reflection.ConstructorInfo, AutoMapper.TypeMap)' does not exist in the implementation but it does exist in the contract.
TypesMustExist : Type 'AutoMapper.CtorParamConfigurationExpression<TSource>' does not exist in the implementation but it does exist in the contract.
InterfacesShouldHaveSameMembers : Interface member 'AutoMapper.IConfigurationProvider.Features' is present in the implementation but not in the contract.
InterfacesShouldHaveSameMembers : Interface member 'AutoMapper.IConfigurationProvider.Features.get()' is present in the implementation but not in the contract.
Expand Down Expand Up @@ -157,7 +156,6 @@ MembersMustExist : Member 'AutoMapper.Configuration.IProfileConfiguration.Valida
InterfacesShouldHaveSameMembers : Interface member 'AutoMapper.Configuration.IPropertyMapConfiguration.SourceExpression' is present in the implementation but not in the contract.
InterfacesShouldHaveSameMembers : Interface member 'AutoMapper.Configuration.IPropertyMapConfiguration.GetDestinationExpression()' is present in the implementation but not in the contract.
InterfacesShouldHaveSameMembers : Interface member 'AutoMapper.Configuration.IPropertyMapConfiguration.SourceExpression.get()' is present in the implementation but not in the contract.
InterfacesShouldHaveSameMembers : Interface member 'AutoMapper.Configuration.ITypeMapConfiguration.GetCtorParameterConfigs()' is present in the implementation but not in the contract.
MembersMustExist : Member 'AutoMapper.Configuration.MapperConfigurationExpression.AddProfiles(System.Collections.Generic.IEnumerable<System.Reflection.Assembly>)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'AutoMapper.Configuration.MapperConfigurationExpression.AddProfiles(System.Collections.Generic.IEnumerable<System.String>)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'AutoMapper.Configuration.MapperConfigurationExpression.AddProfiles(System.Collections.Generic.IEnumerable<System.Type>)' does not exist in the implementation but it does exist in the contract.
Expand Down Expand Up @@ -193,4 +191,4 @@ MembersMustExist : Member 'AutoMapper.QueryableExtensions.ProjectionExpression.T
MembersMustExist : Member 'AutoMapper.QueryableExtensions.ProjectionExpression.To<TResult>(System.Collections.Generic.IDictionary<System.String, System.Object>, System.Linq.Expressions.Expression<System.Func<TResult, System.Object>>[])' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'AutoMapper.QueryableExtensions.ProjectionExpression.To<TResult>(System.Object)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'AutoMapper.QueryableExtensions.ProjectionExpression.To<TResult>(System.Object, System.String[])' does not exist in the implementation but it does exist in the contract.
Total Issues: 194
Total Issues: 192
1 change: 0 additions & 1 deletion src/AutoMapper/Configuration/ITypeMapConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ namespace AutoMapper.Configuration
public interface ITypeMapConfiguration
{
void Configure(TypeMap typeMap);
IList<ICtorParameterConfiguration> GetCtorParameterConfigs();
Type SourceType { get; }
Type DestinationType { get; }
bool IsOpenGeneric { get; }
Expand Down
54 changes: 50 additions & 4 deletions src/AutoMapper/Configuration/MappingExpressionBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ protected MappingExpressionBase(MemberList memberList, TypePair types)

public void Configure(TypeMap typeMap)
{
foreach(var destProperty in typeMap.DestinationTypeDetails.PublicWriteAccessors)
foreach (var destProperty in typeMap.DestinationTypeDetails.PublicWriteAccessors)
{
var attrs = destProperty.GetCustomAttributes(true);
if(attrs.Any(x => x is IgnoreMapAttribute))
Expand All @@ -58,7 +58,20 @@ public void Configure(TypeMap typeMap)
}
}

foreach(var action in TypeMapActions)
var destTypeInfo = typeMap.DestinationTypeDetails;
if (!typeMap.DestinationType.IsAbstract())
{
foreach (var destCtor in destTypeInfo.Constructors.OrderByDescending(ci => ci.GetParameters().Length))
{
if (MapDestinationCtorToSource(typeMap, destCtor, typeMap.SourceTypeDetails, typeMap.Profile))
{
break;
}
}
}


foreach (var action in TypeMapActions)
{
action(typeMap);
}
Expand Down Expand Up @@ -100,6 +113,41 @@ public void Configure(TypeMap typeMap)
}
}

private bool MapDestinationCtorToSource(TypeMap typeMap, ConstructorInfo destCtor, TypeDetails sourceTypeInfo, ProfileMap options)
{
var ctorParameters = destCtor.GetParameters();

if (ctorParameters.Length == 0 || !options.ConstructorMappingEnabled)
return false;

var ctorMap = new ConstructorMap(destCtor, typeMap);

foreach (var parameter in ctorParameters)
{
var resolvers = new LinkedList<MemberInfo>();

var canResolve = MapDestinationPropertyToSource(options, sourceTypeInfo, destCtor.DeclaringType, parameter.GetType(), parameter.Name, resolvers);
if ((!canResolve && parameter.IsOptional) || CtorParamConfigurations.Any(c => c.CheckCtorParamName(parameter.Name)))
{
canResolve = true;
}
ctorMap.AddParameter(parameter, resolvers.ToArray(), canResolve);
}

typeMap.ConstructorMap = ctorMap;

return ctorMap.CanResolve;
}

private bool MapDestinationPropertyToSource(ProfileMap options, TypeDetails sourceTypeInfo, Type destType, Type destMemberType, string destMemberInfo, LinkedList<MemberInfo> members)
{
if (string.IsNullOrEmpty(destMemberInfo))
{
return false;
}
return options.MemberConfigurations.Any(_ => _.MapDestinationPropertyToSource(options, sourceTypeInfo, destType, destMemberType, destMemberInfo, members));
}

protected IEnumerable<IPropertyMapConfiguration> MapToSourceMembers() =>
MemberConfigurations.Where(m => m.SourceExpression != null && m.SourceExpression.Body == m.SourceExpression.Parameters[0]);

Expand Down Expand Up @@ -180,8 +228,6 @@ protected IPropertyMapConfiguration GetDestinationMemberConfiguration(MemberInfo
MemberConfigurations.FirstOrDefault(m => m.DestinationMember.Name == destinationMember.Name);

protected abstract void IgnoreDestinationMember(MemberInfo property, bool ignorePaths = true);

public IList<ICtorParameterConfiguration> GetCtorParameterConfigs() => CtorParamConfigurations;
}

public abstract class MappingExpressionBase<TSource, TDestination, TMappingExpression>
Expand Down
9 changes: 1 addition & 8 deletions src/AutoMapper/ConstructorMap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,15 @@ namespace AutoMapper
public class ConstructorMap
{
private readonly IList<ConstructorParameterMap> _ctorParams = new List<ConstructorParameterMap>();
private readonly IList<ICtorParameterConfiguration> _ctorConfigs = new List<ICtorParameterConfiguration>();

public ConstructorInfo Ctor { get; }
public TypeMap TypeMap { get; }
public IEnumerable<ConstructorParameterMap> CtorParams => _ctorParams;

public ConstructorMap(ConstructorInfo ctor, TypeMap typeMap, ProfileMap options)
public ConstructorMap(ConstructorInfo ctor, TypeMap typeMap)
{
Ctor = ctor;
TypeMap = typeMap;
_ctorConfigs = options.GetCtorParameterConfigs(typeMap);
}

private static readonly IExpressionResultConverter[] ExpressionResultConverters =
Expand Down Expand Up @@ -57,10 +55,5 @@ public void AddParameter(ParameterInfo parameter, MemberInfo[] resolvers, bool c
{
_ctorParams.Add(new ConstructorParameterMap(TypeMap, parameter, resolvers, canResolve));
}

public bool ContainsCtorParameterConfig(string paramName)
{
return _ctorConfigs.Any(c => c.CheckCtorParamName(paramName));
}
}
}
13 changes: 0 additions & 13 deletions src/AutoMapper/ProfileMap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -232,19 +232,6 @@ private void ApplyDerivedMaps(TypeMap baseMap, TypeMap typeMap, IConfigurationPr
}
}

public IList<ICtorParameterConfiguration> GetCtorParameterConfigs(TypeMap typeMap)
{
var list = new List<ICtorParameterConfiguration>();
foreach(var config in _typeMapConfigs.Where(c => c.SourceType == typeMap.SourceType && c.DestinationType == typeMap.DestinationType))
{
if (!(config is MappingExpressionBase mappingExpression))
continue;

list.AddRange(mappingExpression.GetCtorParameterConfigs());
}
return list;
}

}

public readonly struct IncludedMember
Expand Down
60 changes: 30 additions & 30 deletions src/AutoMapper/TypeMapFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,52 +24,52 @@ public TypeMap CreateTypeMap(Type sourceType, Type destinationType, ProfileMap o
typeMap.AddPropertyMap(destProperty, resolvers);
}
}
if (!destinationType.IsAbstract())
{
foreach (var destCtor in destTypeInfo.Constructors.OrderByDescending(ci => ci.GetParameters().Length))
{
if (MapDestinationCtorToSource(typeMap, destCtor, sourceTypeInfo, options))
{
break;
}
}
}
//if (!destinationType.IsAbstract())
//{
// foreach (var destCtor in destTypeInfo.Constructors.OrderByDescending(ci => ci.GetParameters().Length))
// {
// if (MapDestinationCtorToSource(typeMap, destCtor, sourceTypeInfo, options))
// {
// break;
// }
// }
//}
return typeMap;
}

private bool MapDestinationPropertyToSource(ProfileMap options, TypeDetails sourceTypeInfo, Type destType, Type destMemberType, string destMemberInfo, LinkedList<MemberInfo> members)
{
if(string.IsNullOrEmpty(destMemberInfo))
if (string.IsNullOrEmpty(destMemberInfo))
{
return false;
}
return options.MemberConfigurations.Any(_ => _.MapDestinationPropertyToSource(options, sourceTypeInfo, destType, destMemberType, destMemberInfo, members));
}

private bool MapDestinationCtorToSource(TypeMap typeMap, ConstructorInfo destCtor, TypeDetails sourceTypeInfo, ProfileMap options)
{
var ctorParameters = destCtor.GetParameters();
//private bool MapDestinationCtorToSource(TypeMap typeMap, ConstructorInfo destCtor, TypeDetails sourceTypeInfo, ProfileMap options)
//{
// var ctorParameters = destCtor.GetParameters();

if (ctorParameters.Length == 0 || !options.ConstructorMappingEnabled)
return false;
// if (ctorParameters.Length == 0 || !options.ConstructorMappingEnabled)
// return false;

var ctorMap = new ConstructorMap(destCtor, typeMap, options);
// var ctorMap = new ConstructorMap(destCtor, typeMap, options);

foreach (var parameter in ctorParameters)
{
var resolvers = new LinkedList<MemberInfo>();
// foreach (var parameter in ctorParameters)
// {
// var resolvers = new LinkedList<MemberInfo>();

var canResolve = MapDestinationPropertyToSource(options, sourceTypeInfo, destCtor.DeclaringType, parameter.GetType(), parameter.Name, resolvers);
if((!canResolve && parameter.IsOptional) || ctorMap.ContainsCtorParameterConfig(parameter.Name))
{
canResolve = true;
}
ctorMap.AddParameter(parameter, resolvers.ToArray(), canResolve);
}
// var canResolve = MapDestinationPropertyToSource(options, sourceTypeInfo, destCtor.DeclaringType, parameter.GetType(), parameter.Name, resolvers);
// if((!canResolve && parameter.IsOptional) || ctorMap.ContainsCtorParameterConfig(parameter.Name))
// {
// canResolve = true;
// }
// ctorMap.AddParameter(parameter, resolvers.ToArray(), canResolve);
// }

typeMap.ConstructorMap = ctorMap;
// typeMap.ConstructorMap = ctorMap;

return ctorMap.CanResolve;
}
// return ctorMap.CanResolve;
//}
}
}