Skip to content

Commit

Permalink
fix MapsterMapper#227: EmptyCollectionIfNull, CreateNewIfNull Destina…
Browse files Browse the repository at this point in the history
…tionTransform
  • Loading branch information
chaowlert committed Mar 14, 2020
1 parent e2fd308 commit ee77747
Show file tree
Hide file tree
Showing 7 changed files with 144 additions and 85 deletions.
37 changes: 37 additions & 0 deletions src/Mapster.Tests/WhenPerformingDestinationTransforms.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Shouldly;
Expand Down Expand Up @@ -52,6 +53,34 @@ public void Adapter_Destination_Transform_Is_Applied_To_Class()
destination.Name.ShouldBe("TestMethod");
}

[TestMethod]
public void Adapter_Destination_Transform_Collection()
{
var config = new TypeAdapterConfig();
config.Default.AddDestinationTransform((IReadOnlyList<ChildDto> list) => list ?? new List<ChildDto>());

var source = new CollectionPoco();
var destination = source.Adapt<CollectionDto>(config);

destination.Children.ShouldNotBeNull();
}

[TestMethod]
public void Adapter_Destination_Transform_Collection_Generic()
{
var config = new TypeAdapterConfig();
config.Default.AddDestinationTransform(DestinationTransform.EmptyCollectionIfNull);

var source = new CollectionPoco();
var destination = source.Adapt<CollectionDto>(config);

destination.Children.Count.ShouldBe(0);
destination.Array.Length.ShouldBe(0);
destination.MultiDimentionalArray.Length.ShouldBe(0);
destination.ChildDict.Count.ShouldBe(0);
destination.Set.Count.ShouldBe(0);
}

#region TestClasses

public class SimplePoco
Expand Down Expand Up @@ -84,6 +113,10 @@ public class CollectionPoco
public string Name { get; set; }

public List<ChildPoco> Children { get; set; }
public int[] Array { get; set; }
public double[,] MultiDimentionalArray { get; set; }
public Dictionary<string, ChildPoco> ChildDict { get; set; }
public HashSet<string> Set { get; set; }
}

public class CollectionDto
Expand All @@ -92,6 +125,10 @@ public class CollectionDto
public string Name { get; set; }

public IReadOnlyList<ChildDto> Children { get; internal set; }
public int[] Array { get; set; }
public double[,] MultiDimentionalArray { get; set; }
public IReadOnlyDictionary<string, ChildDto> ChildDict { get; set; }
public HashSet<string> Set { get; set; }
}

