Skip to content

Commit

Permalink
Merge pull request MapsterMapper#26 from chaowlert/master
Browse files Browse the repository at this point in the history
Move MapContext usage to inside PreserveReference block
  • Loading branch information
eswann committed Jan 23, 2016
2 parents e601e1e + 2e05310 commit 40aaa28
Show file tree
Hide file tree
Showing 10 changed files with 148 additions and 266 deletions.
1 change: 0 additions & 1 deletion src/Mapster.Tests/Mapster.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@
<Compile Include="WhenMappingPrimitives.cs" />
<Compile Include="WhenConfiguringMapping.cs" />
<Compile Include="WhenMappingWithInstance.cs" />
<Compile Include="WhenMappingWithMaxDepth.cs" />
<Compile Include="WhenPerformingDestinationTransforms.cs" />
<Compile Include="WhenProjecting.cs" />
<Compile Include="WhenRegisteringAndMappingRace.cs" />
Expand Down
129 changes: 0 additions & 129 deletions src/Mapster.Tests/WhenMappingWithMaxDepth.cs

This file was deleted.

41 changes: 5 additions & 36 deletions src/Mapster/Adapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,62 +25,31 @@ public Adapter(TypeAdapterConfig config)
public TDestination Adapt<TDestination>(object source)
{
dynamic fn = _config.GetMapFunction(source.GetType(), typeof(TDestination));
try
{
return (TDestination)fn((dynamic)source);
}
finally
{
MapContext.Clear();
}
return (TDestination)fn((dynamic)source);
}

public TDestination Adapt<TSource, TDestination>(TSource source)
{
var fn = _config.GetMapFunction<TSource, TDestination>();
try
{
return fn(source);
}
finally
{
MapContext.Clear();
}
return fn(source);
}

public TDestination Adapt<TSource, TDestination>(TSource source, TDestination destination)
{
var fn = _config.GetMapToTargetFunction<TSource, TDestination>();

try
{
return fn(source, destination);
}
finally
{
MapContext.Clear();
}
return fn(source, destination);
}

public object Adapt(object source, Type sourceType, Type destinationType)
{
var fn = _config.GetMapFunction(sourceType, destinationType);
var result = fn.DynamicInvoke(source);
MapContext.Clear();
return result;
return fn.DynamicInvoke(source);
}

public object Adapt(object source, object destination, Type sourceType, Type destinationType)
{
dynamic fn = _config.GetMapFunction(sourceType, destinationType);
try
{
return fn((dynamic)source);
}
finally
{
MapContext.Clear();
}
return fn((dynamic)source);
}
}

