Skip to content

Commit

Permalink
fix UseDestinationValue with collection
Browse files Browse the repository at this point in the history
  • Loading branch information
chaowlert committed Oct 23, 2020
1 parent 96ab098 commit 14f4258
Show file tree
Hide file tree
Showing 7 changed files with 50 additions and 9 deletions.
13 changes: 11 additions & 2 deletions src/Mapster.Tests/WhenUsingDestinationValue.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System.Linq.Expressions;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Shouldly;

Expand All @@ -10,20 +12,23 @@ public class WhenUsingDestinationValue
[TestMethod]
public void MapUsingDestinationValue()
{
TypeAdapterConfig.GlobalSettings.Compiler = exp => exp.CompileWithDebugInfo();
TypeAdapterConfig<Invoice, InvoiceDto>.NewConfig().TwoWays();

var dto = new InvoiceDto
{
Id = 1,
DocumentNumber = "AA001",
SupplierCompany = "COM01",
SupplierName = "Apple"
SupplierName = "Apple",
Numbers = Enumerable.Range(1, 5).ToList(),
};
var poco = dto.Adapt<Invoice>();
poco.Id.ShouldBe(dto.Id);
poco.DocumentNumber.ShouldBe("FOO");
poco.Supplier.Name.ShouldBe(dto.SupplierName);
poco.Supplier.Company.ShouldBe(dto.SupplierCompany);
poco.Numbers.ShouldBe(Enumerable.Range(1, 5));
}

public class ContractingParty
Expand All @@ -41,6 +46,9 @@ public class Invoice

[UseDestinationValue]
public ContractingParty Supplier { get; } = new ContractingParty();

[UseDestinationValue]
public ICollection<int> Numbers { get; } = new List<int>();
}

public class InvoiceDto
Expand All @@ -49,6 +57,7 @@ public class InvoiceDto
public string DocumentNumber { get; set; }
public string SupplierName { get; set; }
public string SupplierCompany { get; set; }
public IEnumerable<int> Numbers { get; set; }
}
}
}
29 changes: 27 additions & 2 deletions src/Mapster/Adapters/ArrayAdapter.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
Expand All @@ -19,7 +20,26 @@ protected override bool CanMap(PreCompileArgument arg)

protected override bool CanInline(Expression source, Expression? destination, CompileArgument arg)
{
return arg.MapType == MapType.Projection || ExpressionEx.CreateCountExpression(source) == null;
return arg.MapType == MapType.Projection;
}

protected override Expression TransformSource(Expression source)
{
if (ExpressionEx.CreateCountExpression(source) != null)
return source;
var transformed = source;
var elemType = source.Type.ExtractCollectionType();
var type = typeof(IEnumerable<>).MakeGenericType(elemType);
if (!type.IsAssignableFrom(source.Type))
{
var cast = typeof(Enumerable).GetMethod(nameof(Enumerable.Cast))!
.MakeGenericMethod(elemType);
transformed = Expression.Call(cast, transformed);
}

var toList = typeof(Enumerable).GetMethod(nameof(Enumerable.ToList))!
.MakeGenericMethod(elemType);
return Expression.Call(toList, transformed);
}

protected override Expression CreateInstantiationExpression(Expression source, Expression? destination, CompileArgument arg)
Expand All @@ -39,7 +59,12 @@ protected override Expression CreateBlockExpression(Expression source, Expressio
{
//Array.Copy(src, 0, dest, 0, src.Length)
var method = typeof(Array).GetMethod("Copy", new[] { typeof(Array), typeof(int), typeof(Array), typeof(int), typeof(int) });
return Expression.Call(method, source, Expression.Constant(0), destination, Expression.Constant(0), ExpressionEx.CreateCountExpression(source));
var len = arg.UseDestinationValue
? Expression.Call(typeof(Math).GetMethod("Min", new[] {typeof(int), typeof(int)}),
ExpressionEx.CreateCountExpression(source),
ExpressionEx.CreateCountExpression(destination))
: ExpressionEx.CreateCountExpression(source);
return Expression.Call(method, source, Expression.Constant(0), destination, Expression.Constant(0), len);
}

return CreateArraySet(source, destination, arg);
Expand Down
3 changes: 2 additions & 1 deletion src/Mapster/Adapters/BaseAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ protected virtual Expression CreateExpressionBody(Expression source, Expression?

if (arg.Context.Running.Count > 1 &&
!arg.Context.Config.SelfContainedCodeGeneration &&
!arg.UseDestinationValue &&
!arg.Context.IsSubFunction())
{
if (destination == null)
Expand Down Expand Up @@ -195,7 +196,7 @@ protected Expression CreateBlockExpressionBody(Expression source, Expression? de
transformedSource = src;
}
var set = CreateInstantiationExpression(transformedSource, destination, arg);
if (destination != null && this.UseTargetValue && arg.GetConstructUsing()?.Parameters.Count != 2 && destination.CanBeNull())
if (destination != null && (this.UseTargetValue || arg.UseDestinationValue) && arg.GetConstructUsing()?.Parameters.Count != 2 && destination.CanBeNull())
{
//dest ?? new TDest();
set = Expression.Coalesce(destination, set);
Expand Down
7 changes: 7 additions & 0 deletions src/Mapster/Adapters/CollectionAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,13 @@ protected override Expression CreateBlockExpression(Expression source, Expressio
actions.Add(ExpressionEx.Assign(list, destination)); //convert to list type
}

//list.Clear();
if (arg.UseDestinationValue && arg.MapType == MapType.MapToTarget)
{
var clear = list.Type.GetMethod("Clear", Type.EmptyTypes);
actions.Add(Expression.Call(list, clear));
}

actions.Add(CreateListSet(source, list, arg));

if (shouldConvert)
Expand Down
5 changes: 1 addition & 4 deletions src/Mapster/Adapters/DictionaryAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,10 @@ protected override Expression CreateBlockExpression(Expression source, Expressio
: mapped;
}


//if (object.ReferenceEquals(source, destination))
// return destination;
LabelTarget? label = null;
if (destination != null &&
source.Type.IsObjectReference() &&
if (source.Type.IsObjectReference() &&
destination.Type.IsObjectReference() &&
(source.Type.IsAssignableFrom(destination.Type) || destination.Type.IsAssignableFrom(source.Type)))
{
Expand All @@ -84,7 +82,6 @@ protected override Expression CreateBlockExpression(Expression source, Expressio
actions.Add(Expression.IfThen(refEquals, Expression.Return(label, destination)));
}


var keyType = srcDictType.GetGenericArguments().First();
var kvpType = source.Type.ExtractCollectionType();
var kvp = Expression.Variable(kvpType, "kvp");
Expand Down
1 change: 1 addition & 0 deletions src/Mapster/Compile/CompileArgument.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public class CompileArgument
public bool ExplicitMapping { get; set; }
public TypeAdapterSettings Settings { get; set; }
public CompileContext Context { get; set; }
public bool UseDestinationValue { get; set; }

private HashSet<string>? _srcNames;
internal HashSet<string> GetSourceNames()
Expand Down
1 change: 1 addition & 0 deletions src/Mapster/TypeAdapterConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,7 @@ internal LambdaExpression CreateInlineMapExpression(Type sourceType, Type destin
{
arg.Settings.Resolvers.AddRange(mapping.NextResolvers);
arg.Settings.Ignore.Apply(mapping.NextIgnore);
arg.UseDestinationValue = mapping.UseDestinationValue;
}

return CreateMapExpression(arg);
Expand Down

0 comments on commit 14f4258

Please sign in to comment.