tools/AutoMapper/Configuration/MemberConfigurationExpression.cs (247 lines of code) (raw):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
namespace AutoMapper.Configuration
{
using static Expression;
public class MemberConfigurationExpression<TSource, TDestination, TMember> : IMemberConfigurationExpression<TSource, TDestination, TMember>, IPropertyMapConfiguration
{
private readonly MemberInfo _destinationMember;
private LambdaExpression _sourceMember;
private readonly Type _sourceType;
protected List<Action<PropertyMap>> PropertyMapActions { get; } = new List<Action<PropertyMap>>();
public MemberConfigurationExpression(MemberInfo destinationMember, Type sourceType)
{
_destinationMember = destinationMember;
_sourceType = sourceType;
}
public MemberInfo DestinationMember => _destinationMember;
public void MapAtRuntime()
{
PropertyMapActions.Add(pm => pm.Inline = false);
}
public void NullSubstitute(object nullSubstitute)
{
PropertyMapActions.Add(pm => pm.NullSubstitute = nullSubstitute);
}
public void ResolveUsing<TValueResolver>()
where TValueResolver : IValueResolver<TSource, TDestination, TMember>
{
var config = new ValueResolverConfiguration(typeof(TValueResolver), typeof(IValueResolver<TSource, TDestination, TMember>));
PropertyMapActions.Add(pm => pm.ValueResolverConfig = config);
}
public void ResolveUsing<TValueResolver, TSourceMember>(Expression<Func<TSource, TSourceMember>> sourceMember)
where TValueResolver : IMemberValueResolver<TSource, TDestination, TSourceMember, TMember>
{
var config = new ValueResolverConfiguration(typeof(TValueResolver), typeof(IMemberValueResolver<TSource, TDestination, TSourceMember, TMember>))
{
SourceMember = sourceMember
};
PropertyMapActions.Add(pm => pm.ValueResolverConfig = config);
}
public void ResolveUsing<TValueResolver, TSourceMember>(string sourceMemberName)
where TValueResolver : IMemberValueResolver<TSource, TDestination, TSourceMember, TMember>
{
var config = new ValueResolverConfiguration(typeof(TValueResolver), typeof(IMemberValueResolver<TSource, TDestination, TSourceMember, TMember>))
{
SourceMemberName = sourceMemberName
};
PropertyMapActions.Add(pm => pm.ValueResolverConfig = config);
}
public void ResolveUsing(IValueResolver<TSource, TDestination, TMember> valueResolver)
{
var config = new ValueResolverConfiguration(valueResolver, typeof(IValueResolver<TSource, TDestination, TMember>));
PropertyMapActions.Add(pm => pm.ValueResolverConfig = config);
}
public void ResolveUsing<TSourceMember>(IMemberValueResolver<TSource, TDestination, TSourceMember, TMember> valueResolver, Expression<Func<TSource, TSourceMember>> sourceMember)
{
var config = new ValueResolverConfiguration(valueResolver, typeof(IMemberValueResolver<TSource, TDestination, TSourceMember, TMember>))
{
SourceMember = sourceMember
};
PropertyMapActions.Add(pm => pm.ValueResolverConfig = config);
}
public void ResolveUsing<TResult>(Func<TSource, TResult> resolver)
{
PropertyMapActions.Add(pm =>
{
Expression<Func<TSource, TDestination, TMember, ResolutionContext, TResult>> expr = (src, dest, destMember, ctxt) => resolver(src);
pm.CustomResolver = expr;
});
}
public void ResolveUsing<TResult>(Func<TSource, TDestination, TResult> resolver)
{
PropertyMapActions.Add(pm =>
{
Expression<Func<TSource, TDestination, TMember, ResolutionContext, TResult>> expr = (src, dest, destMember, ctxt) => resolver(src, dest);
pm.CustomResolver = expr;
});
}
public void ResolveUsing<TResult>(Func<TSource, TDestination, TMember, TResult> resolver)
{
PropertyMapActions.Add(pm =>
{
Expression<Func<TSource, TDestination, TMember, ResolutionContext, TResult>> expr = (src, dest, destMember, ctxt) => resolver(src, dest, destMember);
pm.CustomResolver = expr;
});
}
public void ResolveUsing<TResult>(Func<TSource, TDestination, TMember, ResolutionContext, TResult> resolver)
{
PropertyMapActions.Add(pm =>
{
Expression<Func<TSource, TDestination, TMember, ResolutionContext, TResult>> expr = (src, dest, destMember, ctxt) => resolver(src, dest, destMember, ctxt);
pm.CustomResolver = expr;
});
}
public void MapFrom<TSourceMember>(Expression<Func<TSource, TSourceMember>> sourceMember)
{
MapFromUntyped(sourceMember);
}
internal void MapFromUntyped(LambdaExpression sourceExpression)
{
_sourceMember = sourceExpression;
PropertyMapActions.Add(pm => pm.MapFrom(sourceExpression));
}
public void MapFrom(string sourceMember)
{
_sourceType.GetFieldOrProperty(sourceMember);
PropertyMapActions.Add(pm => pm.CustomSourceMemberName = sourceMember);
}
public void UseValue<TValue>(TValue value)
{
MapFrom(s => value);
}
public void Condition(Func<TSource, TDestination, TMember, TMember, ResolutionContext, bool> condition)
{
PropertyMapActions.Add(pm =>
{
Expression<Func<TSource, TDestination, TMember, TMember, ResolutionContext, bool>> expr =
(src, dest, srcMember, destMember, ctxt) => condition(src, dest, srcMember, destMember, ctxt);
pm.Condition = expr;
});
}
public void Condition(Func<TSource, TDestination, TMember, TMember, bool> condition)
{
PropertyMapActions.Add(pm =>
{
Expression<Func<TSource, TDestination, TMember, TMember, ResolutionContext, bool>> expr =
(src, dest, srcMember, destMember, ctxt) => condition(src, dest, srcMember, destMember);
pm.Condition = expr;
});
}
public void Condition(Func<TSource, TDestination, TMember, bool> condition)
{
PropertyMapActions.Add(pm =>
{
Expression<Func<TSource, TDestination, TMember, TMember, ResolutionContext, bool>> expr =
(src, dest, srcMember, destMember, ctxt) => condition(src, dest, srcMember);
pm.Condition = expr;
});
}
public void Condition(Func<TSource, TDestination, bool> condition)
{
PropertyMapActions.Add(pm =>
{
Expression<Func<TSource, TDestination, TMember, TMember, ResolutionContext, bool>> expr =
(src, dest, srcMember, destMember, ctxt) => condition(src, dest);
pm.Condition = expr;
});
}
public void Condition(Func<TSource, bool> condition)
{
PropertyMapActions.Add(pm =>
{
Expression<Func<TSource, TDestination, TMember, TMember, ResolutionContext, bool>> expr =
(src, dest, srcMember, destMember, ctxt) => condition(src);
pm.Condition = expr;
});
}
public void PreCondition(Func<TSource, bool> condition)
{
PropertyMapActions.Add(pm =>
{
Expression<Func<TSource, ResolutionContext, bool>> expr =
(src, ctxt) => condition(src);
pm.PreCondition = expr;
});
}
public void PreCondition(Func<ResolutionContext, bool> condition)
{
PropertyMapActions.Add(pm =>
{
Expression<Func<TSource, ResolutionContext, bool>> expr =
(src, ctxt) => condition(ctxt);
pm.PreCondition = expr;
});
}
public void PreCondition(Func<TSource, ResolutionContext, bool> condition)
{
PropertyMapActions.Add(pm =>
{
Expression<Func<TSource, ResolutionContext, bool>> expr =
(src, ctxt) => condition(src, ctxt);
pm.PreCondition = expr;
});
}
public void AddTransform(Expression<Func<TMember, TMember>> transformer)
{
PropertyMapActions.Add(pm =>
{
var config = new ValueTransformerConfiguration(typeof(TMember), transformer);
pm.AddValueTransformation(config);
});
}
public void ExplicitExpansion()
{
PropertyMapActions.Add(pm => pm.ExplicitExpansion = true);
}
public void Ignore() => Ignore(ignorePaths: true);
internal void Ignore(bool ignorePaths) =>
PropertyMapActions.Add(pm =>
{
pm.Ignored = true;
if(ignorePaths)
{
pm.TypeMap.IgnorePaths(DestinationMember);
}
});
public void AllowNull()
{
PropertyMapActions.Add(pm => pm.AllowNull = true);
}
public void UseDestinationValue()
{
PropertyMapActions.Add(pm => pm.UseDestinationValue = true);
}
public void SetMappingOrder(int mappingOrder)
{
PropertyMapActions.Add(pm => pm.MappingOrder = mappingOrder);
}
public void Configure(TypeMap typeMap)
{
var destMember = _destinationMember;
if(destMember.DeclaringType.IsGenericType())
{
destMember = typeMap.DestinationTypeDetails.PublicReadAccessors.Single(m => m.Name == destMember.Name);
}
var propertyMap = typeMap.FindOrCreatePropertyMapFor(destMember);
Apply(propertyMap);
}
private void Apply(PropertyMap propertyMap)
{
foreach(var action in PropertyMapActions)
{
action(propertyMap);
}
}
public IPropertyMapConfiguration Reverse()
{
var newSource = Parameter(DestinationMember.DeclaringType, "source");
var newSourceProperty = MakeMemberAccess(newSource, _destinationMember);
var newSourceExpression = Lambda(newSourceProperty, newSource);
return PathConfigurationExpression<TDestination, TSource, object>.Create(_sourceMember, newSourceExpression);
}
}
}