diff --git a/src/Mapster.Tests/WhenMappingRecordRegression.cs b/src/Mapster.Tests/WhenMappingRecordRegression.cs
index 94518641..055dddc9 100644
--- a/src/Mapster.Tests/WhenMappingRecordRegression.cs
+++ b/src/Mapster.Tests/WhenMappingRecordRegression.cs
@@ -1,997 +1,1459 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Shouldly;
using System;
-using System.Collections.Generic;
-using System.Text.Json;
+using System.Collections.Generic;
+using System.Text.Json;
using static Mapster.Tests.WhenExplicitMappingRequired;
+using System.Linq.Expressions;
+using System.Reflection;
using static Mapster.Tests.WhenMappingDerived;
namespace Mapster.Tests
-{
- ///
- /// Tests for https://github.com/MapsterMapper/Mapster/issues/537
- ///
- [TestClass]
- public class WhenMappingRecordRegression
- {
- [TestMethod]
- public void AdaptRecordToRecord()
- {
- TypeAdapterConfig
- .NewConfig()
- .Ignore(dest => dest.Y);
-
- var _source = new TestRecord() { X = 700 };
+{
+ ///
+ /// Tests for https://github.com/MapsterMapper/Mapster/issues/537
+ ///
+ [TestClass]
+ public class WhenMappingRecordRegression
+ {
+ ///
+ /// Gets the full expression tree string via the internal DebugView property.
+ /// Body.ToString() only shows a summary for block expressions and hides
+ /// backing field references. DebugView shows the complete tree.
+ ///
+ private static string GetExpressionDebugView(Expression expression)
+ {
+ var prop = typeof(Expression).GetProperty("DebugView", BindingFlags.Instance | BindingFlags.NonPublic);
+ return prop?.GetValue(expression) as string ?? expression.ToString();
+ }
+
+ [TestMethod]
+ public void AdaptRecordToRecord()
+ {
+ TypeAdapterConfig
+ .NewConfig()
+ .Ignore(dest => dest.Y);
+
+ var _source = new TestRecord() { X = 700 };
var _destination = new TestRecordY() { X = 500 , Y = 200 };
-
- var _destination2 = new TestRecordY() { X = 300, Y = 400 };
- var _result = _source.Adapt(_destination);
-
- var result2 = _destination.Adapt(_destination2);
-
- _result.X.ShouldBe(700);
- _result.Y.ShouldBe(200);
- object.ReferenceEquals(_result, _destination).ShouldBeFalse();
- }
-
- [TestMethod]
- public void AdaptPositionalRecordToPositionalRecord()
- {
- var _sourcePositional = new TestRecordPositional(600);
- var _destinationPositional = new TestRecordPositional(900);
- var _positionalResult = _sourcePositional.Adapt(_destinationPositional);
-
- _positionalResult.X.ShouldBe(600);
- object.ReferenceEquals(_destinationPositional, _positionalResult).ShouldBeFalse();
- }
-
- [TestMethod]
- public void AdaptRecordStructToRecordStruct()
- {
- var _sourceStruct = new TestRecordStruct() { X = 1000 };
- var _destinationStruct = new TestRecordStruct() { X = 800 };
- var _structResult = _sourceStruct.Adapt(_destinationStruct);
-
- _structResult.X.ShouldBe(1000);
- _destinationStruct.X.Equals(_structResult.X).ShouldBeFalse();
- }
-
- [TestMethod]
- public void AdaptRecordToClass()
- {
+
+ var _destination2 = new TestRecordY() { X = 300, Y = 400 };
+ var _result = _source.Adapt(_destination);
+
+ var result2 = _destination.Adapt(_destination2);
+
+ _result.X.ShouldBe(700);
+ _result.Y.ShouldBe(200);
+ object.ReferenceEquals(_result, _destination).ShouldBeFalse();
+ }
+
+ [TestMethod]
+ public void AdaptPositionalRecordToPositionalRecord()
+ {
+ var _sourcePositional = new TestRecordPositional(600);
+ var _destinationPositional = new TestRecordPositional(900);
+ var _positionalResult = _sourcePositional.Adapt(_destinationPositional);
+
+ _positionalResult.X.ShouldBe(600);
+ object.ReferenceEquals(_destinationPositional, _positionalResult).ShouldBeFalse();
+ }
+
+ [TestMethod]
+ public void AdaptRecordStructToRecordStruct()
+ {
+ var _sourceStruct = new TestRecordStruct() { X = 1000 };
+ var _destinationStruct = new TestRecordStruct() { X = 800 };
+ var _structResult = _sourceStruct.Adapt(_destinationStruct);
+
+ _structResult.X.ShouldBe(1000);
+ _destinationStruct.X.Equals(_structResult.X).ShouldBeFalse();
+ }
+
+ [TestMethod]
+ public void AdaptRecordToClass()
+ {
var _sourсe = new TestRecordPositional(200);
- var _destination = new TestClassProtectedCtr(400);
+ var _destination = new TestClassProtectedCtr(400);
var _result = _sourсe.Adapt(_destination);
-
- _destination.ShouldBeOfType();
- _destination.X.ShouldBe(200);
- object.ReferenceEquals(_destination, _result).ShouldBeTrue();
- }
-
- [TestMethod]
- public void AdaptClassToRecord()
- {
+
+ _destination.ShouldBeOfType();
+ _destination.X.ShouldBe(200);
+ object.ReferenceEquals(_destination, _result).ShouldBeTrue();
+ }
+
+ [TestMethod]
+ public void AdaptClassToRecord()
+ {
var _sourсe = new TestClassProtectedCtr(200);
- var _destination = new TestRecordPositional(400);
+ var _destination = new TestRecordPositional(400);
var _result = _sourсe.Adapt(_destination);
-
- _destination.ShouldBeOfType();
- _result.X.ShouldBe(200);
- object.ReferenceEquals(_destination, _result).ShouldBeFalse();
- }
-
- [TestMethod]
- public void AdaptToSealtedRecord()
- {
- var _sourceRecord = new TestRecord() { X = 2000 };
- var _destinationSealtedRecord = new TestSealedRecord() { X = 3000 };
- var _RecordResult = _sourceRecord.Adapt(_destinationSealtedRecord);
-
- _RecordResult.X.ShouldBe(2000);
- object.ReferenceEquals(_destinationSealtedRecord, _RecordResult).ShouldBeFalse();
- }
-
- [TestMethod]
- public void AdaptToSealtedPositionalRecord()
- {
- var _sourceRecord = new TestRecord() { X = 2000 };
- var _destinationSealtedPositionalRecord = new TestSealedRecordPositional(4000);
- var _RecordResult = _sourceRecord.Adapt(_destinationSealtedPositionalRecord);
-
- _RecordResult.X.ShouldBe(2000);
- object.ReferenceEquals(_destinationSealtedPositionalRecord, _RecordResult).ShouldBeFalse();
- }
-
- [TestMethod]
- public void AdaptClassToClassPublicCtrIsNotInstanse()
- {
- var _source = new TestClassPublicCtr(200);
- var _destination = new TestClassPublicCtr(400);
- var _result = _source.Adapt(_destination);
-
- _destination.ShouldBeOfType();
- _destination.X.ShouldBe(200);
- object.ReferenceEquals(_destination, _result).ShouldBeTrue();
- }
-
- [TestMethod]
- public void AdaptClassToClassProtectdCtrIsNotInstanse()
- {
- var _source = new TestClassPublicCtr(200);
- var _destination = new TestClassProtectedCtr(400);
- var _result = _source.Adapt(_destination);
-
- _destination.ShouldBeOfType();
- _destination.X.ShouldBe(200);
- object.ReferenceEquals(_destination, _result).ShouldBeTrue();
- }
-
- ///
- /// https://github.com/MapsterMapper/Mapster/issues/615
- ///
- [TestMethod]
- public void AdaptClassIncludeStruct()
- {
- TypeAdapterConfig
- .ForType()
- .Map(x => x.TestStruct, x => x.SourceWithStruct.TestStruct);
-
- var source = new SourceWithClass
- {
- SourceWithStruct = new SourceWithStruct
- {
- TestStruct = new TestStruct("A")
- }
- };
-
- var destination = source.Adapt();
- destination.TestStruct.Property.ShouldBe("A");
- }
-
- ///
- /// https://github.com/MapsterMapper/Mapster/issues/482
- ///
- [TestMethod]
- public void AdaptClassToClassFromPrivatePropertyIsNotInstanse()
- {
- var _source = new TestClassPublicCtr(200);
- var _destination = new TestClassProtectedCtrPrivateProperty(400, "Me");
- var _result = _source.Adapt(_destination);
-
- _destination.ShouldBeOfType();
- _destination.X.ShouldBe(200);
- _destination.Name.ShouldBe("Me");
- object.ReferenceEquals(_destination, _result).ShouldBeTrue();
- }
-
- ///
- /// https://github.com/MapsterMapper/Mapster/issues/427
- ///
- [TestMethod]
- public void UpdateNullable()
- {
- var _source = new UserAccount("123", "123@gmail.com", new DateTime(2023, 9, 24));
- var _update = new UpdateUser
- {
- Id = "123",
- };
- var configDate = new TypeAdapterConfig();
-
- configDate.ForType()
- .Map(dest => dest.Modified, src => new DateTime(2025, 9, 24))
- .IgnoreNullValues(true);
-
- _update.Adapt(_source, configDate);
-
- var _sourceEmailUpdate = new UserAccount("123", "123@gmail.com", new DateTime(2023, 9, 24));
- var _updateEmail = new UpdateUser
- {
- Email = "245@gmail.com",
- };
-
- var config = new TypeAdapterConfig();
- config.ForType()
- .IgnoreNullValues(true);
-
- var _resultEmail = _updateEmail.Adapt(_sourceEmailUpdate, config);
-
- _source.Id.ShouldBe("123");
- _source.Created.ShouldBe(new DateTime(2023, 9, 24));
- _source.Modified.ShouldBe(new DateTime(2025, 9, 24));
- _source.Email.ShouldBe("123@gmail.com");
- _sourceEmailUpdate.Id.ShouldBe("123");
- _sourceEmailUpdate.Created.ShouldBe(new DateTime(2023, 9, 24));
- _sourceEmailUpdate.Modified.ShouldBe(null);
- _sourceEmailUpdate.Email.ShouldBe("245@gmail.com");
-
- }
-
- ///
- /// https://github.com/MapsterMapper/Mapster/issues/569
- ///
- [TestMethod]
- public void ImplicitOperatorCurrentWorkFromClass()
- {
- var guid = Guid.NewGuid();
- var pocoWithGuid1 = new PocoWithGuid { Id = guid };
- var pocoWithId2 = new PocoWithId { Id = new Id(guid) };
-
- var pocoWithId1 = pocoWithGuid1.Adapt();
- var pocoWithGuid2 = pocoWithId2.Adapt();
-
- pocoWithId1.Id.ToString().Equals(guid.ToString()).ShouldBeTrue();
- pocoWithGuid2.Id.Equals(guid).ShouldBeTrue();
-
- var _result = pocoWithId1.Adapt(pocoWithGuid2);
-
- _result.Id.ToString().Equals(guid.ToString()).ShouldBeTrue(); // Guid value transmitted
- object.ReferenceEquals(_result, pocoWithGuid2).ShouldBeTrue(); // Not created new instanse from class pocoWithGuid2
- _result.ShouldBeOfType();
-
- }
-
- [TestMethod]
- public void DetectFakeRecord()
- {
- var _source = new TestClassPublicCtr(200);
- var _destination = new FakeRecord { X = 300 };
- var _result = _source.Adapt(_destination);
- _destination.X.ShouldBe(200);
- object.ReferenceEquals(_destination, _result).ShouldBeTrue();
- }
-
- [TestMethod]
- public void OnlyInlineRecordWorked()
- {
+
+ _destination.ShouldBeOfType();
+ _result.X.ShouldBe(200);
+ object.ReferenceEquals(_destination, _result).ShouldBeFalse();
+ }
+
+ [TestMethod]
+ public void AdaptToSealtedRecord()
+ {
+ var _sourceRecord = new TestRecord() { X = 2000 };
+ var _destinationSealtedRecord = new TestSealedRecord() { X = 3000 };
+ var _RecordResult = _sourceRecord.Adapt(_destinationSealtedRecord);
+
+ _RecordResult.X.ShouldBe(2000);
+ object.ReferenceEquals(_destinationSealtedRecord, _RecordResult).ShouldBeFalse();
+ }
+
+ [TestMethod]
+ public void AdaptToSealtedPositionalRecord()
+ {
+ var _sourceRecord = new TestRecord() { X = 2000 };
+ var _destinationSealtedPositionalRecord = new TestSealedRecordPositional(4000);
+ var _RecordResult = _sourceRecord.Adapt(_destinationSealtedPositionalRecord);
+
+ _RecordResult.X.ShouldBe(2000);
+ object.ReferenceEquals(_destinationSealtedPositionalRecord, _RecordResult).ShouldBeFalse();
+ }
+
+ [TestMethod]
+ public void AdaptClassToClassPublicCtrIsNotInstanse()
+ {
+ var _source = new TestClassPublicCtr(200);
+ var _destination = new TestClassPublicCtr(400);
+ var _result = _source.Adapt(_destination);
+
+ _destination.ShouldBeOfType();
+ _destination.X.ShouldBe(200);
+ object.ReferenceEquals(_destination, _result).ShouldBeTrue();
+ }
+
+ [TestMethod]
+ public void AdaptClassToClassProtectdCtrIsNotInstanse()
+ {
+ var _source = new TestClassPublicCtr(200);
+ var _destination = new TestClassProtectedCtr(400);
+ var _result = _source.Adapt(_destination);
+
+ _destination.ShouldBeOfType();
+ _destination.X.ShouldBe(200);
+ object.ReferenceEquals(_destination, _result).ShouldBeTrue();
+ }
+
+ ///
+ /// https://github.com/MapsterMapper/Mapster/issues/615
+ ///
+ [TestMethod]
+ public void AdaptClassIncludeStruct()
+ {
+ TypeAdapterConfig
+ .ForType()
+ .Map(x => x.TestStruct, x => x.SourceWithStruct.TestStruct);
+
+ var source = new SourceWithClass
+ {
+ SourceWithStruct = new SourceWithStruct
+ {
+ TestStruct = new TestStruct("A")
+ }
+ };
+
+ var destination = source.Adapt();
+ destination.TestStruct.Property.ShouldBe("A");
+ }
+
+ ///
+ /// https://github.com/MapsterMapper/Mapster/issues/482
+ ///
+ [TestMethod]
+ public void AdaptClassToClassFromPrivatePropertyIsNotInstanse()
+ {
+ var _source = new TestClassPublicCtr(200);
+ var _destination = new TestClassProtectedCtrPrivateProperty(400, "Me");
+ var _result = _source.Adapt(_destination);
+
+ _destination.ShouldBeOfType();
+ _destination.X.ShouldBe(200);
+ _destination.Name.ShouldBe("Me");
+ object.ReferenceEquals(_destination, _result).ShouldBeTrue();
+ }
+
+ ///
+ /// https://github.com/MapsterMapper/Mapster/issues/427
+ ///
+ [TestMethod]
+ public void UpdateNullable()
+ {
+ var _source = new UserAccount("123", "123@gmail.com", new DateTime(2023, 9, 24));
+ var _update = new UpdateUser
+ {
+ Id = "123",
+ };
+ var configDate = new TypeAdapterConfig();
+
+ configDate.ForType()
+ .Map(dest => dest.Modified, src => new DateTime(2025, 9, 24))
+ .IgnoreNullValues(true);
+
+ _update.Adapt(_source, configDate);
+
+ var _sourceEmailUpdate = new UserAccount("123", "123@gmail.com", new DateTime(2023, 9, 24));
+ var _updateEmail = new UpdateUser
+ {
+ Email = "245@gmail.com",
+ };
+
+ var config = new TypeAdapterConfig();
+ config.ForType()
+ .IgnoreNullValues(true);
+
+ var _resultEmail = _updateEmail.Adapt(_sourceEmailUpdate, config);
+
+ _source.Id.ShouldBe("123");
+ _source.Created.ShouldBe(new DateTime(2023, 9, 24));
+ _source.Modified.ShouldBe(new DateTime(2025, 9, 24));
+ _source.Email.ShouldBe("123@gmail.com");
+ _sourceEmailUpdate.Id.ShouldBe("123");
+ _sourceEmailUpdate.Created.ShouldBe(new DateTime(2023, 9, 24));
+ _sourceEmailUpdate.Modified.ShouldBe(null);
+ _sourceEmailUpdate.Email.ShouldBe("245@gmail.com");
+
+ }
+
+ ///
+ /// https://github.com/MapsterMapper/Mapster/issues/569
+ ///
+ [TestMethod]
+ public void ImplicitOperatorCurrentWorkFromClass()
+ {
+ var guid = Guid.NewGuid();
+ var pocoWithGuid1 = new PocoWithGuid { Id = guid };
+ var pocoWithId2 = new PocoWithId { Id = new Id(guid) };
+
+ var pocoWithId1 = pocoWithGuid1.Adapt();
+ var pocoWithGuid2 = pocoWithId2.Adapt();
+
+ pocoWithId1.Id.ToString().Equals(guid.ToString()).ShouldBeTrue();
+ pocoWithGuid2.Id.Equals(guid).ShouldBeTrue();
+
+ var _result = pocoWithId1.Adapt(pocoWithGuid2);
+
+ _result.Id.ToString().Equals(guid.ToString()).ShouldBeTrue(); // Guid value transmitted
+ object.ReferenceEquals(_result, pocoWithGuid2).ShouldBeTrue(); // Not created new instanse from class pocoWithGuid2
+ _result.ShouldBeOfType();
+
+ }
+
+ [TestMethod]
+ public void DetectFakeRecord()
+ {
+ var _source = new TestClassPublicCtr(200);
+ var _destination = new FakeRecord { X = 300 };
+ var _result = _source.Adapt(_destination);
+ _destination.X.ShouldBe(200);
+ object.ReferenceEquals(_destination, _result).ShouldBeTrue();
+ }
+
+ [TestMethod]
+ public void OnlyInlineRecordWorked()
+ {
var _sourcePoco = new InlinePoco501() { MyInt = 1 , MyString = "Hello" };
- var _sourceOnlyInitRecord = new OnlyInitRecord501 { MyInt = 2, MyString = "Hello World" };
-
- var _resultOnlyinitRecord = _sourcePoco.Adapt();
- var _updateResult = _sourceOnlyInitRecord.Adapt(_resultOnlyinitRecord);
-
- _resultOnlyinitRecord.MyInt.ShouldBe(1);
- _resultOnlyinitRecord.MyString.ShouldBe("Hello");
- _updateResult.MyInt.ShouldBe(2);
- _updateResult.MyString.ShouldBe("Hello World");
- }
-
- [TestMethod]
- public void MultyCtorRecordWorked()
- {
- var _sourcePoco = new InlinePoco501() { MyInt = 1, MyString = "Hello" };
+ var _sourceOnlyInitRecord = new OnlyInitRecord501 { MyInt = 2, MyString = "Hello World" };
+
+ var _resultOnlyinitRecord = _sourcePoco.Adapt();
+ var _updateResult = _sourceOnlyInitRecord.Adapt(_resultOnlyinitRecord);
+
+ _resultOnlyinitRecord.MyInt.ShouldBe(1);
+ _resultOnlyinitRecord.MyString.ShouldBe("Hello");
+ _updateResult.MyInt.ShouldBe(2);
+ _updateResult.MyString.ShouldBe("Hello World");
+ }
+
+ [TestMethod]
+ public void MultyCtorRecordWorked()
+ {
+ var _sourcePoco = new InlinePoco501() { MyInt = 1, MyString = "Hello" };
var _sourceMultyCtorRecord = new MultiCtorRecord (2, "Hello World");
-
- var _resultMultyCtorRecord = _sourcePoco.Adapt();
- var _updateResult = _sourceMultyCtorRecord.Adapt(_resultMultyCtorRecord);
-
- _resultMultyCtorRecord.MyInt.ShouldBe(1);
- _resultMultyCtorRecord.MyString.ShouldBe("Hello");
- _updateResult.MyInt.ShouldBe(2);
- _updateResult.MyString.ShouldBe("Hello World");
- }
-
- [TestMethod]
- public void MultiCtorAndInlineRecordWorked()
- {
+
+ var _resultMultyCtorRecord = _sourcePoco.Adapt();
+ var _updateResult = _sourceMultyCtorRecord.Adapt(_resultMultyCtorRecord);
+
+ _resultMultyCtorRecord.MyInt.ShouldBe(1);
+ _resultMultyCtorRecord.MyString.ShouldBe("Hello");
+ _updateResult.MyInt.ShouldBe(2);
+ _updateResult.MyString.ShouldBe("Hello World");
+ }
+
+ [TestMethod]
+ public void MultiCtorAndInlineRecordWorked()
+ {
var _sourcePoco = new MultiCtorAndInlinePoco() { MyInt = 1, MyString = "Hello", MyEmail = "123@gmail.com", InitData="Test"};
- var _sourceMultiCtorAndInline = new MultiCtorAndInlineRecord(2, "Hello World") { InitData = "Worked", MyEmail = "243@gmail.com" };
-
- var _resultMultiCtorAndInline = _sourcePoco.Adapt();
- var _updateResult = _sourceMultiCtorAndInline.Adapt(_resultMultiCtorAndInline);
-
- _resultMultiCtorAndInline.MyInt.ShouldBe(1);
- _resultMultiCtorAndInline.MyString.ShouldBe("Hello");
- _resultMultiCtorAndInline.MyEmail.ShouldBe("123@gmail.com");
- _resultMultiCtorAndInline.InitData.ShouldBe("Test");
- _updateResult.MyInt.ShouldBe(2);
- _updateResult.MyString.ShouldBe("Hello World");
- _updateResult.MyEmail.ShouldBe("243@gmail.com");
- _updateResult.InitData.ShouldBe("Worked");
- }
-
-
- [TestMethod]
- public void MappingInterfaceToInterface()
- {
- TypeAdapterConfig
- .ForType()
- .Map(dest => dest.TempLength, src => src.Temp.Length);
-
-
- var sourceBase = new SampleInterfaceClsBase
- {
- ActivityData = new SampleActivityData
- {
- Data = new SampleActivityParsedData
- {
- Steps = new List { "A", "B", "C" }
- },
- Temp = "Temp data"
-
- }
-
- };
- var sourceDerived = new SampleInterfaceClsDerived
- {
- ActivityData = new SampleActivityData
- {
- Data = new SampleActivityParsedData
- {
- Steps = new List { "X", "Y", "Z" }
- },
- Temp = "Update Temp data"
-
- }
-
- };
-
- var sourceExt = new SampleInterfaceClsExtentions
- {
- ActivityData = new SampleActivityDataExtentions
- {
- Data = new SampleActivityParsedData
- {
- Steps = new List { "o", "o", "o" }
- },
- Temp = "Extentions data",
- TempLength = "Extentions data".Length
-
- }
-
- };
-
- var TargetBase = sourceBase.Adapt();
- var targetDerived = sourceDerived.Adapt();
- var update = targetDerived.Adapt(TargetBase);
-
- var targetExtention = sourceExt.Adapt();
-
-
- var updExt = targetDerived.Adapt(targetExtention);
-
- targetDerived.ShouldNotBeNull();
- targetDerived.ShouldSatisfyAllConditions(
- () => targetDerived.ActivityData.ShouldBe(sourceDerived.ActivityData),
- () => update.ActivityData.ShouldBe(targetDerived.ActivityData),
-
+ var _sourceMultiCtorAndInline = new MultiCtorAndInlineRecord(2, "Hello World") { InitData = "Worked", MyEmail = "243@gmail.com" };
+
+ var _resultMultiCtorAndInline = _sourcePoco.Adapt();
+ var _updateResult = _sourceMultiCtorAndInline.Adapt(_resultMultiCtorAndInline);
+
+ _resultMultiCtorAndInline.MyInt.ShouldBe(1);
+ _resultMultiCtorAndInline.MyString.ShouldBe("Hello");
+ _resultMultiCtorAndInline.MyEmail.ShouldBe("123@gmail.com");
+ _resultMultiCtorAndInline.InitData.ShouldBe("Test");
+ _updateResult.MyInt.ShouldBe(2);
+ _updateResult.MyString.ShouldBe("Hello World");
+ _updateResult.MyEmail.ShouldBe("243@gmail.com");
+ _updateResult.InitData.ShouldBe("Worked");
+ }
+
+
+ [TestMethod]
+ public void MappingInterfaceToInterface()
+ {
+ TypeAdapterConfig
+ .ForType()
+ .Map(dest => dest.TempLength, src => src.Temp.Length);
+
+
+ var sourceBase = new SampleInterfaceClsBase
+ {
+ ActivityData = new SampleActivityData
+ {
+ Data = new SampleActivityParsedData
+ {
+ Steps = new List { "A", "B", "C" }
+ },
+ Temp = "Temp data"
+
+ }
+
+ };
+ var sourceDerived = new SampleInterfaceClsDerived
+ {
+ ActivityData = new SampleActivityData
+ {
+ Data = new SampleActivityParsedData
+ {
+ Steps = new List { "X", "Y", "Z" }
+ },
+ Temp = "Update Temp data"
+
+ }
+
+ };
+
+ var sourceExt = new SampleInterfaceClsExtentions
+ {
+ ActivityData = new SampleActivityDataExtentions
+ {
+ Data = new SampleActivityParsedData
+ {
+ Steps = new List { "o", "o", "o" }
+ },
+ Temp = "Extentions data",
+ TempLength = "Extentions data".Length
+
+ }
+
+ };
+
+ var TargetBase = sourceBase.Adapt();
+ var targetDerived = sourceDerived.Adapt();
+ var update = targetDerived.Adapt(TargetBase);
+
+ var targetExtention = sourceExt.Adapt();
+
+
+ var updExt = targetDerived.Adapt(targetExtention);
+
+ targetDerived.ShouldNotBeNull();
+ targetDerived.ShouldSatisfyAllConditions(
+ () => targetDerived.ActivityData.ShouldBe(sourceDerived.ActivityData),
+ () => update.ActivityData.ShouldBe(targetDerived.ActivityData),
+
()=> updExt.ActivityData.ShouldBe(targetExtention.ActivityData),
- () => ((SampleActivityDataExtentions)updExt.ActivityData).Temp.ShouldBe(sourceDerived.ActivityData.Temp),
- () => ((SampleActivityDataExtentions)updExt.ActivityData).TempLength.ShouldBe(sourceDerived.ActivityData.Temp.Length),
- // IActivityData interface and all its derivatives do not provide access to the Data property for all implementations of the SampleActivityData class,
- // so this property will not be changed by mapping
- () => ((SampleActivityDataExtentions)updExt.ActivityData).Data.ShouldBe(((SampleActivityDataExtentions)targetExtention.ActivityData).Data)
-
- );
-
- }
-
- ///
- /// https://github.com/MapsterMapper/Mapster/issues/456
- ///
- [TestMethod]
- public void WhenRecordReceivedIgnoreCtorParamProcessing()
- {
+ () => ((SampleActivityDataExtentions)updExt.ActivityData).Temp.ShouldBe(sourceDerived.ActivityData.Temp),
+ () => ((SampleActivityDataExtentions)updExt.ActivityData).TempLength.ShouldBe(sourceDerived.ActivityData.Temp.Length),
+ // IActivityData interface and all its derivatives do not provide access to the Data property for all implementations of the SampleActivityData class,
+ // so this property will not be changed by mapping
+ () => ((SampleActivityDataExtentions)updExt.ActivityData).Data.ShouldBe(((SampleActivityDataExtentions)targetExtention.ActivityData).Data)
+
+ );
+
+ }
+
+ ///
+ /// https://github.com/MapsterMapper/Mapster/issues/456
+ ///
+ [TestMethod]
+ public void WhenRecordReceivedIgnoreCtorParamProcessing()
+ {
TypeAdapterConfig.NewConfig()
- .Ignore(dest => dest.Name);
-
- TypeAdapterConfig.NewConfig()
- .Ignore(dest => dest.User);
-
- var userDto = new UserDto456("Amichai");
- var user = new UserRecord456("John");
- var DtoInsider = new DtoInside(userDto);
- var UserInsider = new UserInside(user, new UserRecord456("Skot"));
-
- var map = userDto.Adapt();
- var maptoTarget = userDto.Adapt(user);
-
- var MapToTargetInsider = DtoInsider.Adapt(UserInsider);
-
- map.Name.ShouldBeNullOrEmpty(); // Ignore is work set default value
- maptoTarget.Name.ShouldBe("John"); // Ignore is work ignored member save value from Destination
- MapToTargetInsider.User.Name.ShouldBe("John"); // Ignore is work member save value from Destination
- MapToTargetInsider.SecondName.Name.ShouldBe("Skot"); // Unmached member save value from Destination
-
- }
-
- [TestMethod]
- public void WhenRecordTypeWorksWithUseDestinationValueAndIgnoreNullValues()
- {
-
- TypeAdapterConfig
- .NewConfig()
- .IgnoreNullValues(true);
-
- var _source = new SourceFromTestUseDestValue() { X = 300, Y = 200, Name = new StudentNameRecord() { Name = "John" } };
- var result = _source.Adapt();
-
- var _sourceFromMapToTarget = new SourceFromTestUseDestValue() { A = 100, X = null, Y = null, Name = null };
-
- var txt1 = _sourceFromMapToTarget.BuildAdapter().CreateMapExpression();
-
- var txt = _sourceFromMapToTarget.BuildAdapter().CreateMapToTargetExpression();
-
- var _resultMapToTarget = _sourceFromMapToTarget.Adapt(result);
-
- result.A.ShouldBe(0); // default Value - not match
- result.S.ShouldBe("Inside Data"); // is not AutoProperty not mod by source
- result.Y.ShouldBe(200); // Y is AutoProperty value transmitted from source
- result.Name.Name.ShouldBe("John"); // transmitted from source standart method
-
- _resultMapToTarget.A.ShouldBe(100);
- _resultMapToTarget.X.ShouldBe(300); // Ignore NullValues work
- _resultMapToTarget.Y.ShouldBe(200); // Ignore NullValues work
- _resultMapToTarget.Name.Name.ShouldBe("John"); // Ignore NullValues work
-
- }
-
- ///
- /// https://github.com/MapsterMapper/Mapster/issues/771
- /// https://github.com/MapsterMapper/Mapster/issues/746
- ///
- [TestMethod]
- public void FixCtorParamMapping()
- {
- var sourceRequestPaymentDto = new PaymentDTO771("MasterCard", "1234", "12/99", "234", 12);
- var sourceRequestOrderDto = new OrderDTO771(Guid.NewGuid(), Guid.NewGuid(), "order123", sourceRequestPaymentDto);
- var db = new Database746(UserID: "256", Password: "123");
-
-
- var result = new CreateOrderRequest771(sourceRequestOrderDto).Adapt();
- var resultID = db.Adapt(new Database746());
-
-
- result.Order.Payment.CVV.ShouldBe("234");
- resultID.UserID.ShouldBe("256");
- }
-
- ///
- /// https://github.com/MapsterMapper/Mapster/issues/842
- ///
- [TestMethod]
- public void ClassCtorAutomapingWorking()
- {
- var source = new TestRecord() { X = 100 };
- var result = source.Adapt();
-
- result.X.ShouldBe(100);
- }
-
- ///
- /// https://github.com/MapsterMapper/Mapster/issues/842
- ///
- [TestMethod]
- public void ClassCustomCtorWithMapWorking()
- {
- TypeAdapterConfig.NewConfig()
- .Map("y", src => src.X);
-
-
- var source = new TestRecord() { X = 100 };
- var result = source.Adapt();
-
- result.X.ShouldBe(100);
- }
-
- ///
- /// https://github.com/MapsterMapper/Mapster/issues/842
- ///
- [TestMethod]
- public void ClassCustomCtorInsiderUpdateWorking()
- {
- TypeAdapterConfig.NewConfig()
- .Map("y", src => src.X);
-
- var source = new InsiderData() { X = new TestRecord() { X = 100 } };
- var destination = new InsiderWithCtorDestYx(); // null insider
- source.Adapt(destination);
-
- destination.X.X.ShouldBe(100);
- }
-
- ///
- /// https://github.com/MapsterMapper/Mapster/issues/842
- ///
- [TestMethod]
- public void ClassUpdateAutoPropertyWitoutSetterWorking()
- {
- var source = new TestRecord() { X = 100 };
- var patch = new TestRecord() { X = 200 };
- var result = source.Adapt();
-
- patch.Adapt(result);
-
- result.X.ShouldBe(200);
- }
-
- ///
- /// https://github.com/MapsterMapper/Mapster/issues/883
- ///
- [TestMethod]
- public void ClassCtorActivateDefaultValue()
- {
- var source = new Source833
- {
- Value1 = "123",
- };
-
- Should.NotThrow(() =>
- {
- var target = source.Adapt();
- target.Value1.ShouldBe("123");
- target.Value2.ShouldBe(default);
- });
- }
-
- ///
- /// https://github.com/MapsterMapper/Mapster/issues/911
- ///
- [TestMethod]
- public void NotSelfCreationTypeMappingToSelfWithOutError()
- {
- var src = new Uri("https://www.google.com/");
- var srcJ = JsonDocument.Parse("{\"key\": \"value\"}");
-
- var result = src.Adapt();
- var resultJ = srcJ.Adapt();
-
- result.ToString().ShouldBe("https://www.google.com/");
- resultJ.RootElement.GetProperty("key").ToString().ShouldBe("value");
- }
-
- #region NowNotWorking
-
- ///
- /// https://github.com/MapsterMapper/Mapster/issues/430
- ///
- [Ignore]
- [TestMethod]
- public void CollectionUpdate()
- {
- List sources = new()
- {
- new(541),
- new(234)
- };
- var destination = new List();
- var _result = sources.Adapt(destination);
-
- destination.Count.ShouldBe(_result.Count);
- }
-
- #endregion NowNotWorking
-
- }
-
-
- #region TestClasses
-
- public class Source833
- {
- public required string Value1 { get; init; }
- }
-
- public class Target833
- {
- public Target833(string value1, string value2)
- {
- Value1 = value1;
- Value2 = value2;
- }
-
- public string Value1 { get; }
-
- public string Value2 { get; }
- }
-
- public sealed record Database746(
- string Server = "",
- string Name = "",
- string? UserID = null,
- string? Password = null);
-
- public record CreateOrderRequest771(OrderDTO771 Order);
-
- public record CreateOrderCommand771(OrderDTO771 Order);
-
-
- public record OrderDTO771
- (
- Guid Id,
- Guid CustomerId,
- string OrderName,
- PaymentDTO771 Payment
- );
-
- public record PaymentDTO771
- (
- string CardName,
- string CardNumber,
- string Expiration,
- string CVV,
- int PaymentMethod
- );
-
- public class Person553
- {
-
- public string LastName { get; set; }
- public string FirstMidName { get; set; }
- }
-
- public class Person554
- {
- public required int ID { get; set; }
- public string LastName { get; set; }
- public string FirstMidName { get; set; }
- }
-
-
- public class SourceFromTestUseDestValue
- {
- public int? A { get; set; }
- public int? X { get; set; }
- public int? Y { get; set; }
- public StudentNameRecord Name { get; set; }
- }
-
-
- public record TestRecordUseDestValue()
- {
- private string _s = "Inside Data";
-
- public int A { get; set; }
- public int X { get; set; }
-
- [UseDestinationValue]
- public int Y { get; }
-
- [UseDestinationValue]
- public string S { get => _s; }
-
- [UseDestinationValue]
- public StudentNameRecord Name { get; } = new StudentNameRecord() { Name = "Marta" };
- }
-
- public record StudentNameRecord
- {
- public string Name { get; set; }
- }
-
- public record TestRecordY()
- {
- public int X { get; set; }
- public int Y { get; set; }
- }
-
- public record UserInside(UserRecord456 User, UserRecord456 SecondName);
- public record DtoInside(UserDto456 User);
-
- public record UserRecord456(string Name);
-
- public record UserDto456(string Name);
-
- public interface IActivityDataExtentions : IActivityData
- {
- public int TempLength { get; set; }
- }
-
- public interface IActivityData : IActivityDataBase
- {
- public string Temp { get; set; }
- }
-
- public interface IActivityDataBase
- {
-
- }
-
-
- public class SampleInterfaceClsExtentions
- {
- public IActivityDataExtentions? ActivityData { get; set; }
-
- public SampleInterfaceClsExtentions()
- {
-
- }
-
- public SampleInterfaceClsExtentions(IActivityDataExtentions data)
- {
- SetActivityData(data);
- }
-
- public void SetActivityData(IActivityDataExtentions data)
- {
- ActivityData = data;
- }
- }
-
-
-
- public class SampleInterfaceClsBase
- {
- public IActivityDataBase? ActivityData { get; set; }
-
- public SampleInterfaceClsBase()
- {
-
- }
-
- public SampleInterfaceClsBase(IActivityDataBase data)
- {
- SetActivityData(data);
- }
-
- public void SetActivityData(IActivityDataBase data)
- {
- ActivityData = data;
- }
- }
-
- public class SampleInterfaceClsDerived
- {
- public IActivityData? ActivityData { get; set; }
-
- public SampleInterfaceClsDerived()
- {
-
- }
-
- public SampleInterfaceClsDerived(IActivityData data)
- {
- SetActivityData(data);
- }
-
- public void SetActivityData(IActivityData data)
- {
- ActivityData = data;
- }
- }
-
- public class SampleActivityDataExtentions : IActivityDataExtentions
- {
- public SampleActivityParsedData Data { get; set; }
- public string Temp { get; set; }
- public int TempLength { get; set; }
- }
-
- public class SampleActivityData : IActivityData
- {
- public SampleActivityParsedData Data { get; set; }
- public string Temp { get; set; }
- }
-
- public class SampleActivityParsedData
- {
- public List Steps { get; set; } = new List();
- }
-
-
-
- class MultiCtorAndInlinePoco
- {
- public int MyInt { get; set; }
- public string MyString { get; set; }
- public string MyEmail { get; set; }
- public string InitData { get; set; }
- }
-
- record MultiCtorAndInlineRecord
- {
- public MultiCtorAndInlineRecord(int myInt)
- {
- MyInt = myInt;
- }
-
- public MultiCtorAndInlineRecord(int myInt, string myString) : this(myInt)
- {
- MyString = myString;
- }
-
-
- public int MyInt { get; private set; }
- public string MyString { get; private set; }
- public string MyEmail { get; set; }
- public string InitData { get; init; }
- }
-
- record MultiCtorRecord
- {
- public MultiCtorRecord(int myInt)
- {
- MyInt = myInt;
- }
-
- public MultiCtorRecord(int myInt, string myString) : this(myInt)
- {
- MyString = myString;
- }
-
- public int MyInt { get; private set; }
- public string MyString { get; private set; }
- }
-
- class InlinePoco501
- {
- public int MyInt { get; set; }
- public string MyString { get; set; }
- }
-
- record OnlyInitRecord501
- {
- public int MyInt { get; init; }
- public string MyString { get; init; }
- }
-
- class PocoWithGuid
- {
- public Guid Id { get; init; }
- }
-
- class PocoWithId
- {
- public Id Id { get; init; }
- }
-
- class Id
- {
- private readonly Guid _guid;
- public Id(Guid id) => _guid = id;
-
- public static implicit operator Id(Guid value) => new(value);
- public static implicit operator Guid(Id value) => value._guid;
-
- public override string ToString() => _guid.ToString();
- }
-
- public class FakeRecord
- {
- protected FakeRecord(FakeRecord fake) { }
- public FakeRecord() { }
-
- public int X { get; set; }
- }
-
- class UserAccount
- {
- public UserAccount(string id, string email, DateTime created)
- {
- Id = id;
- Email = email;
- Created = created;
- }
- protected UserAccount() { }
-
- public string Id { get; set; }
- public string? Email { get; set; }
- public DateTime Created { get; set; }
- public DateTime? Modified { get; set; }
- }
-
- class UpdateUser
- {
- public string? Id { get; set; }
- public string? Email { get; set; }
- public DateTime? Created { get; set; }
- public DateTime? Modified { get; set; }
- }
-
- class DestinationWithStruct
- {
- public TestStruct TestStruct { get; set; }
- }
-
- class SourceWithClass
- {
- public SourceWithStruct SourceWithStruct { get; set; }
- }
-
- class SourceWithStruct
- {
- public TestStruct TestStruct { get; set; }
- }
-
- struct TestStruct
- {
- public string Property { get; }
- public TestStruct(string property) : this()
- {
- Property = property;
- }
- }
-
- class TestClassPublicCtr
- {
- public TestClassPublicCtr() { }
-
- public TestClassPublicCtr(int x)
- {
- X = x;
- }
-
- public int X { get; set; }
- }
-
- class TestClassProtectedCtr
- {
- protected TestClassProtectedCtr() { }
-
- public TestClassProtectedCtr(int x)
- {
- X = x;
- }
-
- public int X { get; set; }
- }
-
- class TestClassProtectedCtrPrivateProperty
- {
- protected TestClassProtectedCtrPrivateProperty() { }
-
- public TestClassProtectedCtrPrivateProperty(int x, string name)
- {
- X = x;
- Name = name;
- }
-
- public int X { get; private set; }
-
- public string Name { get; private set; }
- }
-
- record TestRecord()
- {
- public int X { set; get; }
- }
-
- record TestRecordPositional(int X);
-
- record struct TestRecordStruct
- {
- public int X { set; get; }
- }
-
- ///
- /// Different Checked Constructor Attribute From Spec
- /// https://learn.microsoft.com/ru-ru/dotnet/csharp/language-reference/proposals/csharp-9.0/records#copy-and-clone-members
- ///
- sealed record TestSealedRecord()
- {
- public int X { get; set; }
- }
-
- sealed record TestSealedRecordPositional(int X);
-
- class AutoCtorDestX
- {
- public AutoCtorDestX(int x)
- {
- X = x;
- }
-
- public int X { get; set; }
- }
-
- class AutoCtorDestYx
- {
- public AutoCtorDestYx(int y)
- {
- X = y;
- }
-
- public int X { get; }
- }
-
- class InsiderData
- {
- public TestRecord X { set; get; }
- }
-
- class InsiderWithCtorDestYx
- {
- public AutoCtorDestYx X { set; get; }
- }
-
- #endregion TestClasses
+ .Ignore(dest => dest.Name);
+
+ TypeAdapterConfig.NewConfig()
+ .Ignore(dest => dest.User);
+
+ var userDto = new UserDto456("Amichai");
+ var user = new UserRecord456("John");
+ var DtoInsider = new DtoInside(userDto);
+ var UserInsider = new UserInside(user, new UserRecord456("Skot"));
+
+ var map = userDto.Adapt();
+ var maptoTarget = userDto.Adapt(user);
+
+ var MapToTargetInsider = DtoInsider.Adapt(UserInsider);
+
+ map.Name.ShouldBeNullOrEmpty(); // Ignore is work set default value
+ maptoTarget.Name.ShouldBe("John"); // Ignore is work ignored member save value from Destination
+ MapToTargetInsider.User.Name.ShouldBe("John"); // Ignore is work member save value from Destination
+ MapToTargetInsider.SecondName.Name.ShouldBe("Skot"); // Unmached member save value from Destination
+
+ }
+
+ [TestMethod]
+ public void WhenRecordTypeWorksWithUseDestinationValueAndIgnoreNullValues()
+ {
+
+ TypeAdapterConfig
+ .NewConfig()
+ .IgnoreNullValues(true);
+
+ var _source = new SourceFromTestUseDestValue() { X = 300, Y = 200, Name = new StudentNameRecord() { Name = "John" } };
+ var result = _source.Adapt();
+
+ var _sourceFromMapToTarget = new SourceFromTestUseDestValue() { A = 100, X = null, Y = null, Name = null };
+
+ var txt1 = _sourceFromMapToTarget.BuildAdapter().CreateMapExpression();
+
+ var txt = _sourceFromMapToTarget.BuildAdapter().CreateMapToTargetExpression();
+
+ var _resultMapToTarget = _sourceFromMapToTarget.Adapt(result);
+
+ result.A.ShouldBe(0); // default Value - not match
+ result.S.ShouldBe("Inside Data"); // is not AutoProperty not mod by source
+ result.Y.ShouldBe(200); // Y is AutoProperty value transmitted from source
+ result.Name.Name.ShouldBe("John"); // transmitted from source standart method
+
+ _resultMapToTarget.A.ShouldBe(100);
+ _resultMapToTarget.X.ShouldBe(300); // Ignore NullValues work
+ _resultMapToTarget.Y.ShouldBe(200); // Ignore NullValues work
+ _resultMapToTarget.Name.Name.ShouldBe("John"); // Ignore NullValues work
+
+ }
+
+ ///
+ /// https://github.com/MapsterMapper/Mapster/issues/771
+ /// https://github.com/MapsterMapper/Mapster/issues/746
+ ///
+ [TestMethod]
+ public void FixCtorParamMapping()
+ {
+ var sourceRequestPaymentDto = new PaymentDTO771("MasterCard", "1234", "12/99", "234", 12);
+ var sourceRequestOrderDto = new OrderDTO771(Guid.NewGuid(), Guid.NewGuid(), "order123", sourceRequestPaymentDto);
+ var db = new Database746(UserID: "256", Password: "123");
+
+
+ var result = new CreateOrderRequest771(sourceRequestOrderDto).Adapt();
+ var resultID = db.Adapt(new Database746());
+
+
+ result.Order.Payment.CVV.ShouldBe("234");
+ resultID.UserID.ShouldBe("256");
+ }
+
+ ///
+ /// https://github.com/MapsterMapper/Mapster/issues/842
+ ///
+ [TestMethod]
+ public void ClassCtorAutomapingWorking()
+ {
+ var source = new TestRecord() { X = 100 };
+ var result = source.Adapt();
+
+ result.X.ShouldBe(100);
+ }
+
+ ///
+ /// https://github.com/MapsterMapper/Mapster/issues/842
+ ///
+ [TestMethod]
+ public void ClassCustomCtorWithMapWorking()
+ {
+ TypeAdapterConfig.NewConfig()
+ .Map("y", src => src.X);
+
+
+ var source = new TestRecord() { X = 100 };
+ var result = source.Adapt();
+
+ result.X.ShouldBe(100);
+ }
+
+ ///
+ /// https://github.com/MapsterMapper/Mapster/issues/842
+ ///
+ [TestMethod]
+ public void ClassCustomCtorInsiderUpdateWorking()
+ {
+ TypeAdapterConfig.NewConfig()
+ .Map("y", src => src.X);
+
+ var source = new InsiderData() { X = new TestRecord() { X = 100 } };
+ var destination = new InsiderWithCtorDestYx(); // null insider
+ source.Adapt(destination);
+
+ destination.X.X.ShouldBe(100);
+ }
+
+ ///
+ /// https://github.com/MapsterMapper/Mapster/issues/842
+ ///
+ [TestMethod]
+ public void ClassUpdateAutoPropertyWitoutSetterWorking()
+ {
+ var source = new TestRecord() { X = 100 };
+ var patch = new TestRecord() { X = 200 };
+ var result = source.Adapt();
+
+ patch.Adapt(result);
+
+ result.X.ShouldBe(200);
+ }
+
+ ///
+ /// https://github.com/MapsterMapper/Mapster/issues/883
+ ///
+ [TestMethod]
+ public void ClassCtorActivateDefaultValue()
+ {
+ var source = new Source833
+ {
+ Value1 = "123",
+ };
+
+ Should.NotThrow(() =>
+ {
+ var target = source.Adapt();
+ target.Value1.ShouldBe("123");
+ target.Value2.ShouldBe(default);
+ });
+ }
+
+ ///
+ /// https://github.com/MapsterMapper/Mapster/issues/911
+ ///
+ [TestMethod]
+ public void NotSelfCreationTypeMappingToSelfWithOutError()
+ {
+ var src = new Uri("https://www.google.com/");
+ var srcJ = JsonDocument.Parse("{\"key\": \"value\"}");
+
+ var result = src.Adapt();
+ var resultJ = srcJ.Adapt();
+
+ result.ToString().ShouldBe("https://www.google.com/");
+ resultJ.RootElement.GetProperty("key").ToString().ShouldBe("value");
+ }
+
+
+ ///
+ /// Regression: MapToTarget expression for record types should not contain
+ /// compiler-generated backing fields (e.g. <Prop>k__BackingField).
+ /// Covers the case where source and destination have fully matching properties.
+ ///
+ [TestMethod]
+ public void MapToTargetRecordShouldNotContainBackingFields()
+ {
+ var source = new BackingFieldSource { A = 1, B = "hello", C = 42m };
+ var destination = new BackingFieldRecord { A = 0, B = "world", C = 0m };
+
+ var mapToTargetExpr = source.BuildAdapter()
+ .CreateMapToTargetExpression();
+ var exprString = GetExpressionDebugView(mapToTargetExpr);
+ exprString.ShouldNotContain("k__BackingField");
+
+ var mapExpr = source.BuildAdapter()
+ .CreateMapExpression();
+ var mapExprString = GetExpressionDebugView(mapExpr);
+ mapExprString.ShouldNotContain("k__BackingField");
+
+ var result = source.Adapt(destination);
+ result.A.ShouldBe(1);
+ result.B.ShouldBe("hello");
+ result.C.ShouldBe(42m);
+ object.ReferenceEquals(result, destination).ShouldBeFalse();
+ }
+
+ ///
+ /// Regression: MapToTarget expression for positional record types should not
+ /// contain compiler-generated backing fields.
+ ///
+ [TestMethod]
+ public void MapToTargetPositionalRecordShouldNotContainBackingFields()
+ {
+ var source = new BackingFieldSource { A = 10, B = "src", C = 99m };
+ var destination = new BackingFieldPositionalRecord(0, "dest", 0m);
+
+ var mapToTargetExpr = source.BuildAdapter()
+ .CreateMapToTargetExpression();
+ var exprString = GetExpressionDebugView(mapToTargetExpr);
+ exprString.ShouldNotContain("k__BackingField");
+
+ var result = source.Adapt(destination);
+ result.A.ShouldBe(10);
+ result.B.ShouldBe("src");
+ result.C.ShouldBe(99m);
+ }
+
+ ///
+ /// Regression: MapToTarget with partially matching types should not contain
+ /// backing fields. The destination record has extra properties not present
+ /// in the source, which are restored from the destination instance.
+ ///
+ [TestMethod]
+ public void MapToTargetPartialMatchRecordShouldNotContainBackingFields()
+ {
+ var source = new PartialSource { A = 1, B = "hello" };
+ var destination = new PartialDestRecord { A = 0, B = "world", Extra1 = "keep", Extra2 = 99 };
+
+ var mapToTargetExpr = source.BuildAdapter()
+ .CreateMapToTargetExpression();
+ var exprString = GetExpressionDebugView(mapToTargetExpr);
+ exprString.ShouldNotContain("k__BackingField");
+
+ var result = source.Adapt(destination);
+ result.A.ShouldBe(1);
+ result.B.ShouldBe("hello");
+ result.Extra1.ShouldBe("keep");
+ result.Extra2.ShouldBe(99);
+ }
+
+ ///
+ /// Regression: MapToTarget with IgnoreNullValues and IgnoreCase name matching
+ /// should not leak backing fields into the generated expression.
+ /// Uses nullable source with partial match.
+ ///
+ [TestMethod]
+ public void MapToTargetWithIgnoreNullValuesAndIgnoreCaseShouldNotContainBackingFields()
+ {
+ var config = new TypeAdapterConfig();
+ config.Default
+ .IgnoreNullValues(true)
+ .NameMatchingStrategy(NameMatchingStrategy.IgnoreCase);
+
+ var source = new NullablePartialSource { A = 1, B = null };
+ var destination = new PartialDestRecord { A = 0, B = "keep", Extra1 = "preserved", Extra2 = 77 };
+
+ var mapToTargetExpr = source.BuildAdapter(config)
+ .CreateMapToTargetExpression();
+ var exprString = GetExpressionDebugView(mapToTargetExpr);
+ exprString.ShouldNotContain("k__BackingField");
+
+ var result = source.Adapt(destination, config);
+ result.A.ShouldBe(1);
+ result.B.ShouldBe("keep"); // null ignored
+ result.Extra1.ShouldBe("preserved");
+ result.Extra2.ShouldBe(77);
+ }
+
+ ///
+ /// Regression: MapToTarget with IgnoreNullValues and nullable source
+ /// properties should not contain backing fields in the expression.
+ ///
+ [TestMethod]
+ public void MapToTargetWithIgnoreNullValuesShouldNotContainBackingFields()
+ {
+ var config = new TypeAdapterConfig();
+ config.ForType()
+ .IgnoreNullValues(true);
+
+ var source = new NullableSource { A = 1, B = null, C = null };
+ var destination = new BackingFieldRecord { A = 0, B = "keep", C = 42m };
+
+ var mapToTargetExpr = source.BuildAdapter(config)
+ .CreateMapToTargetExpression();
+ var exprString = GetExpressionDebugView(mapToTargetExpr);
+ exprString.ShouldNotContain("k__BackingField");
+
+ var result = source.Adapt(destination, config);
+ result.A.ShouldBe(1);
+ result.B.ShouldBe("keep");
+ result.C.ShouldBe(42m);
+ }
+
+ ///
+ /// Regression: MapToTarget with EnableNonPublicMembers should not leak
+ /// backing fields into the expression.
+ ///
+ [TestMethod]
+ public void MapToTargetWithEnableNonPublicMembersShouldNotContainBackingFields()
+ {
+ var config = new TypeAdapterConfig();
+ config.ForType()
+ .EnableNonPublicMembers(true);
+
+ var source = new BackingFieldSource { A = 5, B = "test", C = 100m };
+ var destination = new BackingFieldRecord { A = 0, B = "old", C = 0m };
+
+ var mapToTargetExpr = source.BuildAdapter(config)
+ .CreateMapToTargetExpression();
+ var exprString = GetExpressionDebugView(mapToTargetExpr);
+ exprString.ShouldNotContain("k__BackingField");
+
+ var result = source.Adapt(destination, config);
+ result.A.ShouldBe(5);
+ result.B.ShouldBe("test");
+ result.C.ShouldBe(100m);
+ }
+
+ ///
+ /// Regression: MapToTarget with Ignore config for a record should not
+ /// include backing fields for ignored or non-ignored members.
+ ///
+ [TestMethod]
+ public void MapToTargetWithIgnoreConfigShouldNotContainBackingFields()
+ {
+ var config = new TypeAdapterConfig();
+ config.ForType()
+ .Ignore(dest => dest.C);
+
+ var source = new BackingFieldSource { A = 1, B = "hello", C = 42m };
+ var destination = new BackingFieldRecord { A = 0, B = "world", C = 99m };
+
+ var mapToTargetExpr = source.BuildAdapter(config)
+ .CreateMapToTargetExpression();
+ var exprString = GetExpressionDebugView(mapToTargetExpr);
+ exprString.ShouldNotContain("k__BackingField");
+
+ var result = source.Adapt(destination, config);
+ result.A.ShouldBe(1);
+ result.B.ShouldBe("hello");
+ result.C.ShouldBe(99m);
+ }
+
+ ///
+ /// Regression: MapToTarget from a class to a sealed positional record
+ /// with partially matching properties should not contain backing fields.
+ ///
+ [TestMethod]
+ public void MapToTargetSealedPositionalRecordShouldNotContainBackingFields()
+ {
+ var source = new PartialSource { A = 10, B = "src" };
+ var destination = new SealedPartialDestRecord(0, "dest", "extra", 77);
+
+ var mapToTargetExpr = source.BuildAdapter()
+ .CreateMapToTargetExpression();
+ var exprString = GetExpressionDebugView(mapToTargetExpr);
+ exprString.ShouldNotContain("k__BackingField");
+
+ var result = source.Adapt(destination);
+ result.A.ShouldBe(10);
+ result.B.ShouldBe("src");
+ result.Extra1.ShouldBe("extra");
+ result.Extra2.ShouldBe(77);
+ }
+
+ ///
+ /// Regression: MapToTarget with settings IgnoreNullValues + IgnoreCase
+ /// combined with EnableNonPublicMembers and partial match
+ /// should not contain backing fields.
+ ///
+ [TestMethod]
+ public void MapToTargetWithAllSettingsCombinedShouldNotContainBackingFields()
+ {
+ var config = new TypeAdapterConfig();
+ config.Default
+ .IgnoreNullValues(true)
+ .NameMatchingStrategy(NameMatchingStrategy.IgnoreCase)
+ .EnableNonPublicMembers(true);
+
+ var source = new NullablePartialSource { A = 5, B = "mapped" };
+ var destination = new PartialDestRecord { A = 0, B = "old", Extra1 = "stay", Extra2 = 42 };
+
+ var mapToTargetExpr = source.BuildAdapter(config)
+ .CreateMapToTargetExpression();
+ var exprString = GetExpressionDebugView(mapToTargetExpr);
+ exprString.ShouldNotContain("k__BackingField");
+
+ var result = source.Adapt(destination, config);
+ result.A.ShouldBe(5);
+ result.B.ShouldBe("mapped");
+ result.Extra1.ShouldBe("stay");
+ result.Extra2.ShouldBe(42);
+ }
+
+ ///
+ /// Regression: MapToTarget with IgnoreNullValues + IgnoreCase for a
+ /// positional record with extra ctor params should not contain backing fields.
+ ///
+ [TestMethod]
+ public void MapToTargetPositionalRecordWithGlobalSettingsShouldNotContainBackingFields()
+ {
+ var config = new TypeAdapterConfig();
+ config.Default
+ .IgnoreNullValues(true)
+ .NameMatchingStrategy(NameMatchingStrategy.IgnoreCase);
+
+ var source = new NullablePartialSource { A = 10, B = null };
+ var destination = new SealedPartialDestRecord(0, "dest", "extra", 77);
+
+ var mapToTargetExpr = source.BuildAdapter(config)
+ .CreateMapToTargetExpression();
+ var exprString = GetExpressionDebugView(mapToTargetExpr);
+ exprString.ShouldNotContain("k__BackingField");
+
+ var result = source.Adapt(destination, config);
+ result.A.ShouldBe(10);
+ // B is null from source; for positional records, IgnoreNullValues does not
+ // apply to constructor parameters, so B becomes null in the new instance.
+ result.B.ShouldBeNull();
+ result.Extra1.ShouldBe("extra");
+ result.Extra2.ShouldBe(77);
+ }
+
+ ///
+ /// Regression: IgnoreNonMapped(true) adds ALL non-resolver members (including
+ /// compiler-generated backing fields) to Settings.Ignore. Then
+ /// RecordIngnoredWithoutConditonRestore selects members in the Ignore list
+ /// and restores them from the destination — leaking backing field bindings
+ /// into the generated MemberInit expression.
+ ///
+ [TestMethod]
+ public void MapToTargetWithIgnoreNonMappedShouldNotContainBackingFields()
+ {
+ var config = new TypeAdapterConfig();
+ config.ForType()
+ .IgnoreNonMapped(true)
+ .Map(dest => dest.A, src => src.A)
+ .Map(dest => dest.B, src => src.B)
+ .Map(dest => dest.C, src => src.C);
+
+ var source = new BackingFieldSource { A = 1, B = "hello", C = 42m };
+ var destination = new BackingFieldRecord { A = 0, B = "world", C = 0m };
+
+ // Check the expression does not contain backing field references
+ var mapToTargetExpr = source.BuildAdapter(config)
+ .CreateMapToTargetExpression();
+ var exprString = GetExpressionDebugView(mapToTargetExpr);
+ exprString.ShouldNotContain("k__BackingField");
+ }
+
+ ///
+ /// Regression: IgnoreNonMapped(true) with record MapToTarget should produce
+ /// correct mapped values — backing fields must not overwrite property values.
+ /// Uses a separate config to avoid side-effects from expression inspection.
+ ///
+ [TestMethod]
+ public void MapToTargetWithIgnoreNonMappedShouldProduceCorrectValues()
+ {
+ var config = new TypeAdapterConfig();
+ config.ForType()
+ .IgnoreNonMapped(true)
+ .Map(dest => dest.A, src => src.A)
+ .Map(dest => dest.B, src => src.B)
+ .Map(dest => dest.C, src => src.C);
+
+ var source = new BackingFieldSource { A = 1, B = "hello", C = 42m };
+ var destination = new BackingFieldRecord { A = 0, B = "world", C = 0m };
+
+ var result = source.Adapt(destination, config);
+ result.A.ShouldBe(1);
+ result.B.ShouldBe("hello");
+ result.C.ShouldBe(42m);
+ }
+
+ ///
+ /// Regression: Full reproduction of user's global settings with IgnoreNonMapped.
+ /// IgnoreNullValues(true) + IgnoreNonMapped(true) + IgnoreCase with partial
+ /// match and explicit Map resolvers. Expression must not contain backing fields.
+ ///
+ [TestMethod]
+ public void MapToTargetWithAllUserGlobalSettingsExpressionShouldNotContainBackingFields()
+ {
+ var config = new TypeAdapterConfig();
+ config.Default
+ .IgnoreNullValues(true)
+ .IgnoreNonMapped(true)
+ .NameMatchingStrategy(NameMatchingStrategy.IgnoreCase);
+
+ config.ForType()
+ .Map(dest => dest.A, src => src.A)
+ .Map(dest => dest.B, src => src.B);
+
+ var source = new NullablePartialSource { A = 5, B = null };
+
+ var mapToTargetExpr = source.BuildAdapter(config)
+ .CreateMapToTargetExpression();
+ var exprString = GetExpressionDebugView(mapToTargetExpr);
+ exprString.ShouldNotContain("k__BackingField");
+ }
+
+ ///
+ /// Regression: Full reproduction of user's global settings with IgnoreNonMapped.
+ /// Functional correctness — backing fields must not overwrite property values.
+ ///
+ [TestMethod]
+ public void MapToTargetWithAllUserGlobalSettingsShouldProduceCorrectValues()
+ {
+ var config = new TypeAdapterConfig();
+ config.Default
+ .IgnoreNullValues(true)
+ .IgnoreNonMapped(true)
+ .NameMatchingStrategy(NameMatchingStrategy.IgnoreCase);
+
+ config.ForType()
+ .Map(dest => dest.A, src => src.A)
+ .Map(dest => dest.B, src => src.B);
+
+ var source = new NullablePartialSource { A = 5, B = null };
+ var destination = new PartialDestRecord { A = 0, B = "keep", Extra1 = "stay", Extra2 = 42 };
+
+ var result = source.Adapt(destination, config);
+ result.A.ShouldBe(5);
+ result.B.ShouldBe("keep"); // null ignored
+ result.Extra1.ShouldBe("stay");
+ result.Extra2.ShouldBe(42);
+ }
+
+ ///
+ /// Regression: IgnoreNonMapped(true) with a positional record destination.
+ /// Backing fields of positional record properties must not leak into the
+ /// MapToTarget expression.
+ ///
+ [TestMethod]
+ public void MapToTargetPositionalRecordWithIgnoreNonMappedShouldNotContainBackingFields()
+ {
+ var config = new TypeAdapterConfig();
+ config.Default
+ .IgnoreNullValues(true)
+ .IgnoreNonMapped(true)
+ .NameMatchingStrategy(NameMatchingStrategy.IgnoreCase);
+
+ config.ForType()
+ .Map(dest => dest.A, src => src.A)
+ .Map(dest => dest.B, src => src.B);
+
+ var source = new PartialSource { A = 10, B = "src" };
+ var destination = new SealedPartialDestRecord(0, "dest", "extra", 77);
+
+ var mapToTargetExpr = source.BuildAdapter(config)
+ .CreateMapToTargetExpression();
+ var exprString = GetExpressionDebugView(mapToTargetExpr);
+ exprString.ShouldNotContain("k__BackingField");
+
+ // Use a separate config for Adapt to avoid side-effects
+ var config2 = new TypeAdapterConfig();
+ config2.Default
+ .IgnoreNullValues(true)
+ .IgnoreNonMapped(true)
+ .NameMatchingStrategy(NameMatchingStrategy.IgnoreCase);
+
+ config2.ForType()
+ .Map(dest => dest.A, src => src.A)
+ .Map(dest => dest.B, src => src.B);
+
+ var result = source.Adapt(destination, config2);
+ result.A.ShouldBe(10);
+ result.B.ShouldBe("src");
+ result.Extra1.ShouldBe("extra");
+ result.Extra2.ShouldBe(77);
+ }
+
+ #region NowNotWorking
+
+ ///
+ /// https://github.com/MapsterMapper/Mapster/issues/430
+ ///
+ [Ignore]
+ [TestMethod]
+ public void CollectionUpdate()
+ {
+ List sources = new()
+ {
+ new(541),
+ new(234)
+ };
+ var destination = new List();
+ var _result = sources.Adapt(destination);
+
+ destination.Count.ShouldBe(_result.Count);
+ }
+
+ #endregion NowNotWorking
+
+ }
+
+
+ #region TestClasses
+
+ public class BackingFieldSource
+ {
+ public int A { get; set; }
+ public string B { get; set; }
+ public decimal C { get; set; }
+ }
+
+ public record BackingFieldRecord
+ {
+ public int A { get; set; }
+ public string B { get; set; }
+ public decimal C { get; set; }
+ }
+
+ public record BackingFieldPositionalRecord(int A, string B, decimal C);
+
+ public class PartialSource
+ {
+ public int A { get; set; }
+ public string B { get; set; }
+ }
+
+ public record PartialDestRecord
+ {
+ public int A { get; set; }
+ public string B { get; set; }
+ public string Extra1 { get; set; }
+ public int Extra2 { get; set; }
+ }
+
+ public sealed record SealedPartialDestRecord(int A, string B, string Extra1, int Extra2);
+
+ public class NullableSource
+ {
+ public int? A { get; set; }
+ public string? B { get; set; }
+ public decimal? C { get; set; }
+ }
+
+ public class NullablePartialSource
+ {
+ public int? A { get; set; }
+ public string? B { get; set; }
+ }
+
+ public class Source833
+ {
+ public required string Value1 { get; init; }
+ }
+
+ public class Target833
+ {
+ public Target833(string value1, string value2)
+ {
+ Value1 = value1;
+ Value2 = value2;
+ }
+
+ public string Value1 { get; }
+
+ public string Value2 { get; }
+ }
+
+ public sealed record Database746(
+ string Server = "",
+ string Name = "",
+ string? UserID = null,
+ string? Password = null);
+
+ public record CreateOrderRequest771(OrderDTO771 Order);
+
+ public record CreateOrderCommand771(OrderDTO771 Order);
+
+
+ public record OrderDTO771
+ (
+ Guid Id,
+ Guid CustomerId,
+ string OrderName,
+ PaymentDTO771 Payment
+ );
+
+ public record PaymentDTO771
+ (
+ string CardName,
+ string CardNumber,
+ string Expiration,
+ string CVV,
+ int PaymentMethod
+ );
+
+ public class Person553
+ {
+
+ public string LastName { get; set; }
+ public string FirstMidName { get; set; }
+ }
+
+ public class Person554
+ {
+ public required int ID { get; set; }
+ public string LastName { get; set; }
+ public string FirstMidName { get; set; }
+ }
+
+
+ public class SourceFromTestUseDestValue
+ {
+ public int? A { get; set; }
+ public int? X { get; set; }
+ public int? Y { get; set; }
+ public StudentNameRecord Name { get; set; }
+ }
+
+
+ public record TestRecordUseDestValue()
+ {
+ private string _s = "Inside Data";
+
+ public int A { get; set; }
+ public int X { get; set; }
+
+ [UseDestinationValue]
+ public int Y { get; }
+
+ [UseDestinationValue]
+ public string S { get => _s; }
+
+ [UseDestinationValue]
+ public StudentNameRecord Name { get; } = new StudentNameRecord() { Name = "Marta" };
+ }
+
+ public record StudentNameRecord
+ {
+ public string Name { get; set; }
+ }
+
+ public record TestRecordY()
+ {
+ public int X { get; set; }
+ public int Y { get; set; }
+ }
+
+ public record UserInside(UserRecord456 User, UserRecord456 SecondName);
+ public record DtoInside(UserDto456 User);
+
+ public record UserRecord456(string Name);
+
+ public record UserDto456(string Name);
+
+ public interface IActivityDataExtentions : IActivityData
+ {
+ public int TempLength { get; set; }
+ }
+
+ public interface IActivityData : IActivityDataBase
+ {
+ public string Temp { get; set; }
+ }
+
+ public interface IActivityDataBase
+ {
+
+ }
+
+
+ public class SampleInterfaceClsExtentions
+ {
+ public IActivityDataExtentions? ActivityData { get; set; }
+
+ public SampleInterfaceClsExtentions()
+ {
+
+ }
+
+ public SampleInterfaceClsExtentions(IActivityDataExtentions data)
+ {
+ SetActivityData(data);
+ }
+
+ public void SetActivityData(IActivityDataExtentions data)
+ {
+ ActivityData = data;
+ }
+ }
+
+
+
+ public class SampleInterfaceClsBase
+ {
+ public IActivityDataBase? ActivityData { get; set; }
+
+ public SampleInterfaceClsBase()
+ {
+
+ }
+
+ public SampleInterfaceClsBase(IActivityDataBase data)
+ {
+ SetActivityData(data);
+ }
+
+ public void SetActivityData(IActivityDataBase data)
+ {
+ ActivityData = data;
+ }
+ }
+
+ public class SampleInterfaceClsDerived
+ {
+ public IActivityData? ActivityData { get; set; }
+
+ public SampleInterfaceClsDerived()
+ {
+
+ }
+
+ public SampleInterfaceClsDerived(IActivityData data)
+ {
+ SetActivityData(data);
+ }
+
+ public void SetActivityData(IActivityData data)
+ {
+ ActivityData = data;
+ }
+ }
+
+ public class SampleActivityDataExtentions : IActivityDataExtentions
+ {
+ public SampleActivityParsedData Data { get; set; }
+ public string Temp { get; set; }
+ public int TempLength { get; set; }
+ }
+
+ public class SampleActivityData : IActivityData
+ {
+ public SampleActivityParsedData Data { get; set; }
+ public string Temp { get; set; }
+ }
+
+ public class SampleActivityParsedData
+ {
+ public List Steps { get; set; } = new List();
+ }
+
+
+
+ class MultiCtorAndInlinePoco
+ {
+ public int MyInt { get; set; }
+ public string MyString { get; set; }
+ public string MyEmail { get; set; }
+ public string InitData { get; set; }
+ }
+
+ record MultiCtorAndInlineRecord
+ {
+ public MultiCtorAndInlineRecord(int myInt)
+ {
+ MyInt = myInt;
+ }
+
+ public MultiCtorAndInlineRecord(int myInt, string myString) : this(myInt)
+ {
+ MyString = myString;
+ }
+
+
+ public int MyInt { get; private set; }
+ public string MyString { get; private set; }
+ public string MyEmail { get; set; }
+ public string InitData { get; init; }
+ }
+
+ record MultiCtorRecord
+ {
+ public MultiCtorRecord(int myInt)
+ {
+ MyInt = myInt;
+ }
+
+ public MultiCtorRecord(int myInt, string myString) : this(myInt)
+ {
+ MyString = myString;
+ }
+
+ public int MyInt { get; private set; }
+ public string MyString { get; private set; }
+ }
+
+ class InlinePoco501
+ {
+ public int MyInt { get; set; }
+ public string MyString { get; set; }
+ }
+
+ record OnlyInitRecord501
+ {
+ public int MyInt { get; init; }
+ public string MyString { get; init; }
+ }
+
+ class PocoWithGuid
+ {
+ public Guid Id { get; init; }
+ }
+
+ class PocoWithId
+ {
+ public Id Id { get; init; }
+ }
+
+ class Id
+ {
+ private readonly Guid _guid;
+ public Id(Guid id) => _guid = id;
+
+ public static implicit operator Id(Guid value) => new(value);
+ public static implicit operator Guid(Id value) => value._guid;
+
+ public override string ToString() => _guid.ToString();
+ }
+
+ public class FakeRecord
+ {
+ protected FakeRecord(FakeRecord fake) { }
+ public FakeRecord() { }
+
+ public int X { get; set; }
+ }
+
+ class UserAccount
+ {
+ public UserAccount(string id, string email, DateTime created)
+ {
+ Id = id;
+ Email = email;
+ Created = created;
+ }
+ protected UserAccount() { }
+
+ public string Id { get; set; }
+ public string? Email { get; set; }
+ public DateTime Created { get; set; }
+ public DateTime? Modified { get; set; }
+ }
+
+ class UpdateUser
+ {
+ public string? Id { get; set; }
+ public string? Email { get; set; }
+ public DateTime? Created { get; set; }
+ public DateTime? Modified { get; set; }
+ }
+
+ class DestinationWithStruct
+ {
+ public TestStruct TestStruct { get; set; }
+ }
+
+ class SourceWithClass
+ {
+ public SourceWithStruct SourceWithStruct { get; set; }
+ }
+
+ class SourceWithStruct
+ {
+ public TestStruct TestStruct { get; set; }
+ }
+
+ struct TestStruct
+ {
+ public string Property { get; }
+ public TestStruct(string property) : this()
+ {
+ Property = property;
+ }
+ }
+
+ class TestClassPublicCtr
+ {
+ public TestClassPublicCtr() { }
+
+ public TestClassPublicCtr(int x)
+ {
+ X = x;
+ }
+
+ public int X { get; set; }
+ }
+
+ class TestClassProtectedCtr
+ {
+ protected TestClassProtectedCtr() { }
+
+ public TestClassProtectedCtr(int x)
+ {
+ X = x;
+ }
+
+ public int X { get; set; }
+ }
+
+ class TestClassProtectedCtrPrivateProperty
+ {
+ protected TestClassProtectedCtrPrivateProperty() { }
+
+ public TestClassProtectedCtrPrivateProperty(int x, string name)
+ {
+ X = x;
+ Name = name;
+ }
+
+ public int X { get; private set; }
+
+ public string Name { get; private set; }
+ }
+
+ record TestRecord()
+ {
+ public int X { set; get; }
+ }
+
+ record TestRecordPositional(int X);
+
+ record struct TestRecordStruct
+ {
+ public int X { set; get; }
+ }
+
+ ///
+ /// Different Checked Constructor Attribute From Spec
+ /// https://learn.microsoft.com/ru-ru/dotnet/csharp/language-reference/proposals/csharp-9.0/records#copy-and-clone-members
+ ///
+ sealed record TestSealedRecord()
+ {
+ public int X { get; set; }
+ }
+
+ sealed record TestSealedRecordPositional(int X);
+
+ class AutoCtorDestX
+ {
+ public AutoCtorDestX(int x)
+ {
+ X = x;
+ }
+
+ public int X { get; set; }
+ }
+
+ class AutoCtorDestYx
+ {
+ public AutoCtorDestYx(int y)
+ {
+ X = y;
+ }
+
+ public int X { get; }
+ }
+
+ class InsiderData
+ {
+ public TestRecord X { set; get; }
+ }
+
+ class InsiderWithCtorDestYx
+ {
+ public AutoCtorDestYx X { set; get; }
+ }
+
+ #endregion TestClasses
}
diff --git a/src/Mapster/Adapters/BaseClassAdapter.cs b/src/Mapster/Adapters/BaseClassAdapter.cs
index a8b7a4c0..f192823e 100644
--- a/src/Mapster/Adapters/BaseClassAdapter.cs
+++ b/src/Mapster/Adapters/BaseClassAdapter.cs
@@ -300,6 +300,8 @@ protected void IgnoreNonMapped (ClassModel classModel, CompileArgument arg)
foreach (var item in notMappingToIgnore)
{
+ if (!item.ShouldMapMember(arg, MemberSide.Destination))
+ continue;
arg.Settings.Ignore.TryAdd(item.Name, new IgnoreDictionary.IgnoreItem());
}
}
diff --git a/src/Mapster/Adapters/RecordTypeAdapter.cs b/src/Mapster/Adapters/RecordTypeAdapter.cs
index 659da39c..78ab6c04 100644
--- a/src/Mapster/Adapters/RecordTypeAdapter.cs
+++ b/src/Mapster/Adapters/RecordTypeAdapter.cs
@@ -141,15 +141,18 @@ private List RecordIngnoredWithoutConditonRestore(Expression? des
var lines = new List();
- foreach (var member in members)
- {
- if (destination == null)
- continue;
-
+ foreach (var member in members)
+ {
+ if (destination == null)
+ continue;
+
+ if (!member.ShouldMapMember(arg, MemberSide.Destination))
+ continue;
+
IgnoreItem ignore;
- ProcessIgnores(arg, member, out ignore);
-
- if (member.SetterModifier == AccessModifier.None ||
+ ProcessIgnores(arg, member, out ignore);
+
+ if (member.SetterModifier == AccessModifier.None ||
ignore.Condition != null ||
contructorMembers.Any(x => string.Equals(x.Name, member.Name, StringComparison.InvariantCultureIgnoreCase)))
continue;