Expand Down
48 changes: 39 additions & 9 deletions src/Mapster/Adapters/BaseAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@ protected virtual bool CanInline(Expression source, Expression destination, Comp
{
if (destination != null)
return false;
if (arg.Settings.ConstructUsing != null && arg.Settings.ConstructUsing.Body.NodeType != ExpressionType.New)
if (arg.Settings.ConstructUsing != null &&
arg.Settings.ConstructUsing.Body.NodeType != ExpressionType.New &&
arg.Settings.ConstructUsing.Body.NodeType != ExpressionType.MemberInit)
return false;
if (arg.Settings.PreserveReference == true &&
arg.MapType != MapType.Projection &&
Expand Down Expand Up @@ -76,29 +78,53 @@ protected Expression CreateBlockExpressionBody(Expression source, Expression des
!arg.SourceType.GetTypeInfo().IsValueType &&
!arg.DestinationType.GetTypeInfo().IsValueType)
{
var dict = Expression.Parameter(typeof (Dictionary<object, object>));
var propInfo = typeof(MapContext).GetProperty("Context", BindingFlags.Static | BindingFlags.Public);
var refContext = Expression.Property(null, propInfo);
//using (var scope = new MapContextScope()) {
// var dict = scope.Context.Reference;
// object cache;
// if (dict.TryGetValue(source, out cache))
// result = (TDestination)cache;
// else {
// result = new TDestination();
// dict.Add(source, (object)result);
// result.Prop1 = adapt(source.Prop1);
// result.Prop2 = adapt(source.Prop2);
// }
//}

var scope = Expression.Variable(typeof(MapContextScope));
var newScope = Expression.Assign(scope, Expression.New(typeof(MapContextScope)));

var dict = Expression.Variable(typeof (Dictionary<object, object>));
var refContext = Expression.Property(scope, "Context");
var refDict = Expression.Property(refContext, "References");
var assignDict = Expression.Assign(dict, refDict);

var refAdd = Expression.Call(dict, "Add", null, Expression.Convert(source, typeof(object)), Expression.Convert(result, typeof(object)));
set = Expression.Block(assign, refAdd, set);
var setResultAndCache = Expression.Block(assign, refAdd, set);

var cached = Expression.Variable(typeof(object));
var tryGetMethod = typeof(Dictionary<object, object>).GetMethod("TryGetValue", new[] { typeof(object), typeof(object).MakeByRefType() });
var checkHasRef = Expression.Call(dict, tryGetMethod, source, cached);
var assignDict = Expression.Assign(dict, refDict);
set = Expression.IfThenElse(
var setResult = Expression.IfThenElse(
checkHasRef,
ExpressionEx.Assign(result, cached),
set);
set = Expression.Block(new[] { cached, dict }, assignDict, set);
setResultAndCache);
var usingBody = Expression.Block(new[] { cached, dict }, assignDict, setResult);

var dispose = Expression.Call(scope, "Dispose", null);
set = Expression.Block(new[] { scope }, newScope, Expression.TryFinally(usingBody, dispose));
}
else
{
set = Expression.Block(assign, set);
}

//TDestination result;
//if (source == null)
// result = default(TDestination);
//else
// result = adapt(source);
//return result;
if (arg.MapType != MapType.Projection &&
(!arg.SourceType.GetTypeInfo().IsValueType || arg.SourceType.IsNullable()))
{
Expand All @@ -113,6 +139,8 @@ protected Expression CreateBlockExpressionBody(Expression source, Expression des
}
protected Expression CreateInlineExpressionBody(Expression source, CompileArgument arg)
{
//source == null ? default(TDestination) : convert(source)

var exp = CreateInlineExpression(source, arg);

if (arg.MapType != MapType.Projection
Expand All @@ -133,6 +161,8 @@ protected Expression CreateInlineExpressionBody(Expression source, CompileArgume

protected virtual Expression CreateInstantiationExpression(Expression source, CompileArgument arg)
{
//new TDestination()

return arg.Settings.ConstructUsing != null
? arg.Settings.ConstructUsing.Apply(source).TrimConversion().To(arg.DestinationType)
: Expression.New(arg.DestinationType);
Expand Down
21 changes: 20 additions & 1 deletion src/Mapster/Adapters/ClassAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,16 @@ protected override Expression CreateExpressionBody(Expression source, Expression

protected override Expression CreateBlockExpression(Expression source, Expression destination, CompileArgument arg)
{
//### !IgnoreNullValues
//dest.Prop1 = convert(src.Prop1);
//dest.Prop2 = convert(src.Prop2);

//### IgnoreNullValues
//if (src.Prop1 != null)
// dest.Prop1 = convert(src.Prop1);
//if (src.Prop2 != null)
// dest.Prop2 = convert(src.Prop2);

var properties = CreateAdapterModel(source, destination, arg);

var lines = new List<Expression>();
Expand All @@ -63,10 +73,19 @@ protected override Expression CreateBlockExpression(Expression source, Expressio

protected override Expression CreateInlineExpression(Expression source, CompileArgument arg)
{
var newInstance = (NewExpression)CreateInstantiationExpression(source, arg);
//new TDestination {
// Prop1 = convert(src.Prop1),
// Prop2 = convert(src.Prop2),
//}

var exp = CreateInstantiationExpression(source, arg);
var memberInit = exp as MemberInitExpression;
var newInstance = memberInit != null ? memberInit.NewExpression : (NewExpression)exp;
var properties = CreateAdapterModel(source, newInstance, arg);

var lines = new List<MemberBinding>();
if (memberInit != null)
lines.AddRange(memberInit.Bindings);
foreach (var property in properties)
{
var getter = CreateAdaptExpression(property.Getter, property.Setter.Type, arg);
Expand Down
Loading

0 comments on commit 40aaa28

Please sign in to comment.