#endregion
Expand Down
8 changes: 3 additions & 5 deletions src/Mapster/Adapters/BaseAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -409,11 +409,9 @@ internal Expression CreateAdaptExpression(Expression source, Type destinationTyp
var exp = CreateAdaptExpressionCore(source, destinationType, arg, mapping, destination);

//transform(adapt(source));
if (arg.Settings.DestinationTransforms.Transforms.ContainsKey(exp.Type))
{
var transform = arg.Settings.DestinationTransforms.Transforms[exp.Type];
exp = transform.Apply(arg.MapType, exp);
}
var transform = arg.Settings.DestinationTransforms.FirstOrDefault(it => it.Condition(exp.Type));
if (transform != null)
exp = transform.TransformFunc(exp.Type).Apply(arg.MapType, exp);
return exp.To(destinationType);
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/Mapster/Mapster.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
<NetStandardImplicitPackageVersion Condition=" '$(TargetFramework)' == 'netstandard1.3' ">1.6.1</NetStandardImplicitPackageVersion>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<RootNamespace>Mapster</RootNamespace>
<Version>5.1.0</Version>
<Version>5.2.0</Version>
<LangVersion>8.0</LangVersion>
<Nullable>enable</Nullable>
</PropertyGroup>
Expand Down
80 changes: 80 additions & 0 deletions src/Mapster/Settings/DestinationTransform.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

namespace Mapster
{
public class DestinationTransform
{
public static readonly DestinationTransform EmptyCollectionIfNull = new DestinationTransform
{
Condition = type => type.IsArray
|| type.IsListCompatible()
|| type.GetDictionaryType() != null,
TransformFunc = type =>
{
Expression newExp;
if (type.IsArray)
{
var rank = type.GetArrayRank();
var elemType = type.GetElementType()!;
newExp = Expression.NewArrayBounds(elemType, Enumerable.Repeat(Expression.Constant(0), rank));
}
else if (type.GetTypeInfo().IsInterface)
{
if (type.GetDictionaryType() != null)
{
var dict = type.GetDictionaryType()!;
var dictArgs = dict.GetGenericArguments();
var dictType = typeof(Dictionary<,>).MakeGenericType(dictArgs);
newExp = Expression.New(dictType);
}
else
{
var elemType = type.ExtractCollectionType();
var listType = typeof(List<>).MakeGenericType(elemType);
newExp = Expression.New(listType);
}
}
else
newExp = Expression.New(type);
var p = Expression.Parameter(type);
return Expression.Lambda(Expression.Coalesce(p, newExp), p);
}
};

public static readonly DestinationTransform CreateNewIfNull = new DestinationTransform
{
Condition = type =>
{
if (!type.CanBeNull())
return false;
if (type.GetTypeInfo().IsInterface || type.GetTypeInfo().IsAbstract)
return false;
var ci = type.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).SingleOrDefault(c => c.GetParameters().Length == 0);
return ci != null;
},
TransformFunc = type =>
{
var p = Expression.Parameter(type);
return Expression.Lambda(
Expression.Coalesce(p, Expression.New(type)));
}
};

public Func<Type, bool> Condition { get; set; }
public Func<Type, LambdaExpression> TransformFunc { get; set; }

public DestinationTransform WithCondition(Func<Type, bool> condition)
{
return new DestinationTransform
{
Condition = condition,
TransformFunc = this.TransformFunc
};
}
}
}
76 changes: 0 additions & 76 deletions src/Mapster/Settings/TransformsCollection.cs

This file was deleted.

22 changes: 21 additions & 1 deletion src/Mapster/TypeAdapterSetter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,19 @@ public static TSetter AddDestinationTransform<TSetter, TDestinationMember>(this
{
setter.CheckCompiled();

setter.Settings.DestinationTransforms.Upsert(transform);
setter.Settings.DestinationTransforms.Add(new DestinationTransform
{
Condition = t => t == typeof(TDestinationMember),
TransformFunc = _ => transform,
});
return setter;
}

public static TSetter AddDestinationTransform<TSetter>(this TSetter setter, DestinationTransform transform) where TSetter : TypeAdapterSetter
{
setter.CheckCompiled();

setter.Settings.DestinationTransforms.Add(transform);
return setter;
}

Expand Down Expand Up @@ -646,6 +658,14 @@ public TwoWaysTypeAdapterSetter<TSource, TDestination> AddDestinationTransform<T
return this;
}

public TwoWaysTypeAdapterSetter<TSource, TDestination> AddDestinationTransform(DestinationTransform transform)
{
SourceToDestinationSetter.AddDestinationTransform(transform);
if (typeof(TSource) != typeof(TDestination))
DestinationToSourceSetter.AddDestinationTransform(transform);
return this;
}

public TwoWaysTypeAdapterSetter<TSource, TDestination> Ignore(params string[] names)
{
SourceToDestinationSetter.Ignore(names);
Expand Down
4 changes: 2 additions & 2 deletions src/Mapster/TypeAdapterSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ public IgnoreDictionary Ignore
{
get => Get("Ignore", () => new IgnoreDictionary());
}
public TransformsCollection DestinationTransforms
public List<DestinationTransform> DestinationTransforms
{
get => Get("DestinationTransforms", () => new TransformsCollection());
get => Get("DestinationTransforms", () => new List<DestinationTransform>());
}
public NameMatchingStrategy NameMatchingStrategy
{
Expand Down

0 comments on commit ee77747

Please sign in to comment.