Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
2 changes: 1 addition & 1 deletion src/AutoMapper/Configuration/IProfileConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,6 @@ public interface IProfileConfiguration
INamingConvention DestinationMemberNamingConvention { get; }
IEnumerable<ITypeMapConfiguration> TypeMapConfigs { get; }
IEnumerable<ITypeMapConfiguration> OpenTypeMapConfigs { get; }
IEnumerable<ValueTransformerConfiguration> ValueTransformers { get; }
IEnumerable<IValueTransformConfiguration> ValueTransformers { get; }
}
}
14 changes: 2 additions & 12 deletions src/AutoMapper/Configuration/MappingExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ public MappingExpression(MemberList memberList, Type sourceType, Type destinatio
public Type DestinationType => Types.DestinationType;
public bool IsOpenGeneric { get; }
public ITypeMapConfiguration ReverseTypeMap => _reverseMap;
protected List<Action<TypeMap>> TypeMapActions { get; } = new List<Action<TypeMap>>();
public List<Action<TypeMap>> TypeMapActions { get; } = new List<Action<TypeMap>>();

public IMappingExpression<TSource, TDestination> PreserveReferences()
{
Expand Down Expand Up @@ -530,17 +530,7 @@ public IMappingExpression<TSource, TDestination> DisableCtorValidation()
return this;
}

public IMappingExpression<TSource, TDestination> ApplyTransform<TValue>(Expression<Func<TValue, TValue>> transformer)
{
TypeMapActions.Add(tm =>
{
var config = new ValueTransformerConfiguration(typeof(TValue), transformer);

tm.AddValueTransformation(config);
});

return this;
}


private IPropertyMapConfiguration GetDestinationMemberConfiguration(MemberInfo destinationMember) =>
_memberConfigurations.FirstOrDefault(m => m.DestinationMember == destinationMember);
Expand Down
58 changes: 24 additions & 34 deletions src/AutoMapper/Configuration/MemberConfigurationExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public class MemberConfigurationExpression<TSource, TDestination, TMember> : IMe
private readonly MemberInfo _destinationMember;
private LambdaExpression _sourceMember;
private readonly Type _sourceType;
protected List<Action<PropertyMap>> PropertyMapActions { get; } = new List<Action<PropertyMap>>();
public List<Action<PropertyMap>> PropertyMapActions { get; } = new List<Action<PropertyMap>>();

public MemberConfigurationExpression(MemberInfo destinationMember, Type sourceType)
{
Expand All @@ -23,9 +23,9 @@ public MemberConfigurationExpression(MemberInfo destinationMember, Type sourceTy

public MemberInfo DestinationMember => _destinationMember;

public void MapAtRuntime()
{
PropertyMapActions.Add(pm => pm.Inline = false);
public void MapAtRuntime()
{
PropertyMapActions.Add(pm => pm.Inline = false);
}

public void NullSubstitute(object nullSubstitute)
Expand Down Expand Up @@ -125,7 +125,7 @@ public void MapFrom<TSourceMember>(Expression<Func<TSource, TSourceMember>> sour
MapFromUntyped(sourceMember);
}

internal void MapFromUntyped(LambdaExpression sourceExpression)
internal void MapFromUntyped(LambdaExpression sourceExpression)
{
_sourceMember = sourceExpression;
PropertyMapActions.Add(pm => pm.MapFrom(sourceExpression));
Expand Down Expand Up @@ -233,31 +233,21 @@ public void PreCondition(Func<TSource, ResolutionContext, bool> condition)
});
}

public void ApplyTransform<TValue>(Expression<Func<TValue, TValue>> transformer)
{
PropertyMapActions.Add(pm =>
{
var config = new ValueTransformerConfiguration(typeof(TValue), transformer);

pm.AddValueTransformation(config);
});
}

public void ExplicitExpansion()
{
PropertyMapActions.Add(pm => pm.ExplicitExpansion = true);
}

public void Ignore() => Ignore(ignorePaths: true);
public void Ignore() => Ignore(ignorePaths: true);

internal void Ignore(bool ignorePaths) =>
PropertyMapActions.Add(pm =>
{
PropertyMapActions.Add(pm =>
{
pm.Ignored = true;
if(ignorePaths)
{
pm.TypeMap.IgnorePaths(DestinationMember);
}
if(ignorePaths)
{
pm.TypeMap.IgnorePaths(DestinationMember);
}
});

public void AllowNull()
Expand All @@ -284,25 +274,25 @@ public void Configure(TypeMap typeMap)
destMember = typeMap.DestinationTypeDetails.PublicReadAccessors.Single(m => m.Name == destMember.Name);
}

var propertyMap = typeMap.FindOrCreatePropertyMapFor(destMember);
var propertyMap = typeMap.FindOrCreatePropertyMapFor(destMember);

Apply(propertyMap);
}
private void Apply(PropertyMap propertyMap)
{
}

private void Apply(PropertyMap propertyMap)
{
foreach(var action in PropertyMapActions)
{
action(propertyMap);
}
}
public IPropertyMapConfiguration Reverse()
}
}

