Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
chaowlert committed Mar 6, 2019
1 parent 3f02b6d commit 41259a2
Show file tree
Hide file tree
Showing 18 changed files with 97 additions and 57 deletions.
1 change: 0 additions & 1 deletion src/Mapster/Adapters/ArrayAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ namespace Mapster.Adapters
public class ArrayAdapter : BaseAdapter
{
protected override int Score => -123;
protected override bool CheckExplicitMapping => false;

protected override bool CanMap(PreCompileArgument arg)
{
Expand Down
30 changes: 13 additions & 17 deletions src/Mapster/Adapters/BaseAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ namespace Mapster.Adapters
public abstract class BaseAdapter
{
protected virtual int Score => 0;
protected virtual bool CheckExplicitMapping => true;
protected virtual bool CheckExplicitMapping => false;
protected virtual bool UseTargetValue => false;

public virtual int? Priority(PreCompileArgument arg)
{
Expand Down Expand Up @@ -72,14 +73,8 @@ protected virtual bool CanInline(Expression source, Expression destination, Comp

protected virtual Expression CreateExpressionBody(Expression source, Expression destination, CompileArgument arg)
{
if (this.CheckExplicitMapping)
{
if (arg.Settings.MaxDepth <= 0)
return arg.DestinationType.CreateDefault();

if (arg.Context.Config.RequireExplicitMapping && !arg.ExplicitMapping)
throw new InvalidOperationException("Implicit mapping is not allowed (check GlobalSettings.RequireExplicitMapping) and no configuration exists");
}
if (this.CheckExplicitMapping && arg.Context.Config.RequireExplicitMapping && !arg.ExplicitMapping)
throw new InvalidOperationException("Implicit mapping is not allowed (check GlobalSettings.RequireExplicitMapping) and no configuration exists");

if (CanInline(source, destination, arg) && arg.Settings.AvoidInlineMapping != true)
return CreateInlineExpressionBody(source, arg).To(arg.DestinationType, true);
Expand All @@ -100,6 +95,11 @@ protected Expression CreateBlockExpressionBody(Expression source, Expression des

if (set.NodeType != ExpressionType.Throw)
{
if (arg.MapType == MapType.MapToTarget && this.UseTargetValue && arg.GetConstructUsing()?.Parameters.Count != 2)
{
set = Expression.Coalesce(destination, set);
}

var actions = new List<Expression>
{
Expression.Assign(result, set)
Expand Down Expand Up @@ -280,19 +280,18 @@ protected virtual Expression CreateInstantiationExpression(Expression source, Ex
//new TDestination()

//if there is constructUsing, use constructUsing
var constructUsing = arg.Settings.ConstructUsingFactory?.Invoke(arg);
Expression newObj;
var constructUsing = arg.GetConstructUsing();
if (constructUsing != null)
newObj = constructUsing.Apply(source).TrimConversion(true).To(arg.DestinationType);
return constructUsing.Apply(source, destination).TrimConversion(true).To(arg.DestinationType);

//if there is default constructor, use default constructor
else if (arg.DestinationType.HasDefaultConstructor())
newObj = Expression.New(arg.DestinationType);
return Expression.New(arg.DestinationType);

//if mapToTarget or include derived types, allow mapping & throw exception on runtime
//instantiation is not needed
else if (destination != null || arg.Settings.Includes.Count > 0)
newObj = Expression.Throw(
return Expression.Throw(
Expression.New(
// ReSharper disable once AssignNullToNotNullAttribute
typeof(InvalidOperationException).GetConstructor(new[] { typeof(string) }),
Expand All @@ -302,9 +301,6 @@ protected virtual Expression CreateInstantiationExpression(Expression source, Ex
//otherwise throw
else
throw new InvalidOperationException($"No default constructor for type '{arg.DestinationType.Name}', please use 'ConstructUsing'");

//dest ?? new TDest();
return newObj;
}

protected Expression CreateAdaptExpression(Expression source, Type destinationType, CompileArgument arg)
Expand Down
11 changes: 8 additions & 3 deletions src/Mapster/Adapters/BaseClassAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,30 @@ namespace Mapster.Adapters
{
internal abstract class BaseClassAdapter : BaseAdapter
{
protected override bool CheckExplicitMapping => true;
protected override bool UseTargetValue => true;

#region Build the Adapter Model

protected ClassMapping CreateClassConverter(Expression source, ClassModel classModel, CompileArgument arg)
{
var destinationMembers = classModel.Members;
var unmappedDestinationMembers = new List<string>();
var properties = new List<MemberMapping>();
var includeResolvers = arg.Settings.Resolvers
.Where(it => it.DestinationMemberName == "")
.ToList();

foreach (var destinationMember in destinationMembers)
{
if (ProcessIgnores(arg, destinationMember, out var setterCondition))
continue;

var member = destinationMember;
var resolvers = arg.Settings.ValueAccessingStrategies.AsEnumerable();
if (arg.Settings.IgnoreNonMapped == true)
resolvers = resolvers.Where(ValueAccessingStrategy.CustomResolvers.Contains);
var getter = resolvers
.Select(fn => fn(source, member, arg))
.Select(fn => fn(source, destinationMember, arg))
.FirstOrDefault(result => result != null);

if (getter != null)
Expand All @@ -43,7 +48,7 @@ protected ClassMapping CreateClassConverter(Expression source, ClassModel classM
}
else if (classModel.ConstructorInfo != null)
{
var info = (ParameterInfo)member.Info;
var info = (ParameterInfo)destinationMember.Info;
if (!info.IsOptional)
return null;
var propertyModel = new MemberMapping
Expand Down
4 changes: 2 additions & 2 deletions src/Mapster/Adapters/ClassAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ protected override bool CanInline(Expression source, Expression destination, Com

if (arg.MapType == MapType.MapToTarget)
return false;
var constructUsing = arg.Settings.ConstructUsingFactory?.Invoke(arg);
var constructUsing = arg.GetConstructUsing();
if (constructUsing != null &&
constructUsing.Body.NodeType != ExpressionType.New &&
constructUsing.Body.NodeType != ExpressionType.MemberInit)
Expand All @@ -54,7 +54,7 @@ protected override Expression CreateInstantiationExpression(Expression source, E
{
//new TDestination(src.Prop1, src.Prop2)

if (arg.Settings.ConstructUsingFactory != null || arg.Settings.MapToConstructor != true)
if (arg.GetConstructUsing() != null || arg.Settings.MapToConstructor != true)
return base.CreateInstantiationExpression(source, destination, arg);

var classConverter = arg.DestinationType.GetConstructors()
Expand Down
18 changes: 12 additions & 6 deletions src/Mapster/Adapters/CollectionAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace Mapster.Adapters
internal class CollectionAdapter : BaseAdapter
{
protected override int Score => -125;
protected override bool CheckExplicitMapping => false;
protected override bool UseTargetValue => true;

protected override bool CanMap(PreCompileArgument arg)
{
Expand Down Expand Up @@ -79,9 +79,16 @@ protected override Expression CreateBlockExpression(Expression source, Expressio
? typeof(ICollection<>).MakeGenericType(destinationElementType)
: typeof(IList);
var tmp = Expression.Variable(listType, "list");
var assign = ExpressionEx.Assign(tmp, destination); //convert to list type
var set = CreateListSet(source, tmp, arg);
return Expression.Block(new[] { tmp }, assign, set);
var actions = new List<Expression> {
ExpressionEx.Assign(tmp, destination) //convert to list type
};
if (arg.MapType == MapType.MapToTarget)
{
var clear = listType.GetMethod("Clear", Type.EmptyTypes);
actions.Add(Expression.Call(tmp, clear));
}
actions.Add(CreateListSet(source, tmp, arg));
return Expression.Block(new[] { tmp }, actions);
}

protected override Expression CreateInlineExpression(Expression source, CompileArgument arg)
Expand Down Expand Up @@ -159,8 +166,7 @@ private Expression CreateListSet(Expression source, Expression destination, Comp
destination,
addMethod,
getter);
var loop = ExpressionEx.ForLoop(source, item, set);
return loop;
return ExpressionEx.ForLoop(source, item, set);
}
}
}
6 changes: 3 additions & 3 deletions src/Mapster/Adapters/DictionaryAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ protected override Expression CreateBlockExpression(Expression source, Expressio
Expression.Assign(
key,
Expression.Call(
Expression.Constant(arg.Settings.NameMatchingStrategy.SourceMemberNameConverter),
MapsterHelper.GetConverterExpression(arg.Settings.NameMatchingStrategy.SourceMemberNameConverter),
"Invoke",
null,
key)),
Expand Down Expand Up @@ -205,7 +205,7 @@ private ClassModel GetClassModel(CompileArgument arg)
var getMethod = typeof(MapsterHelper).GetMethods()
.First(m => m.Name == nameof(MapsterHelper.FlexibleGet))
.MakeGenericMethod(args[1]);
var destNameConverter = Expression.Constant(strategy.DestinationMemberNameConverter);
var destNameConverter = MapsterHelper.GetConverterExpression(strategy.DestinationMemberNameConverter);
return (dict, key) => Expression.Call(getMethod, dict, key, destNameConverter);
}
else
Expand All @@ -228,7 +228,7 @@ private ClassModel GetClassModel(CompileArgument arg)
var setMethod = typeof(MapsterHelper).GetMethods()
.First(m => m.Name == nameof(MapsterHelper.FlexibleSet))
.MakeGenericMethod(args[1]);
var destNameConverter = Expression.Constant(strategy.DestinationMemberNameConverter);
var destNameConverter = MapsterHelper.GetConverterExpression(strategy.DestinationMemberNameConverter);
return (dict, key, value) => Expression.Call(setMethod, dict, key, destNameConverter, value);
}
else
Expand Down
1 change: 0 additions & 1 deletion src/Mapster/Adapters/EnumAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ namespace Mapster.Adapters
internal class EnumAdapter : PrimitiveAdapter
{
protected override int Score => -109; //must do before StringAdapter
protected override bool CheckExplicitMapping => false;

protected override bool CanMap(PreCompileArgument arg)
{
Expand Down
1 change: 0 additions & 1 deletion src/Mapster/Adapters/MultiDimensionalArrayAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ namespace Mapster.Adapters
public class MultiDimensionalArrayAdapter : BaseAdapter
{
protected override int Score => -122;
protected override bool CheckExplicitMapping => false;

protected override bool CanMap(PreCompileArgument arg)
{
Expand Down
1 change: 0 additions & 1 deletion src/Mapster/Adapters/ObjectAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ namespace Mapster.Adapters
internal class ObjectAdapter : BaseAdapter
{
protected override int Score => -111; //must do before all class adapters
protected override bool CheckExplicitMapping => false;

protected override bool CanMap(PreCompileArgument arg)
{
Expand Down
1 change: 0 additions & 1 deletion src/Mapster/Adapters/PrimitiveAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ namespace Mapster.Adapters
internal class PrimitiveAdapter : BaseAdapter
{
protected override int Score => -200; //must do last
protected override bool CheckExplicitMapping => false;

protected override bool CanMap(PreCompileArgument arg)
{
Expand Down
3 changes: 2 additions & 1 deletion src/Mapster/Adapters/RecordTypeAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ namespace Mapster.Adapters
internal class RecordTypeAdapter : BaseClassAdapter
{
protected override int Score => -149;
protected override bool UseTargetValue => false;

protected override bool CanMap(PreCompileArgument arg)
{
Expand All @@ -16,7 +17,7 @@ protected override Expression CreateInstantiationExpression(Expression source, E
{
//new TDestination(src.Prop1, src.Prop2)

if (arg.Settings.ConstructUsingFactory != null)
if (arg.GetConstructUsing() != null)
return base.CreateInstantiationExpression(source, destination, arg);

var ctor = arg.DestinationType.GetConstructors()[0];
Expand Down
1 change: 0 additions & 1 deletion src/Mapster/Adapters/StringAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ namespace Mapster.Adapters
internal class StringAdapter : PrimitiveAdapter
{
protected override int Score => -110; //must do before all class adapters
protected override bool CheckExplicitMapping => false;

protected override bool CanMap(PreCompileArgument arg)
{
Expand Down
17 changes: 15 additions & 2 deletions src/Mapster/Compile/CompileArgument.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

namespace Mapster
{
Expand All @@ -15,19 +16,31 @@ public class CompileArgument
public CompileContext Context;

private HashSet<string> _srcNames;
public HashSet<string> GetSourceNames()
internal HashSet<string> GetSourceNames()
{
return _srcNames ?? (_srcNames = (from it in Settings.Resolvers
where it.SourceMemberName != null
select it.SourceMemberName.Split('.').First()).ToHashSet());
}

private HashSet<string> _destNames;
public HashSet<string> GetDestinationNames()
internal HashSet<string> GetDestinationNames()
{
return _destNames ?? (_destNames = (from it in Settings.Resolvers
where it.DestinationMemberName != null
select it.DestinationMemberName.Split('.').First()).ToHashSet());
}

private bool _fetchConstructUsing;
private LambdaExpression _constructUsing;
internal LambdaExpression GetConstructUsing()
{
if (!_fetchConstructUsing)
{
_constructUsing = Settings.ConstructUsingFactory?.Invoke(this);
_fetchConstructUsing = true;
}
return _constructUsing;
}
}
}
2 changes: 1 addition & 1 deletion src/Mapster/Settings/ValueAccessingStrategy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ private static Expression DictionaryFn(Expression source, IMemberModel destinati
if (strategy.SourceMemberNameConverter != NameMatchingStrategy.Identity)
{
var method = typeof(MapsterHelper).GetMethods().First(m => m.Name == nameof(MapsterHelper.FlexibleGet)).MakeGenericMethod(args[1]);
return Expression.Call(method, source.To(dictType), key, Expression.Constant(strategy.SourceMemberNameConverter));
return Expression.Call(method, source.To(dictType), key, MapsterHelper.GetConverterExpression(strategy.SourceMemberNameConverter));
}
else
{
Expand Down
28 changes: 18 additions & 10 deletions src/Mapster/TypeAdapterSetter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -211,14 +211,6 @@ public static class TypeAdapterSetterExtensions
return setter;
}

public static TSetter MaxDepth<TSetter>(this TSetter setter, int? value) where TSetter : TypeAdapterSetter
{
setter.CheckCompiled();

setter.Settings.MaxDepth = value;
return setter;
}

public static TSetter MapToConstructor<TSetter>(this TSetter setter, bool value) where TSetter : TypeAdapterSetter
{
setter.CheckCompiled();
Expand All @@ -240,7 +232,7 @@ public TypeAdapterSetter<TDestination> Ignore(params Expression<Func<TDestinatio

foreach (var member in members)
{
Settings.IgnoreIfs[ReflectionUtils.GetMemberPath(member)] = null;
Settings.IgnoreIfs[ReflectionUtils.GetMemberPath(member, true)] = null;
}
return this;
}
Expand Down Expand Up @@ -371,7 +363,7 @@ internal TypeAdapterSetter(TypeAdapterSettings settings, TypeAdapterConfig paren

foreach (var member in members)
{
var name = ReflectionUtils.GetMemberPath(member);
var name = ReflectionUtils.GetMemberPath(member, true);
Settings.IgnoreIfs.Merge(name, condition);
}
return this;
Expand Down Expand Up @@ -512,6 +504,22 @@ internal TypeAdapterSetter(TypeAdapterSettings settings, TypeAdapterConfig paren
return this;
}

public TypeAdapterSetter<TSource, TDestination> BeforeMappingInline(Expression<Action<TSource, TDestination>> action)
{
this.CheckCompiled();

Settings.BeforeMappingFactories.Add(arg => action);
return this;
}

public TypeAdapterSetter<TSource, TDestination> AfterMappingInline(Expression<Action<TSource, TDestination>> action)
{
this.CheckCompiled();

Settings.AfterMappingFactories.Add(arg => action);
return this;
}

public TypeAdapterSetter<TSource, TDestination> Include<TDerivedSource, TDerivedDestination>()
where TDerivedSource: class, TSource
where TDerivedDestination: class, TDestination
Expand Down
5 changes: 0 additions & 5 deletions src/Mapster/TypeAdapterSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,6 @@ public NameMatchingStrategy NameMatchingStrategy
get => Get("NameMatchingStrategy", () => new NameMatchingStrategy());
set => Set("NameMatchingStrategy", value);
}
public int? MaxDepth
{
get => Get<int?>("MaxDepth");
set => Set("MaxDepth", value);
}

public bool? PreserveReference
{
Expand Down
Loading

0 comments on commit 41259a2

Please sign in to comment.