Skip to content

Commit ee77747

Browse files
committed
fix #227: EmptyCollectionIfNull, CreateNewIfNull DestinationTransform
1 parent e2fd308 commit ee77747

File tree

7 files changed

+144
-85
lines changed

7 files changed

+144
-85
lines changed

src/Mapster.Tests/WhenPerformingDestinationTransforms.cs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Collections;
23
using System.Collections.Generic;
34
using Microsoft.VisualStudio.TestTools.UnitTesting;
45
using Shouldly;
@@ -52,6 +53,34 @@ public void Adapter_Destination_Transform_Is_Applied_To_Class()
5253
destination.Name.ShouldBe("TestMethod");
5354
}
5455

56+
[TestMethod]
57+
public void Adapter_Destination_Transform_Collection()
58+
{
59+
var config = new TypeAdapterConfig();
60+
config.Default.AddDestinationTransform((IReadOnlyList<ChildDto> list) => list ?? new List<ChildDto>());
61+
62+
var source = new CollectionPoco();
63+
var destination = source.Adapt<CollectionDto>(config);
64+
65+
destination.Children.ShouldNotBeNull();
66+
}
67+
68+
[TestMethod]
69+
public void Adapter_Destination_Transform_Collection_Generic()
70+
{
71+
var config = new TypeAdapterConfig();
72+
config.Default.AddDestinationTransform(DestinationTransform.EmptyCollectionIfNull);
73+
74+
var source = new CollectionPoco();
75+
var destination = source.Adapt<CollectionDto>(config);
76+
77+
destination.Children.Count.ShouldBe(0);
78+
destination.Array.Length.ShouldBe(0);
79+
destination.MultiDimentionalArray.Length.ShouldBe(0);
80+
destination.ChildDict.Count.ShouldBe(0);
81+
destination.Set.Count.ShouldBe(0);
82+
}
83+
5584
#region TestClasses
5685

5786
public class SimplePoco
@@ -84,6 +113,10 @@ public class CollectionPoco
84113
public string Name { get; set; }
85114

86115
public List<ChildPoco> Children { get; set; }
116+
public int[] Array { get; set; }
117+
public double[,] MultiDimentionalArray { get; set; }
118+
public Dictionary<string, ChildPoco> ChildDict { get; set; }
119+
public HashSet<string> Set { get; set; }
87120
}
88121

89122
public class CollectionDto
@@ -92,6 +125,10 @@ public class CollectionDto
92125
public string Name { get; set; }
93126

94127
public IReadOnlyList<ChildDto> Children { get; internal set; }
128+
public int[] Array { get; set; }
129+
public double[,] MultiDimentionalArray { get; set; }
130+
public IReadOnlyDictionary<string, ChildDto> ChildDict { get; set; }
131+
public HashSet<string> Set { get; set; }
95132
}
96133

97134
#endregion

src/Mapster/Adapters/BaseAdapter.cs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -409,11 +409,9 @@ internal Expression CreateAdaptExpression(Expression source, Type destinationTyp
409409
var exp = CreateAdaptExpressionCore(source, destinationType, arg, mapping, destination);
410410

411411
//transform(adapt(source));
412-
if (arg.Settings.DestinationTransforms.Transforms.ContainsKey(exp.Type))
413-
{
414-
var transform = arg.Settings.DestinationTransforms.Transforms[exp.Type];
415-
exp = transform.Apply(arg.MapType, exp);
416-
}
412+
var transform = arg.Settings.DestinationTransforms.FirstOrDefault(it => it.Condition(exp.Type));
413+
if (transform != null)
414+
exp = transform.TransformFunc(exp.Type).Apply(arg.MapType, exp);
417415
return exp.To(destinationType);
418416
}
419417
}

