Skip to content

Commit 14f4258

Browse files
committed
fix UseDestinationValue with collection
1 parent 96ab098 commit 14f4258

File tree

7 files changed

+50
-9
lines changed

7 files changed

+50
-9
lines changed

src/Mapster.Tests/WhenUsingDestinationValue.cs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
using System.Linq.Expressions;
1+
using System.Collections.Generic;
2+
using System.Linq;
3+
using System.Linq.Expressions;
24
using Microsoft.VisualStudio.TestTools.UnitTesting;
35
using Shouldly;
46

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

1518
var dto = new InvoiceDto
1619
{
1720
Id = 1,
1821
DocumentNumber = "AA001",
1922
SupplierCompany = "COM01",
20-
SupplierName = "Apple"
23+
SupplierName = "Apple",
24+
Numbers = Enumerable.Range(1, 5).ToList(),
2125
};
2226
var poco = dto.Adapt<Invoice>();
2327
poco.Id.ShouldBe(dto.Id);
2428
poco.DocumentNumber.ShouldBe("FOO");
2529
poco.Supplier.Name.ShouldBe(dto.SupplierName);
2630
poco.Supplier.Company.ShouldBe(dto.SupplierCompany);
31+
poco.Numbers.ShouldBe(Enumerable.Range(1, 5));
2732
}
2833

2934
public class ContractingParty
@@ -41,6 +46,9 @@ public class Invoice
4146

4247
[UseDestinationValue]
4348
public ContractingParty Supplier { get; } = new ContractingParty();
49+
50+
[UseDestinationValue]
51+
public ICollection<int> Numbers { get; } = new List<int>();
4452
}
4553

4654
public class InvoiceDto
@@ -49,6 +57,7 @@ public class InvoiceDto
4957
public string DocumentNumber { get; set; }
5058
public string SupplierName { get; set; }
5159
public string SupplierCompany { get; set; }
60+
public IEnumerable<int> Numbers { get; set; }
5261
}
5362
}
5463
}

src/Mapster/Adapters/ArrayAdapter.cs

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Collections.Generic;
23
using System.Linq;
34
using System.Linq.Expressions;
45
using System.Reflection;
@@ -19,7 +20,26 @@ protected override bool CanMap(PreCompileArgument arg)
1920

2021
protected override bool CanInline(Expression source, Expression? destination, CompileArgument arg)
2122
{
22-
return arg.MapType == MapType.Projection || ExpressionEx.CreateCountExpression(source) == null;
23+
return arg.MapType == MapType.Projection;
24+
}
25+
26+
protected override Expression TransformSource(Expression source)
27+
{
28+
if (ExpressionEx.CreateCountExpression(source) != null)
29+
return source;
30+
var transformed = source;
31+
var elemType = source.Type.ExtractCollectionType();
32+
var type = typeof(IEnumerable<>).MakeGenericType(elemType);
33+
if (!type.IsAssignableFrom(source.Type))
34+
{
35+
var cast = typeof(Enumerable).GetMethod(nameof(Enumerable.Cast))!
36+
.MakeGenericMethod(elemType);
37+
transformed = Expression.Call(cast, transformed);
38+
}
39+
40+
var toList = typeof(Enumerable).GetMethod(nameof(Enumerable.ToList))!
41+
.MakeGenericMethod(elemType);
42+
return Expression.Call(toList, transformed);
2343
}
2444

