diff --git a/src/Riok.Mapperly/Descriptors/MappingBodyBuilders/BuilderContext/MembersContainerBuilderContext.cs b/src/Riok.Mapperly/Descriptors/MappingBodyBuilders/BuilderContext/MembersContainerBuilderContext.cs index ee775e6b9d..6eaea15569 100644 --- a/src/Riok.Mapperly/Descriptors/MappingBodyBuilders/BuilderContext/MembersContainerBuilderContext.cs +++ b/src/Riok.Mapperly/Descriptors/MappingBodyBuilders/BuilderContext/MembersContainerBuilderContext.cs @@ -1,5 +1,6 @@ using Riok.Mapperly.Descriptors.Mappings.MemberMappings; using Riok.Mapperly.Diagnostics; +using Riok.Mapperly.Helpers; using Riok.Mapperly.Symbols; namespace Riok.Mapperly.Descriptors.MappingBodyBuilders.BuilderContext; @@ -22,6 +23,13 @@ public void AddNullDelegateMemberAssignmentMapping(IMemberAssignmentMapping memb var nullConditionSourcePath = new MemberPath(memberMapping.SourcePath.PathWithoutTrailingNonNullable().ToList()); var container = GetOrCreateNullDelegateMappingForPath(nullConditionSourcePath); AddMemberAssignmentMapping(container, memberMapping); + + // set target member to null if null assignments are allowed + // and the source is null + if (BuilderContext.MapperConfiguration.AllowNullPropertyAssignment && memberMapping.TargetPath.Member.Type.IsNullable()) + { + container.AddNullMemberAssignment(SetterMemberPath.Build(BuilderContext, memberMapping.TargetPath)); + } } private void AddMemberAssignmentMapping(IMemberAssignmentMappingContainer container, IMemberAssignmentMapping mapping) diff --git a/src/Riok.Mapperly/Descriptors/Mappings/MemberMappings/MemberNullDelegateAssignmentMapping.cs b/src/Riok.Mapperly/Descriptors/Mappings/MemberMappings/MemberNullDelegateAssignmentMapping.cs index efb8808778..97e1c9b391 100644 --- a/src/Riok.Mapperly/Descriptors/Mappings/MemberMappings/MemberNullDelegateAssignmentMapping.cs +++ b/src/Riok.Mapperly/Descriptors/Mappings/MemberMappings/MemberNullDelegateAssignmentMapping.cs @@ -18,6 +18,7 @@ bool needsNullSafeAccess { private readonly GetterMemberPath _nullConditionalSourcePath = nullConditionalSourcePath; private readonly bool _throwInsteadOfConditionalNullMapping = throwInsteadOfConditionalNullMapping; + private readonly List _targetsToSetNull = new(); public override IEnumerable Build(TypeMappingBuildContext ctx, ExpressionSyntax targetAccess) { @@ -26,17 +27,16 @@ public override IEnumerable Build(TypeMappingBuildContext ctx, // else // throw ... var sourceNullConditionalAccess = _nullConditionalSourcePath.BuildAccess(ctx.Source, false, needsNullSafeAccess, true); - var nameofSourceAccess = _nullConditionalSourcePath.BuildAccess(ctx.Source, false, false, true); var condition = IsNotNull(sourceNullConditionalAccess); var conditionCtx = ctx.AddIndentation(); var trueClause = base.Build(conditionCtx, targetAccess); - var elseClause = _throwInsteadOfConditionalNullMapping - ? new[] { conditionCtx.SyntaxFactory.ExpressionStatement(ThrowArgumentNullException(nameofSourceAccess)) } - : null; + var elseClause = BuildElseClause(conditionCtx, targetAccess); var ifExpression = ctx.SyntaxFactory.If(condition, trueClause, elseClause); return new[] { ifExpression }; } + public void AddNullMemberAssignment(SetterMemberPath targetPath) => _targetsToSetNull.Add(targetPath); + public override bool Equals(object? obj) { if (ReferenceEquals(null, obj)) @@ -70,4 +70,19 @@ protected bool Equals(MemberNullDelegateAssignmentMapping other) return _nullConditionalSourcePath.Equals(other._nullConditionalSourcePath) && _throwInsteadOfConditionalNullMapping == other._throwInsteadOfConditionalNullMapping; } + + private IEnumerable? BuildElseClause(TypeMappingBuildContext ctx, ExpressionSyntax targetAccess) + { + if (_throwInsteadOfConditionalNullMapping) + { + // throw new ArgumentNullException + var nameofSourceAccess = _nullConditionalSourcePath.BuildAccess(ctx.Source, false, false, true); + return new[] { ctx.SyntaxFactory.ExpressionStatement(ThrowArgumentNullException(nameofSourceAccess)) }; + } + + // target.A = null; + return _targetsToSetNull.Count == 0 + ? null + : _targetsToSetNull.Select(x => ctx.SyntaxFactory.ExpressionStatement(x.BuildAssignment(targetAccess, NullLiteral()))); + } } diff --git a/src/Riok.Mapperly/Symbols/SetterMemberPath.cs b/src/Riok.Mapperly/Symbols/SetterMemberPath.cs index aed864cb9f..dbf76a98f9 100644 --- a/src/Riok.Mapperly/Symbols/SetterMemberPath.cs +++ b/src/Riok.Mapperly/Symbols/SetterMemberPath.cs @@ -55,7 +55,7 @@ private static (IMappableMember, bool) BuildMemberSetter(MappingBuilderContext c return (new MethodAccessorMember(member, unsafeGetAccessor.MethodName, methodRequiresParameter: true), true); } - public ExpressionSyntax BuildAssignment(ExpressionSyntax? baseAccess, ExpressionSyntax sourceValue, bool coalesceAssignment = false) + public ExpressionSyntax BuildAssignment(ExpressionSyntax? baseAccess, ExpressionSyntax valueToAssign, bool coalesceAssignment = false) { IEnumerable path = Path; @@ -73,16 +73,16 @@ public ExpressionSyntax BuildAssignment(ExpressionSyntax? baseAccess, Expression Debug.Assert(!IsMethod); // target.Value ??= mappedValue; - return CoalesceAssignment(memberPath, sourceValue); + return CoalesceAssignment(memberPath, valueToAssign); } if (IsMethod) { // target.SetValue(source.Value); - return Invocation(memberPath, sourceValue); + return Invocation(memberPath, valueToAssign); } // target.Value = source.Value; - return Assignment(memberPath, sourceValue); + return Assignment(memberPath, valueToAssign); } } diff --git a/test/Riok.Mapperly.IntegrationTests/_snapshots/CircularReferenceMapperTest.SnapshotGeneratedSource.verified.cs b/test/Riok.Mapperly.IntegrationTests/_snapshots/CircularReferenceMapperTest.SnapshotGeneratedSource.verified.cs index 203e6f9afa..a7a9a0fa7b 100644 --- a/test/Riok.Mapperly.IntegrationTests/_snapshots/CircularReferenceMapperTest.SnapshotGeneratedSource.verified.cs +++ b/test/Riok.Mapperly.IntegrationTests/_snapshots/CircularReferenceMapperTest.SnapshotGeneratedSource.verified.cs @@ -19,6 +19,10 @@ public static partial class CircularReferenceMapper { target.Parent = MapToCircularReferenceDto(source.Parent, refHandler); } + else + { + target.Parent = null; + } target.Value = source.Value; return target; } diff --git a/test/Riok.Mapperly.IntegrationTests/_snapshots/DeepCloningMapperTest.SnapshotGeneratedSource_NET6_0.verified.cs b/test/Riok.Mapperly.IntegrationTests/_snapshots/DeepCloningMapperTest.SnapshotGeneratedSource_NET6_0.verified.cs index c23f6c8f9f..dff7323ee7 100644 --- a/test/Riok.Mapperly.IntegrationTests/_snapshots/DeepCloningMapperTest.SnapshotGeneratedSource_NET6_0.verified.cs +++ b/test/Riok.Mapperly.IntegrationTests/_snapshots/DeepCloningMapperTest.SnapshotGeneratedSource_NET6_0.verified.cs @@ -22,34 +22,66 @@ public static partial class DeepCloningMapper { target.NullableFlattening = Copy(src.NullableFlattening); } + else + { + target.NullableFlattening = null; + } if (src.NestedNullable != null) { target.NestedNullable = MapToTestObjectNested(src.NestedNullable); } + else + { + target.NestedNullable = null; + } if (src.NestedNullableTargetNotNullable != null) { target.NestedNullableTargetNotNullable = MapToTestObjectNested(src.NestedNullableTargetNotNullable); } + else + { + target.NestedNullableTargetNotNullable = null; + } if (src.TupleValue != null) { target.TupleValue = MapToValueTuple(src.TupleValue.Value); } + else + { + target.TupleValue = null; + } if (src.RecursiveObject != null) { target.RecursiveObject = Copy(src.RecursiveObject); } + else + { + target.RecursiveObject = null; + } if (src.SourceTargetSameObjectType != null) { target.SourceTargetSameObjectType = Copy(src.SourceTargetSameObjectType); } + else + { + target.SourceTargetSameObjectType = null; + } if (src.NullableReadOnlyObjectCollection != null) { target.NullableReadOnlyObjectCollection = MapToIReadOnlyCollection(src.NullableReadOnlyObjectCollection); } + else + { + target.NullableReadOnlyObjectCollection = null; + } if (src.SubObject != null) { target.SubObject = MapToInheritanceSubObject(src.SubObject); } + else + { + target.SubObject = null; + } target.IntValue = src.IntValue; target.StringValue = src.StringValue; target.RenamedStringValue = src.RenamedStringValue; diff --git a/test/Riok.Mapperly.IntegrationTests/_snapshots/MapperTest.SnapshotGeneratedSource_NET8_0.verified.cs b/test/Riok.Mapperly.IntegrationTests/_snapshots/MapperTest.SnapshotGeneratedSource_NET8_0.verified.cs index c56f5b81db..0cfca8b7b1 100644 --- a/test/Riok.Mapperly.IntegrationTests/_snapshots/MapperTest.SnapshotGeneratedSource_NET8_0.verified.cs +++ b/test/Riok.Mapperly.IntegrationTests/_snapshots/MapperTest.SnapshotGeneratedSource_NET8_0.verified.cs @@ -55,6 +55,10 @@ public partial int ParseableInt(string value) { target.NullableFlatteningIdValue = CastIntNullable(testObject.NullableFlattening.IdValue); } + else + { + target.NullableFlatteningIdValue = null; + } if (testObject.NullableUnflatteningIdValue != null) { target.NullableUnflattening ??= new(); @@ -65,6 +69,10 @@ public partial int ParseableInt(string value) target.NestedNullableIntValue = DirectInt(testObject.NestedNullable.IntValue); target.NestedNullable = MapToTestObjectNestedDto(testObject.NestedNullable); } + else + { + target.NestedNullable = null; + } if (testObject.NestedNullableTargetNotNullable != null) { target.NestedNullableTargetNotNullable = MapToTestObjectNestedDto(testObject.NestedNullableTargetNotNullable); @@ -77,18 +85,34 @@ public partial int ParseableInt(string value) { target.TupleValue = MapToValueTuple(testObject.TupleValue.Value); } + else + { + target.TupleValue = null; + } if (testObject.RecursiveObject != null) { target.RecursiveObject = MapToDto(testObject.RecursiveObject); } + else + { + target.RecursiveObject = null; + } if (testObject.NullableReadOnlyObjectCollection != null) { target.NullableReadOnlyObjectCollection = MapToTestObjectNestedDtoArray(testObject.NullableReadOnlyObjectCollection); } + else + { + target.NullableReadOnlyObjectCollection = null; + } if (testObject.SubObject != null) { target.SubObject = MapToInheritanceSubObjectDto(testObject.SubObject); } + else + { + target.SubObject = null; + } target.IntValue = DirectInt(testObject.IntValue); target.StringValue = testObject.StringValue; target.RenamedStringValue2 = testObject.RenamedStringValue; @@ -154,26 +178,50 @@ public partial int ParseableInt(string value) { target.NullableUnflatteningIdValue = CastIntNullable(dto.NullableUnflattening.IdValue); } + else + { + target.NullableUnflatteningIdValue = null; + } if (dto.NestedNullable != null) { target.NestedNullable = MapToTestObjectNested(dto.NestedNullable); } + else + { + target.NestedNullable = null; + } if (dto.TupleValue != null) { target.TupleValue = MapToValueTuple1(dto.TupleValue.Value); } + else + { + target.TupleValue = null; + } if (dto.RecursiveObject != null) { target.RecursiveObject = MapFromDto(dto.RecursiveObject); } + else + { + target.RecursiveObject = null; + } if (dto.NullableReadOnlyObjectCollection != null) { target.NullableReadOnlyObjectCollection = MapToIReadOnlyCollection(dto.NullableReadOnlyObjectCollection); } + else + { + target.NullableReadOnlyObjectCollection = null; + } if (dto.SubObject != null) { target.SubObject = MapToInheritanceSubObject(dto.SubObject); } + else + { + target.SubObject = null; + } target.IntValue = DirectInt(dto.IntValue); target.StringValue = dto.StringValue; target.UnflatteningIdValue = DirectInt(dto.Unflattening.IdValue); @@ -229,11 +277,19 @@ public partial void UpdateDto(global::Riok.Mapperly.IntegrationTests.Models.Test { target.NullableFlatteningIdValue = CastIntNullable(source.NullableFlattening.IdValue); } + else + { + target.NullableFlatteningIdValue = null; + } if (source.NestedNullable != null) { target.NestedNullableIntValue = DirectInt(source.NestedNullable.IntValue); target.NestedNullable = MapToTestObjectNestedDto(source.NestedNullable); } + else + { + target.NestedNullable = null; + } if (source.NestedNullableTargetNotNullable != null) { target.NestedNullableTargetNotNullable = MapToTestObjectNestedDto(source.NestedNullableTargetNotNullable); @@ -246,18 +302,34 @@ public partial void UpdateDto(global::Riok.Mapperly.IntegrationTests.Models.Test { target.TupleValue = MapToValueTuple(source.TupleValue.Value); } + else + { + target.TupleValue = null; + } if (source.RecursiveObject != null) { target.RecursiveObject = MapToDto(source.RecursiveObject); } + else + { + target.RecursiveObject = null; + } if (source.NullableReadOnlyObjectCollection != null) { target.NullableReadOnlyObjectCollection = MapToTestObjectNestedDtoArray(source.NullableReadOnlyObjectCollection); } + else + { + target.NullableReadOnlyObjectCollection = null; + } if (source.SubObject != null) { target.SubObject = MapToInheritanceSubObjectDto(source.SubObject); } + else + { + target.SubObject = null; + } target.CtorValue = DirectInt(source.CtorValue); target.CtorValue2 = DirectInt(source.CtorValue2); target.IntValue = DirectInt(source.IntValue); diff --git a/test/Riok.Mapperly.IntegrationTests/_snapshots/ProjectionMapperTest.SnapshotGeneratedSource_NET6_0.verified.cs b/test/Riok.Mapperly.IntegrationTests/_snapshots/ProjectionMapperTest.SnapshotGeneratedSource_NET6_0.verified.cs index 89eb70cbbe..358b1ff6a0 100644 --- a/test/Riok.Mapperly.IntegrationTests/_snapshots/ProjectionMapperTest.SnapshotGeneratedSource_NET6_0.verified.cs +++ b/test/Riok.Mapperly.IntegrationTests/_snapshots/ProjectionMapperTest.SnapshotGeneratedSource_NET6_0.verified.cs @@ -78,6 +78,10 @@ public static partial class ProjectionMapper target.NestedNullableIntValue = testObject.NestedNullable.IntValue; target.NestedNullable = MapToTestObjectNestedDto(testObject.NestedNullable); } + else + { + target.NestedNullable = null; + } if (testObject.NestedNullableTargetNotNullable != null) { target.NestedNullableTargetNotNullable = MapToTestObjectNestedDto(testObject.NestedNullableTargetNotNullable); @@ -90,10 +94,18 @@ public static partial class ProjectionMapper { target.NullableReadOnlyObjectCollection = MapToIReadOnlyCollection(testObject.NullableReadOnlyObjectCollection); } + else + { + target.NullableReadOnlyObjectCollection = null; + } if (testObject.SubObject != null) { target.SubObject = MapToInheritanceSubObjectDto(testObject.SubObject); } + else + { + target.SubObject = null; + } target.IntValue = testObject.IntValue; target.StringValue = testObject.StringValue; target.RenamedStringValue2 = testObject.RenamedStringValue; diff --git a/test/Riok.Mapperly.IntegrationTests/_snapshots/StaticMapperTest.SnapshotGeneratedSource_NET6_0.verified.cs b/test/Riok.Mapperly.IntegrationTests/_snapshots/StaticMapperTest.SnapshotGeneratedSource_NET6_0.verified.cs index 3d77b56c3a..bd8552e7bf 100644 --- a/test/Riok.Mapperly.IntegrationTests/_snapshots/StaticMapperTest.SnapshotGeneratedSource_NET6_0.verified.cs +++ b/test/Riok.Mapperly.IntegrationTests/_snapshots/StaticMapperTest.SnapshotGeneratedSource_NET6_0.verified.cs @@ -60,11 +60,19 @@ public static partial int ParseableInt(string value) { target.NullableFlatteningIdValue = CastIntNullable(src.NullableFlattening.IdValue); } + else + { + target.NullableFlatteningIdValue = null; + } if (src.NestedNullable != null) { target.NestedNullableIntValue = DirectInt(src.NestedNullable.IntValue); target.NestedNullable = MapToTestObjectNestedDto(src.NestedNullable); } + else + { + target.NestedNullable = null; + } if (src.NestedNullableTargetNotNullable != null) { target.NestedNullableTargetNotNullable = MapToTestObjectNestedDto(src.NestedNullableTargetNotNullable); @@ -77,18 +85,34 @@ public static partial int ParseableInt(string value) { target.TupleValue = MapToValueTuple(src.TupleValue.Value); } + else + { + target.TupleValue = null; + } if (src.RecursiveObject != null) { target.RecursiveObject = MapToDtoExt(src.RecursiveObject); } + else + { + target.RecursiveObject = null; + } if (src.NullableReadOnlyObjectCollection != null) { target.NullableReadOnlyObjectCollection = MapToTestObjectNestedDtoArray(src.NullableReadOnlyObjectCollection); } + else + { + target.NullableReadOnlyObjectCollection = null; + } if (src.SubObject != null) { target.SubObject = MapToInheritanceSubObjectDto(src.SubObject); } + else + { + target.SubObject = null; + } target.IntValue = DirectInt(src.IntValue); target.StringValue = src.StringValue; target.FlatteningIdValue = DirectInt(src.Flattening.IdValue); @@ -145,6 +169,10 @@ public static partial int ParseableInt(string value) { target.NullableFlatteningIdValue = CastIntNullable(testObject.NullableFlattening.IdValue); } + else + { + target.NullableFlatteningIdValue = null; + } if (testObject.NullableUnflatteningIdValue != null) { target.NullableUnflattening ??= new(); @@ -155,6 +183,10 @@ public static partial int ParseableInt(string value) target.NestedNullableIntValue = DirectInt(testObject.NestedNullable.IntValue); target.NestedNullable = MapToTestObjectNestedDto(testObject.NestedNullable); } + else + { + target.NestedNullable = null; + } if (testObject.NestedNullableTargetNotNullable != null) { target.NestedNullableTargetNotNullable = MapToTestObjectNestedDto(testObject.NestedNullableTargetNotNullable); @@ -167,18 +199,34 @@ public static partial int ParseableInt(string value) { target.TupleValue = MapToValueTuple(testObject.TupleValue.Value); } + else + { + target.TupleValue = null; + } if (testObject.RecursiveObject != null) { target.RecursiveObject = MapToDtoExt(testObject.RecursiveObject); } + else + { + target.RecursiveObject = null; + } if (testObject.NullableReadOnlyObjectCollection != null) { target.NullableReadOnlyObjectCollection = MapToTestObjectNestedDtoArray(testObject.NullableReadOnlyObjectCollection); } + else + { + target.NullableReadOnlyObjectCollection = null; + } if (testObject.SubObject != null) { target.SubObject = MapToInheritanceSubObjectDto(testObject.SubObject); } + else + { + target.SubObject = null; + } target.IntValue = DirectInt(testObject.IntValue); target.StringValue = testObject.StringValue; target.RenamedStringValue2 = testObject.RenamedStringValue; @@ -237,26 +285,50 @@ public static partial int ParseableInt(string value) { target.NullableUnflatteningIdValue = CastIntNullable(dto.NullableUnflattening.IdValue); } + else + { + target.NullableUnflatteningIdValue = null; + } if (dto.NestedNullable != null) { target.NestedNullable = MapToTestObjectNested(dto.NestedNullable); } + else + { + target.NestedNullable = null; + } if (dto.TupleValue != null) { target.TupleValue = MapToValueTuple1(dto.TupleValue.Value); } + else + { + target.TupleValue = null; + } if (dto.RecursiveObject != null) { target.RecursiveObject = MapFromDto(dto.RecursiveObject); } + else + { + target.RecursiveObject = null; + } if (dto.NullableReadOnlyObjectCollection != null) { target.NullableReadOnlyObjectCollection = MapToIReadOnlyCollection(dto.NullableReadOnlyObjectCollection); } + else + { + target.NullableReadOnlyObjectCollection = null; + } if (dto.SubObject != null) { target.SubObject = MapToInheritanceSubObject(dto.SubObject); } + else + { + target.SubObject = null; + } target.IntValue = DirectInt(dto.IntValue); target.StringValue = dto.StringValue; target.UnflatteningIdValue = DirectInt(dto.Unflattening.IdValue); @@ -311,11 +383,19 @@ public static partial void UpdateDto(global::Riok.Mapperly.IntegrationTests.Mode { target.NullableFlatteningIdValue = CastIntNullable(source.NullableFlattening.IdValue); } + else + { + target.NullableFlatteningIdValue = null; + } if (source.NestedNullable != null) { target.NestedNullableIntValue = DirectInt(source.NestedNullable.IntValue); target.NestedNullable = MapToTestObjectNestedDto(source.NestedNullable); } + else + { + target.NestedNullable = null; + } if (source.NestedNullableTargetNotNullable != null) { target.NestedNullableTargetNotNullable = MapToTestObjectNestedDto(source.NestedNullableTargetNotNullable); @@ -328,18 +408,34 @@ public static partial void UpdateDto(global::Riok.Mapperly.IntegrationTests.Mode { target.TupleValue = MapToValueTuple(source.TupleValue.Value); } + else + { + target.TupleValue = null; + } if (source.RecursiveObject != null) { target.RecursiveObject = MapToDtoExt(source.RecursiveObject); } + else + { + target.RecursiveObject = null; + } if (source.NullableReadOnlyObjectCollection != null) { target.NullableReadOnlyObjectCollection = MapToTestObjectNestedDtoArray(source.NullableReadOnlyObjectCollection); } + else + { + target.NullableReadOnlyObjectCollection = null; + } if (source.SubObject != null) { target.SubObject = MapToInheritanceSubObjectDto(source.SubObject); } + else + { + target.SubObject = null; + } target.CtorValue = DirectInt(source.CtorValue); target.CtorValue2 = DirectInt(source.CtorValue2); target.IntValue = DirectInt(source.IntValue); diff --git a/test/Riok.Mapperly.Tests/Mapping/ObjectPropertyFlatteningTest.cs b/test/Riok.Mapperly.Tests/Mapping/ObjectPropertyFlatteningTest.cs index ac9ae349dc..365df1c0ce 100644 --- a/test/Riok.Mapperly.Tests/Mapping/ObjectPropertyFlatteningTest.cs +++ b/test/Riok.Mapperly.Tests/Mapping/ObjectPropertyFlatteningTest.cs @@ -264,6 +264,10 @@ public void AutoFlattenedMultiplePropertiesPathDisabledNullable() { target.ValueId = source.Value.Id.ToString(); } + else + { + target.ValueId = null; + } target.ValueName = source.Value?.Name; return target; """ diff --git a/test/Riok.Mapperly.Tests/Mapping/ObjectPropertyNullableTest.cs b/test/Riok.Mapperly.Tests/Mapping/ObjectPropertyNullableTest.cs index fdfcba999c..b120d9ffd9 100644 --- a/test/Riok.Mapperly.Tests/Mapping/ObjectPropertyNullableTest.cs +++ b/test/Riok.Mapperly.Tests/Mapping/ObjectPropertyNullableTest.cs @@ -319,6 +319,10 @@ public void NullableClassToNullableClassProperty() { target.Value = MapToD(source.Value); } + else + { + target.Value = null; + } return target; """ ); @@ -440,6 +444,39 @@ public void NullableClassPropertyToDisabledNullableProperty() { target.Value = MapToD(source.Value); } + else + { + target.Value = null; + } + return target; + """ + ); + } + + [Fact] + public void NullableValueTypeToOtherNullableValueType() + { + var source = TestSourceBuilder.Mapping( + "A", + "B", + "class A { public float? Value { get; set; } }", + "class B { public decimal? Value { get; set; } }" + ); + + TestHelper + .GenerateMapper(source) + .Should() + .HaveSingleMethodBody( + """ + var target = new global::B(); + if (source.Value != null) + { + target.Value = new decimal(source.Value.Value); + } + else + { + target.Value = null; + } return target; """ ); diff --git a/test/Riok.Mapperly.Tests/_snapshots/EnumerableTest.ArrayToCollectionShouldUpgradeNullability#Mapper.g.verified.cs b/test/Riok.Mapperly.Tests/_snapshots/EnumerableTest.ArrayToCollectionShouldUpgradeNullability#Mapper.g.verified.cs index 5267eb47d5..c68eaab91b 100644 --- a/test/Riok.Mapperly.Tests/_snapshots/EnumerableTest.ArrayToCollectionShouldUpgradeNullability#Mapper.g.verified.cs +++ b/test/Riok.Mapperly.Tests/_snapshots/EnumerableTest.ArrayToCollectionShouldUpgradeNullability#Mapper.g.verified.cs @@ -12,6 +12,10 @@ public partial class Mapper { target.Value = MapToICollection(source.Value); } + else + { + target.Value = null; + } return target; } diff --git a/test/Riok.Mapperly.Tests/_snapshots/EnumerableTest.ArrayToReadOnlyCollectionShouldUpgradeNullability#Mapper.g.verified.cs b/test/Riok.Mapperly.Tests/_snapshots/EnumerableTest.ArrayToReadOnlyCollectionShouldUpgradeNullability#Mapper.g.verified.cs index 0f146fd1c0..ad980589c9 100644 --- a/test/Riok.Mapperly.Tests/_snapshots/EnumerableTest.ArrayToReadOnlyCollectionShouldUpgradeNullability#Mapper.g.verified.cs +++ b/test/Riok.Mapperly.Tests/_snapshots/EnumerableTest.ArrayToReadOnlyCollectionShouldUpgradeNullability#Mapper.g.verified.cs @@ -12,6 +12,10 @@ public partial class Mapper { target.Value = MapToIReadOnlyCollection(source.Value); } + else + { + target.Value = null; + } return target; } diff --git a/test/Riok.Mapperly.Tests/_snapshots/EnumerableTest.CollectionToReadOnlyCollectionShouldUpgradeNullability#Mapper.g.verified.cs b/test/Riok.Mapperly.Tests/_snapshots/EnumerableTest.CollectionToReadOnlyCollectionShouldUpgradeNullability#Mapper.g.verified.cs index 55e9a83148..e4857907bc 100644 --- a/test/Riok.Mapperly.Tests/_snapshots/EnumerableTest.CollectionToReadOnlyCollectionShouldUpgradeNullability#Mapper.g.verified.cs +++ b/test/Riok.Mapperly.Tests/_snapshots/EnumerableTest.CollectionToReadOnlyCollectionShouldUpgradeNullability#Mapper.g.verified.cs @@ -12,6 +12,10 @@ public partial class Mapper { target.Value = MapToIReadOnlyCollection(source.Value); } + else + { + target.Value = null; + } return target; } diff --git a/test/Riok.Mapperly.Tests/_snapshots/EnumerableTest.ShouldUpgradeNullabilityInDisabledNullableContextInSelectClause#Mapper.g.verified.cs b/test/Riok.Mapperly.Tests/_snapshots/EnumerableTest.ShouldUpgradeNullabilityInDisabledNullableContextInSelectClause#Mapper.g.verified.cs index e370d2585d..e876283bd6 100644 --- a/test/Riok.Mapperly.Tests/_snapshots/EnumerableTest.ShouldUpgradeNullabilityInDisabledNullableContextInSelectClause#Mapper.g.verified.cs +++ b/test/Riok.Mapperly.Tests/_snapshots/EnumerableTest.ShouldUpgradeNullabilityInDisabledNullableContextInSelectClause#Mapper.g.verified.cs @@ -12,6 +12,10 @@ public partial class Mapper { target.Value = MapToDArray(source.Value); } + else + { + target.Value = null; + } return target; } diff --git a/test/Riok.Mapperly.Tests/_snapshots/ObjectPropertyNullableTest.ShouldUpgradeNullabilityInDisabledNullableContextInNestedProperty#Mapper.g.verified.cs b/test/Riok.Mapperly.Tests/_snapshots/ObjectPropertyNullableTest.ShouldUpgradeNullabilityInDisabledNullableContextInNestedProperty#Mapper.g.verified.cs index 1606f4b591..074cd160da 100644 --- a/test/Riok.Mapperly.Tests/_snapshots/ObjectPropertyNullableTest.ShouldUpgradeNullabilityInDisabledNullableContextInNestedProperty#Mapper.g.verified.cs +++ b/test/Riok.Mapperly.Tests/_snapshots/ObjectPropertyNullableTest.ShouldUpgradeNullabilityInDisabledNullableContextInNestedProperty#Mapper.g.verified.cs @@ -12,6 +12,10 @@ public partial class Mapper { target.Value = MapToD(source.Value); } + else + { + target.Value = null; + } return target; }