diff --git a/src/Mapster.Tests/WhenExplicitNullDestinationTransformRegression.cs b/src/Mapster.Tests/WhenExplicitNullDestinationTransformRegression.cs
new file mode 100644
index 00000000..c8264bd2
--- /dev/null
+++ b/src/Mapster.Tests/WhenExplicitNullDestinationTransformRegression.cs
@@ -0,0 +1,38 @@
+using System.Collections.Generic;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Shouldly;
+
+namespace Mapster.Tests
+{
+ ///
+ /// https://github.com/MapsterMapper/Mapster/issues/952
+ ///
+ [TestClass]
+ public class WhenExplicitNullDestinationTransformRegression
+ {
+ [TestMethod]
+ public void ExplicitNullMapping_ShouldNotBeOverridden_ByDefaultEmptyCollectionTransform()
+ {
+ var config = new TypeAdapterConfig();
+
+ config.Default
+ .AddDestinationTransform(DestinationTransform.EmptyCollectionIfNull);
+
+ config.NewConfig()
+ .Map(d => d.Strings, _ => (string[]?)null);
+
+ var foo = new Foo952([]);
+
+ var dto = foo.Adapt(config);
+
+ dto.Strings.ShouldBeNull();
+ }
+
+ record Foo952(string?[] Strings);
+
+ class FooDto952
+ {
+ public string[]? Strings { get; set; }
+ }
+ }
+}
diff --git a/src/Mapster/Adapters/BaseClassAdapter.cs b/src/Mapster/Adapters/BaseClassAdapter.cs
index 6d12a934..bc267d6e 100644
--- a/src/Mapster/Adapters/BaseClassAdapter.cs
+++ b/src/Mapster/Adapters/BaseClassAdapter.cs
@@ -263,7 +263,7 @@ protected Expression CreateInstantiationExpression(Expression source, ClassMappi
}
else
getter = member.Getter
- .ApplyNullPropagationFromCtor(CreateAdaptExpressionCore(member.Getter, member.DestinationMember.Type, arg, member), arg);
+ .ApplyNullPropagationFromCtor(CreateAdaptExpressionCore(member.Getter, member.DestinationMember.Type, arg, member), arg, member);
if (member.Ignore.Condition != null)
@@ -283,7 +283,7 @@ protected Expression CreateInstantiationExpression(Expression source, ClassMappi
getter = TryRestoreRecordMember(member.DestinationMember, recordRestorParamModel, destination) ?? getter;
}
}
- arguments.Add(getter);
+ arguments.Add(ExpressionEx.ApplyDestinationTransform(getter, arg, member));
}
return Expression.New(classConverter.ConstructorInfo!, arguments);
diff --git a/src/Mapster/Utils/ExpressionEx.cs b/src/Mapster/Utils/ExpressionEx.cs
index b7ffc365..ffed8cd4 100644
--- a/src/Mapster/Utils/ExpressionEx.cs
+++ b/src/Mapster/Utils/ExpressionEx.cs
@@ -445,7 +445,7 @@ public static Expression ApplyPropertyNullPropagation(this Expression getter)
return getter;
}
- public static Expression ApplyNullPropagationFromCtor(this Expression getter, Expression adapt, CompileArgument arg)
+ public static Expression ApplyNullPropagationFromCtor(this Expression getter, Expression adapt, CompileArgument arg, MemberMapping? member = null)
{
if (getter == null)
return adapt;
@@ -481,9 +481,12 @@ public static Expression ApplyNullPropagationFromCtor(this Expression getter, Ex
}
if (condition == null)
- return adapt;
+ return ApplyDestinationTransform(adapt, arg, member);
// add supporting DestinationTransforms
+ if (HasExplicitMemberMap(member, arg))
+ return Expression.Condition(condition, adapt, Expression.Default(adapt.Type));
+
var transform = arg.Settings.DestinationTransforms.Find(it => it.Condition(adapt.Type));
if (transform != null)
return transform.TransformFunc(adapt.Type).Apply(arg.MapType, Expression.Condition(condition, adapt, Expression.Default(adapt.Type)));
@@ -491,6 +494,29 @@ public static Expression ApplyNullPropagationFromCtor(this Expression getter, Ex
return Expression.Condition(condition, adapt, Expression.Default(adapt.Type));
}
+ public static Expression ApplyDestinationTransform(Expression exp, CompileArgument arg, MemberMapping? mapping = null)
+ {
+ if (HasExplicitMemberMap(mapping, arg))
+ return exp;
+
+ var transform = arg.Settings.DestinationTransforms.Find(it => it.Condition(exp.Type));
+ if (transform == null)
+ return exp;
+
+ return transform.TransformFunc(exp.Type).Apply(arg.MapType, exp);
+ }
+
+ static bool HasExplicitMemberMap(MemberMapping? mapping, CompileArgument arg)
+ {
+ if (mapping?.DestinationMember == null)
+ return false;
+
+ var memberName = mapping.DestinationMember.Name;
+ return arg.Settings.Resolvers.Any(resolver =>
+ !resolver.IsChildPath &&
+ resolver.DestinationMemberName.Equals(memberName, StringComparison.InvariantCultureIgnoreCase));
+ }
+
public static string? GetMemberPath(this LambdaExpression lambda, bool firstLevelOnly = false, bool noError = false)
{
var props = new List();