public IPropertyMapConfiguration Reverse()
{
var newSource = Parameter(DestinationMember.DeclaringType, "source");
var newSourceProperty = MakeMemberAccess(newSource, _destinationMember);
var newSourceExpression = Lambda(newSourceProperty, newSource);
var newSourceExpression = Lambda(newSourceProperty, newSource);
return PathConfigurationExpression<TDestination, TSource>.Create(_sourceMember, newSourceExpression);
}
}
}
}
31 changes: 16 additions & 15 deletions src/AutoMapper/Execution/TypeMapPlanBuilder.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using AutoMapper.Internal;

namespace AutoMapper.Execution
{
using System;
Expand Down Expand Up @@ -136,7 +138,7 @@ private LambdaExpression TypeConverterMapper()
typeof(ITypeConverter<,>).MakeGenericType(_typeMap.SourceType, _typeMap.DestinationTypeToUse);
return Lambda(
Call(
ToType(CreateInstance(type), converterInterfaceType),
CreateInstance(type).ToType(converterInterfaceType),
converterInterfaceType.GetDeclaredMethod("Convert"),
Source, _initialDestination, Context
),
Expand All @@ -145,7 +147,7 @@ private LambdaExpression TypeConverterMapper()

private Expression CreateDestinationFunc(out bool constructorMapping)
{
var newDestFunc = ToType(CreateNewDestinationFunc(out constructorMapping), _typeMap.DestinationTypeToUse);
var newDestFunc = CreateNewDestinationFunc(out constructorMapping).ToType(_typeMap.DestinationTypeToUse);

var getDest = _typeMap.DestinationTypeToUse.IsValueType()
? newDestFunc
Expand Down Expand Up @@ -250,7 +252,7 @@ private Expression CreateMapperFunc(Expression assignmentFunc)
var getDestination = Context.Type.GetDeclaredMethod("GetDestination");
var assignCache =
Assign(cache,
ToType(Call(Context, getDestination, Source, Constant(_destination.Type)), _destination.Type));
Call(Context, getDestination, Source, Constant(_destination.Type)).ToType(_destination.Type));
var condition = Condition(
AndAlso(NotEqual(Source, Constant(null)), NotEqual(assignCache, Constant(null))),
cache,
Expand Down Expand Up @@ -408,7 +410,7 @@ private Expression CreatePropertyMapFunc(PropertyMap propertyMap, Expression des
if (propertyMap.DestinationProperty is FieldInfo)
{
mapperExpr = propertyMap.SourceType != propertyMap.DestinationPropertyType
? Assign(destMember, ToType(propertyValue, propertyMap.DestinationPropertyType))
? Assign(destMember, propertyValue.ToType(propertyMap.DestinationPropertyType))
: Assign(getter, propertyValue);
}
else
Expand All @@ -417,16 +419,16 @@ private Expression CreatePropertyMapFunc(PropertyMap propertyMap, Expression des
if (setter == null)
mapperExpr = propertyValue;
else
mapperExpr = Assign(destMember, ToType(propertyValue, propertyMap.DestinationPropertyType));
mapperExpr = Assign(destMember, propertyValue.ToType(propertyMap.DestinationPropertyType));
}

if (propertyMap.Condition != null)
mapperExpr = IfThen(
propertyMap.Condition.ConvertReplaceParameters(
Source,
_destination,
ToType(propertyValue, propertyMap.Condition.Parameters[2].Type),
ToType(getter, propertyMap.Condition.Parameters[2].Type),
propertyValue.ToType(propertyMap.Condition.Parameters[2].Type),
getter.ToType(propertyMap.Condition.Parameters[2].Type),
Context
),
mapperExpr
Expand All @@ -452,8 +454,7 @@ private Expression BuildValueResolverFunc(PropertyMap propertyMap, Expression de

if (valueResolverConfig != null)
{
valueResolverFunc = ToType(BuildResolveCall(destValueExpr, valueResolverConfig),
destinationPropertyType);
valueResolverFunc = BuildResolveCall(destValueExpr, valueResolverConfig).ToType(destinationPropertyType);
}
else if (propertyMap.CustomResolver != null)
{
Expand All @@ -471,7 +472,7 @@ private Expression BuildValueResolverFunc(PropertyMap propertyMap, Expression de
: nullCheckedExpression.Type;
valueResolverFunc =
TryCatch(
ToType(nullCheckedExpression, returnType),
nullCheckedExpression.ToType(returnType),
Catch(typeof(NullReferenceException), Default(returnType)),
Catch(typeof(ArgumentNullException), Default(returnType))
);
Expand Down Expand Up @@ -510,23 +511,23 @@ private Expression BuildValueResolverFunc(PropertyMap propertyMap, Expression de
if (propertyMap.NullSubstitute != null)
{
var nullSubstitute = Constant(propertyMap.NullSubstitute);
valueResolverFunc = Coalesce(valueResolverFunc, ToType(nullSubstitute, valueResolverFunc.Type));
valueResolverFunc = Coalesce(valueResolverFunc, nullSubstitute.ToType(valueResolverFunc.Type));
}
else if (!typeMap.Profile.AllowNullDestinationValues)
{
var toCreate = propertyMap.SourceType ?? destinationPropertyType;
if (!toCreate.IsAbstract() && toCreate.IsClass())
valueResolverFunc = Coalesce(
valueResolverFunc,
ToType(DelegateFactory.GenerateNonNullConstructorExpression(toCreate), propertyMap.SourceType)
DelegateFactory.GenerateNonNullConstructorExpression(toCreate).ToType(propertyMap.SourceType)
);
}

valueResolverFunc = propertyMap.ValueTransformers
.Concat(_typeMap.ValueTransformers)
.Concat(_typeMap.Profile.ValueTransformers)
.Where(vt => vt.IsMatch(propertyMap))
.Aggregate(valueResolverFunc, (current, vtConfig) => ToType(ReplaceParameters(vtConfig.TransformerExpression, ToType(current, vtConfig.ValueType)), propertyMap.DestinationPropertyType));
.Aggregate(valueResolverFunc, (current, vtConfig) => vtConfig.Visit(current, propertyMap));

return valueResolverFunc;
}
Expand All @@ -549,9 +550,9 @@ private Expression BuildResolveCall(Expression destValueExpr, ValueResolverConfi
var iResolverType = valueResolverConfig.InterfaceType;

var parameters = new[] {Source, _destination, sourceMember, destValueExpr}.Where(p => p != null)
.Zip(iResolverType.GetGenericArguments(), ToType)
.Zip(iResolverType.GetGenericArguments(), ExpressionFactory.ToType)
.Concat(new[] {Context});
return Call(ToType(resolverInstance, iResolverType), iResolverType.GetDeclaredMethod("Resolve"),
return Call(resolverInstance.ToType(iResolverType), iResolverType.GetDeclaredMethod("Resolve"),
parameters);
}
}
Expand Down
17 changes: 7 additions & 10 deletions src/AutoMapper/IMappingExpression.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq.Expressions;

namespace AutoMapper
{
public interface IMappingExpressionBase
{
List<Action<TypeMap>> TypeMapActions { get; }
}
/// <summary>
/// Mapping configuration options for non-generic maps
/// </summary>
public interface IMappingExpression
public interface IMappingExpression : IMappingExpressionBase
{
/// <summary>
/// Preserve object identity. Useful for circular references.
Expand Down Expand Up @@ -188,7 +193,7 @@ IMappingExpression AfterMap<TMappingAction>()
/// </summary>
/// <typeparam name="TSource">Source type</typeparam>
/// <typeparam name="TDestination">Destination type</typeparam>
public interface IMappingExpression<TSource, TDestination>
public interface IMappingExpression<TSource, TDestination> : IMappingExpressionBase
{
/// <summary>
/// Customize configuration for a path inside the destination object.
Expand Down Expand Up @@ -439,13 +444,5 @@ IMappingExpression<TSource, TDestination> ForSourceMember(string sourceMemberNam
/// </summary>
/// <returns>Itself</returns>
IMappingExpression<TSource, TDestination> DisableCtorValidation();

/// <summary>
/// Apply a transformation function after any resolved destination member value with the given type
/// </summary>
/// <typeparam name="TValue">Value type to match and transform</typeparam>
/// <param name="transformer">Transformation expression</param>
/// <returns>Itself</returns>
IMappingExpression<TSource, TDestination> ApplyTransform<TValue>(Expression<Func<TValue, TValue>> transformer);
}
}
15 changes: 7 additions & 8 deletions src/AutoMapper/IMemberConfigurationExpression.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;

namespace AutoMapper
{
public interface IMemberConfigurationExpressionBase
{
List<Action<PropertyMap>> PropertyMapActions { get; }
}

/// <summary>
/// Member configuration options
/// </summary>
/// <typeparam name="TSource">Source type for this member</typeparam>
/// <typeparam name="TMember">Type for this member</typeparam>
/// <typeparam name="TDestination">Destination type for this map</typeparam>
public interface IMemberConfigurationExpression<TSource, TDestination, TMember>
public interface IMemberConfigurationExpression<TSource, TDestination, TMember> : IMemberConfigurationExpressionBase
{
/// <summary>
/// Do not precompute the execution plan for this member, just map it at runtime.
Expand Down Expand Up @@ -199,13 +205,6 @@ void ResolveUsing<TValueResolver, TSourceMember>(string sourceMemberName)
/// The destination member being configured.
/// </summary>
MemberInfo DestinationMember { get; }

/// <summary>
/// Apply a transformation function after any resolved destination member value with the given type
/// </summary>
/// <typeparam name="TValue">Value type to match and transform</typeparam>
/// <param name="transformer">Transformation expression</param>
void ApplyTransform<TValue>(Expression<Func<TValue, TValue>> transformer);
}

/// <summary>
Expand Down
4 changes: 2 additions & 2 deletions src/AutoMapper/IObjectMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ public Expression MapExpression(IConfigurationProvider configurationProvider, Pr
Call(
Constant(this),
MapMethod,
ToType(sourceExpression, typeof(TSource)),
ToType(destExpression, typeof(TDestination)),
sourceExpression.ToType(typeof(TSource)),
destExpression.ToType(typeof(TDestination)),
contextExpression);
}
}
9 changes: 2 additions & 7 deletions src/AutoMapper/IProfileExpression.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using System;
using System.Linq.Expressions;
using System.Collections.Generic;
using System.Reflection;
using AutoMapper.Configuration.Conventions;
using AutoMapper.Mappers;
Expand Down Expand Up @@ -154,11 +154,6 @@ public interface IProfileExpression
/// <param name="type">Static type that contains extension methods</param>
void IncludeSourceExtensionMethods(Type type);

/// <summary>
/// Apply a transformation function after any resolved destination member value with the given type
/// </summary>
/// <typeparam name="TValue">Value type to match and transform</typeparam>
/// <param name="transformer">Transformation expression</param>
void ApplyTransform<TValue>(Expression<Func<TValue, TValue>> transformer);
IList<IValueTransformConfiguration> ValueTransformers { get; }
}
}
10 changes: 10 additions & 0 deletions src/AutoMapper/IValueTransformConfiguration.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System.Linq.Expressions;

namespace AutoMapper
{
public interface IValueTransformConfiguration
{
bool IsMatch(PropertyMap propertyMap);
Expression Visit(Expression current, PropertyMap propertyMap);
}
}
Loading