2545
protected override Expression CreateInstantiationExpression(Expression source, Expression? destination, CompileArgument arg)
@@ -39,7 +59,12 @@ protected override Expression CreateBlockExpression(Expression source, Expressio
3959
{
4060
//Array.Copy(src, 0, dest, 0, src.Length)
4161
var method = typeof(Array).GetMethod("Copy", new[] { typeof(Array), typeof(int), typeof(Array), typeof(int), typeof(int) });
42-
return Expression.Call(method, source, Expression.Constant(0), destination, Expression.Constant(0), ExpressionEx.CreateCountExpression(source));
62+
var len = arg.UseDestinationValue
63+
? Expression.Call(typeof(Math).GetMethod("Min", new[] {typeof(int), typeof(int)}),
64+
ExpressionEx.CreateCountExpression(source),
65+
ExpressionEx.CreateCountExpression(destination))
66+
: ExpressionEx.CreateCountExpression(source);
67+
return Expression.Call(method, source, Expression.Constant(0), destination, Expression.Constant(0), len);
4368
}
4469

4570
return CreateArraySet(source, destination, arg);

src/Mapster/Adapters/BaseAdapter.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ protected virtual Expression CreateExpressionBody(Expression source, Expression?
111111

112112
if (arg.Context.Running.Count > 1 &&
113113
!arg.Context.Config.SelfContainedCodeGeneration &&
114+
!arg.UseDestinationValue &&
114115
!arg.Context.IsSubFunction())
115116
{
116117
if (destination == null)
@@ -195,7 +196,7 @@ protected Expression CreateBlockExpressionBody(Expression source, Expression? de
195196
transformedSource = src;
196197
}
197198
var set = CreateInstantiationExpression(transformedSource, destination, arg);
198-
if (destination != null && this.UseTargetValue && arg.GetConstructUsing()?.Parameters.Count != 2 && destination.CanBeNull())
199+
if (destination != null && (this.UseTargetValue || arg.UseDestinationValue) && arg.GetConstructUsing()?.Parameters.Count != 2 && destination.CanBeNull())
199200
{
200201
//dest ?? new TDest();
201202
set = Expression.Coalesce(destination, set);

src/Mapster/Adapters/CollectionAdapter.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,13 @@ protected override Expression CreateBlockExpression(Expression source, Expressio
9494
actions.Add(ExpressionEx.Assign(list, destination)); //convert to list type
9595
}
9696

97+
//list.Clear();
98+
if (arg.UseDestinationValue && arg.MapType == MapType.MapToTarget)
99+
{
100+
var clear = list.Type.GetMethod("Clear", Type.EmptyTypes);
101+
actions.Add(Expression.Call(list, clear));
102+
}
103+
97104
actions.Add(CreateListSet(source, list, arg));
98105

99106
if (shouldConvert)

src/Mapster/Adapters/DictionaryAdapter.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,10 @@ protected override Expression CreateBlockExpression(Expression source, Expressio
7070
: mapped;
7171
}
7272

73-
7473
//if (object.ReferenceEquals(source, destination))
7574
// return destination;
7675
LabelTarget? label = null;
77-
if (destination != null &&
78-
source.Type.IsObjectReference() &&
76+
if (source.Type.IsObjectReference() &&
7977
destination.Type.IsObjectReference() &&
8078
(source.Type.IsAssignableFrom(destination.Type) || destination.Type.IsAssignableFrom(source.Type)))
8179
{
@@ -84,7 +82,6 @@ protected override Expression CreateBlockExpression(Expression source, Expressio
8482
actions.Add(Expression.IfThen(refEquals, Expression.Return(label, destination)));
8583
}
8684

87-
8885
var keyType = srcDictType.GetGenericArguments().First();
8986
var kvpType = source.Type.ExtractCollectionType();
9087
var kvp = Expression.Variable(kvpType, "kvp");

src/Mapster/Compile/CompileArgument.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ public class CompileArgument
1414
public bool ExplicitMapping { get; set; }
1515
public TypeAdapterSettings Settings { get; set; }
1616
public CompileContext Context { get; set; }
17+
public bool UseDestinationValue { get; set; }
1718

1819
private HashSet<string>? _srcNames;
1920
internal HashSet<string> GetSourceNames()

src/Mapster/TypeAdapterConfig.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,7 @@ internal LambdaExpression CreateInlineMapExpression(Type sourceType, Type destin
407407
{
408408
arg.Settings.Resolvers.AddRange(mapping.NextResolvers);
409409
arg.Settings.Ignore.Apply(mapping.NextIgnore);
410+
arg.UseDestinationValue = mapping.UseDestinationValue;
410411
}
411412

412413
return CreateMapExpression(arg);

0 commit comments

Comments
 (0)