src/Mapster/Mapster.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
<NetStandardImplicitPackageVersion Condition=" '$(TargetFramework)' == 'netstandard1.3' ">1.6.1</NetStandardImplicitPackageVersion>
2020
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
2121
<RootNamespace>Mapster</RootNamespace>
22-
<Version>5.1.0</Version>
22+
<Version>5.2.0</Version>
2323
<LangVersion>8.0</LangVersion>
2424
<Nullable>enable</Nullable>
2525
</PropertyGroup>
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Linq.Expressions;
5+
using System.Reflection;
6+
7+
namespace Mapster
8+
{
9+
public class DestinationTransform
10+
{
11+
public static readonly DestinationTransform EmptyCollectionIfNull = new DestinationTransform
12+
{
13+
Condition = type => type.IsArray
14+
|| type.IsListCompatible()
15+
|| type.GetDictionaryType() != null,
16+
TransformFunc = type =>
17+
{
18+
Expression newExp;
19+
if (type.IsArray)
20+
{
21+
var rank = type.GetArrayRank();
22+
var elemType = type.GetElementType()!;
23+
newExp = Expression.NewArrayBounds(elemType, Enumerable.Repeat(Expression.Constant(0), rank));
24+
}
25+
else if (type.GetTypeInfo().IsInterface)
26+
{
27+
if (type.GetDictionaryType() != null)
28+
{
29+
var dict = type.GetDictionaryType()!;
30+
var dictArgs = dict.GetGenericArguments();
31+
var dictType = typeof(Dictionary<,>).MakeGenericType(dictArgs);
32+
newExp = Expression.New(dictType);
33+
}
34+
else
35+
{
36+
var elemType = type.ExtractCollectionType();
37+
var listType = typeof(List<>).MakeGenericType(elemType);
38+
newExp = Expression.New(listType);
39+
}
40+
}
41+
else
42+
newExp = Expression.New(type);
43+
44+
var p = Expression.Parameter(type);
45+
return Expression.Lambda(Expression.Coalesce(p, newExp), p);
46+
}
47+
};
48+
49+
public static readonly DestinationTransform CreateNewIfNull = new DestinationTransform
50+
{
51+
Condition = type =>
52+
{
53+
if (!type.CanBeNull())
54+
return false;
55+
if (type.GetTypeInfo().IsInterface || type.GetTypeInfo().IsAbstract)
56+
return false;
57+
var ci = type.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).SingleOrDefault(c => c.GetParameters().Length == 0);
58+
return ci != null;
59+
},
60+
TransformFunc = type =>
61+
{
62+
var p = Expression.Parameter(type);
63+
return Expression.Lambda(
64+
Expression.Coalesce(p, Expression.New(type)));
65+
}
66+
};
67+
68+
public Func<Type, bool> Condition { get; set; }
69+
public Func<Type, LambdaExpression> TransformFunc { get; set; }
70+
71+
public DestinationTransform WithCondition(Func<Type, bool> condition)
72+
{
73+
return new DestinationTransform
74+
{
75+
Condition = condition,
76+
TransformFunc = this.TransformFunc
77+
};
78+
}
79+
}
80+
}

src/Mapster/Settings/TransformsCollection.cs

Lines changed: 0 additions & 76 deletions
This file was deleted.

src/Mapster/TypeAdapterSetter.cs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,19 @@ public static TSetter AddDestinationTransform<TSetter, TDestinationMember>(this
2929
{
3030
setter.CheckCompiled();
3131

32-
setter.Settings.DestinationTransforms.Upsert(transform);
32+
setter.Settings.DestinationTransforms.Add(new DestinationTransform
33+
{
34+
Condition = t => t == typeof(TDestinationMember),
35+
TransformFunc = _ => transform,
36+
});
37+
return setter;
38+
}
39+
40+
public static TSetter AddDestinationTransform<TSetter>(this TSetter setter, DestinationTransform transform) where TSetter : TypeAdapterSetter
41+
{
42+
setter.CheckCompiled();
43+
44+
setter.Settings.DestinationTransforms.Add(transform);
3345
return setter;
3446
}
3547

@@ -646,6 +658,14 @@ public TwoWaysTypeAdapterSetter<TSource, TDestination> AddDestinationTransform<T
646658
return this;
647659
}
648660

661+
public TwoWaysTypeAdapterSetter<TSource, TDestination> AddDestinationTransform(DestinationTransform transform)
662+
{
663+
SourceToDestinationSetter.AddDestinationTransform(transform);
664+
if (typeof(TSource) != typeof(TDestination))
665+
DestinationToSourceSetter.AddDestinationTransform(transform);
666+
return this;
667+
}
668+
649669
public TwoWaysTypeAdapterSetter<TSource, TDestination> Ignore(params string[] names)
650670
{
651671
SourceToDestinationSetter.Ignore(names);

src/Mapster/TypeAdapterSettings.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ public IgnoreDictionary Ignore
1111
{
1212
get => Get("Ignore", () => new IgnoreDictionary());
1313
}
14-
public TransformsCollection DestinationTransforms
14+
public List<DestinationTransform> DestinationTransforms
1515
{
16-
get => Get("DestinationTransforms", () => new TransformsCollection());
16+
get => Get("DestinationTransforms", () => new List<DestinationTransform>());
1717
}
1818
public NameMatchingStrategy NameMatchingStrategy
1919
{

0 commit comments

Comments
 (0)