Skip to content

Commit bdfe266

Browse files
authored
Merge pull request #646 from DocSvartz/add-asRecord-Attribute
FIx Issue #537 - Step 2 - Add Support Extended Record Function + Attribute from support used current record definitions
2 parents 0e4c3b8 + e06f6ed commit bdfe266

File tree

11 files changed

+252
-116
lines changed

11 files changed

+252
-116
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using System;
2+
3+
namespace Mapster
4+
{
5+
[AttributeUsage(AttributeTargets.Class
6+
| AttributeTargets.Struct
7+
| AttributeTargets.Property
8+
| AttributeTargets.Field, AllowMultiple = true)]
9+
public class AdaptWithAttribute : Attribute
10+
{
11+
public AdaptDirectives AdaptDirective { get; set; }
12+
public AdaptWithAttribute(AdaptDirectives directive)
13+
{
14+
AdaptDirective = directive;
15+
}
16+
}
17+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
namespace Mapster
2+
{
3+
public enum AdaptDirectives
4+
{
5+
None = 0,
6+
DestinationAsRecord = 1
7+
}
8+
}

src/Mapster.Core/Utils/RecordTypeIdentityHelper.cs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,11 @@ private static bool IsRecordСonstructor(Type type)
1717
if (ctors.Count < 2)
1818
return false;
1919

20-
var isRecordTypeCtor = type.GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic)
20+
var isRecordTypeCtor =
21+
ctors
2122
.Where(x => x.IsFamily == true || (type.IsSealed && x.IsPrivate == true)) // add target from Sealed record
2223
.Any(x => x.GetParameters()
23-
.Any(y => y.ParameterType == type));
24+
.Any(y => y.ParameterType == type));
2425

2526
if (isRecordTypeCtor)
2627
return true;
@@ -43,5 +44,17 @@ public static bool IsRecordType(Type type)
4344

4445
return false;
4546
}
47+
48+
public static bool IsDirectiveTagret(Type type)
49+
{
50+
var arrt = type.GetCustomAttributes<AdaptWithAttribute>()?.FirstOrDefault()?.AdaptDirective;
51+
52+
if (arrt == null)
53+
return false;
54+
if (arrt == AdaptDirectives.DestinationAsRecord)
55+
return true;
56+
57+
return false;
58+
}
4659
}
4760
}

src/Mapster.Tests/WhenIgnoringConditionally.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,6 @@ public void IgnoreIf_Can_Be_Combined()
160160
public void IgnoreIf_Apply_To_RecordType()
161161
{
162162
TypeAdapterConfig<SimplePoco, SimpleRecord>.NewConfig()
163-
.EnableNonPublicMembers(true) // add or
164163
.IgnoreIf((src, dest) => src.Name == "TestName", dest => dest.Name)
165164
.Compile();
166165

@@ -188,7 +187,8 @@ public class SimpleDto
188187
public string Name { get; set; }
189188
}
190189

191-
public class SimpleRecord // or Replace on record
190+
[AdaptWith(AdaptDirectives.DestinationAsRecord)]
191+
public class SimpleRecord
192192
{
193193
public int Id { get; }
194194
public string Name { get; }

src/Mapster.Tests/WhenMappingPrivateFieldsAndProperties.cs

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ public void Should_Map_Private_Field_To_New_Object_Correctly()
6161
dto.Name.ShouldBe(customerName);
6262
}
6363

64+
6465
[TestMethod]
6566
public void Should_Map_Private_Property_To_New_Object_Correctly()
6667
{
@@ -78,21 +79,20 @@ public void Should_Map_Private_Property_To_New_Object_Correctly()
7879
}
7980

8081
[TestMethod]
81-
public void Should_Map_To_Private_Fields_Correctly()
82+
public void Should_Map_To_Private_Fields_Correctly()
8283
{
83-
SetUpMappingNonPublicFields<CustomerDTO, CustomerWithPrivateField>();
84-
85-
var dto = new CustomerDTO
84+
SetUpMappingNonPublicFields<CustomerDTOWithPrivateGet, CustomerWithPrivateField>();
85+
86+
var dto = new CustomerDTOWithPrivateGet
8687
{
8788
Id = 1,
8889
Name = "Customer 1"
8990
};
9091

91-
var customer = dto.Adapt<CustomerWithPrivateField>();
92+
var customer = dto.Adapt<CustomerWithPrivateField>();
9293

93-
Assert.IsNotNull(customer);
94-
Assert.IsTrue(customer.HasId(dto.Id));
95-
customer.Name.ShouldBe(dto.Name);
94+
customer.HasId().ShouldBe(1);
95+
customer.Name.ShouldBe("Customer 1");
9696
}
9797

9898
[TestMethod]
@@ -108,9 +108,8 @@ public void Should_Map_To_Private_Properties_Correctly()
108108

109109
var customer = dto.Adapt<CustomerWithPrivateProperty>();
110110

111-
Assert.IsNotNull(customer);
112-
customer.Id.ShouldBe(dto.Id);
113-
Assert.IsTrue(customer.HasName(dto.Name));
111+
customer.Id.ShouldBe(1);
112+
customer.HasName().ShouldBe("Customer 1");
114113
}
115114

116115
[TestMethod]
@@ -167,39 +166,39 @@ private static void SetUpMappingNonPublicProperties<TSource, TDestination>()
167166

168167
public class CustomerWithPrivateField
169168
{
170-
private readonly int _id;
169+
private int _id;
171170
public string Name { get; private set; }
172171

173-
private CustomerWithPrivateField() { }
172+
public CustomerWithPrivateField() { }
174173

175174
public CustomerWithPrivateField(int id, string name)
176175
{
177176
_id = id;
178177
Name = name;
179178
}
180179

181-
public bool HasId(int id)
180+
public int HasId()
182181
{
183-
return _id == id;
182+
return _id;
184183
}
185184
}
186185

187-
public class CustomerWithPrivateProperty
186+
public class CustomerWithPrivateProperty
188187
{
189188
public int Id { get; private set; }
190189
private string Name { get; set; }
191190

192-
private CustomerWithPrivateProperty() { }
191+
public CustomerWithPrivateProperty() { }
193192

194-
public CustomerWithPrivateProperty(int id, string name)
193+
public CustomerWithPrivateProperty(int id, string name)
195194
{
196195
Id = id;
197196
Name = name;
198197
}
199198

200-
public bool HasName(string name)
199+
public string HasName()
201200
{
202-
return Name == name;
201+
return Name;
203202
}
204203
}
205204

@@ -228,6 +227,12 @@ public class CustomerDTO
228227
public string Name { get; set; }
229228
}
230229

230+
public class CustomerDTOWithPrivateGet
231+
{
232+
public int Id { private get; set; }
233+
public string Name { private get; set; }
234+
}
235+
231236
public class Pet
232237
{
233238
public string Name { get; set; }

src/Mapster.Tests/WhenMappingRecordRegression.cs

Lines changed: 101 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public void AdaptRecordStructToRecordStruct()
4141
var _structResult = _sourceStruct.Adapt(_destinationStruct);
4242

4343
_structResult.X.ShouldBe(1000);
44-
object.ReferenceEquals(_destinationStruct, _structResult).ShouldBeFalse();
44+
_destinationStruct.X.Equals(_structResult.X).ShouldBeFalse();
4545
}
4646

4747
[TestMethod]
@@ -194,26 +194,6 @@ public void UpdateNullable()
194194

195195
}
196196

197-
/// <summary>
198-
/// https://github.com/MapsterMapper/Mapster/issues/524
199-
/// </summary>
200-
[TestMethod]
201-
public void TSousreIsObjectUpdateUseDynamicCast()
202-
{
203-
var source = new TestClassPublicCtr { X = 123 };
204-
var _result = SomemapWithDynamic(source);
205-
206-
_result.X.ShouldBe(123);
207-
}
208-
209-
TestClassPublicCtr SomemapWithDynamic(object source)
210-
{
211-
var dest = new TestClassPublicCtr { X = 321 };
212-
var dest1 = source.Adapt(dest,source.GetType(),dest.GetType());
213-
214-
return dest;
215-
}
216-
217197
/// <summary>
218198
/// https://github.com/MapsterMapper/Mapster/issues/569
219199
/// </summary>
@@ -247,6 +227,56 @@ public void DetectFakeRecord()
247227
_destination.X.ShouldBe(200);
248228
object.ReferenceEquals(_destination, _result).ShouldBeTrue();
249229
}
230+
231+
[TestMethod]
232+
public void OnlyInlineRecordWorked()
233+
{
234+
var _sourcePoco = new InlinePoco501() { MyInt = 1 , MyString = "Hello" };
235+
var _sourceOnlyInitRecord = new OnlyInitRecord501 { MyInt = 2, MyString = "Hello World" };
236+
237+
var _resultOnlyinitRecord = _sourcePoco.Adapt<OnlyInitRecord501>();
238+
var _updateResult = _sourceOnlyInitRecord.Adapt(_resultOnlyinitRecord);
239+
240+
_resultOnlyinitRecord.MyInt.ShouldBe(1);
241+
_resultOnlyinitRecord.MyString.ShouldBe("Hello");
242+
_updateResult.MyInt.ShouldBe(2);
243+
_updateResult.MyString.ShouldBe("Hello World");
244+
}
245+
246+
[TestMethod]
247+
public void MultyCtorRecordWorked()
248+
{
249+
var _sourcePoco = new InlinePoco501() { MyInt = 1, MyString = "Hello" };
250+
var _sourceMultyCtorRecord = new MultiCtorRecord (2, "Hello World");
251+
252+
var _resultMultyCtorRecord = _sourcePoco.Adapt<MultiCtorRecord>();
253+
var _updateResult = _sourceMultyCtorRecord.Adapt(_resultMultyCtorRecord);
254+
255+
_resultMultyCtorRecord.MyInt.ShouldBe(1);
256+
_resultMultyCtorRecord.MyString.ShouldBe("Hello");
257+
_updateResult.MyInt.ShouldBe(2);
258+
_updateResult.MyString.ShouldBe("Hello World");
259+
}
260+
261+
[TestMethod]
262+
public void MultiCtorAndInlineRecordWorked()
263+
{
264+
var _sourcePoco = new MultiCtorAndInlinePoco() { MyInt = 1, MyString = "Hello", MyEmail = "[email protected]", InitData="Test"};
265+
var _sourceMultiCtorAndInline = new MultiCtorAndInlineRecord(2, "Hello World") { InitData = "Worked", MyEmail = "[email protected]" };
266+
267+
var _resultMultiCtorAndInline = _sourcePoco.Adapt<MultiCtorAndInlineRecord>();
268+
var _updateResult = _sourceMultiCtorAndInline.Adapt(_resultMultiCtorAndInline);
269+
270+
_resultMultiCtorAndInline.MyInt.ShouldBe(1);
271+
_resultMultiCtorAndInline.MyString.ShouldBe("Hello");
272+
_resultMultiCtorAndInline.MyEmail.ShouldBe("[email protected]");
273+
_resultMultiCtorAndInline.InitData.ShouldBe("Test");
274+
_updateResult.MyInt.ShouldBe(2);
275+
_updateResult.MyString.ShouldBe("Hello World");
276+
_updateResult.MyEmail.ShouldBe("[email protected]");
277+
_updateResult.InitData.ShouldBe("Worked");
278+
}
279+
250280

251281
#region NowNotWorking
252282

@@ -268,35 +298,67 @@ public void CollectionUpdate()
268298
destination.Count.ShouldBe(_result.Count);
269299
}
270300

271-
/// <summary>
272-
/// https://github.com/MapsterMapper/Mapster/issues/524
273-
/// Not work. Already has a special overload:
274-
/// .Adapt(this object source, object destination, Type sourceType, Type destinationType)
275-
/// </summary>
276-
[Ignore]
277-
[TestMethod]
278-
public void TSousreIsObjectUpdate()
279-
{
280-
var source = new TestClassPublicCtr { X = 123 };
281-
var _result = Somemap(source);
301+
#endregion NowNotWorking
302+
303+
}
304+
282305

283-
_result.X.ShouldBe(123);
306+
#region TestClasses
307+
308+
class MultiCtorAndInlinePoco
309+
{
310+
public int MyInt { get; set; }
311+
public string MyString { get; set; }
312+
public string MyEmail { get; set; }
313+
public string InitData { get; set; }
314+
}
315+
316+
record MultiCtorAndInlineRecord
317+
{
318+
public MultiCtorAndInlineRecord(int myInt)
319+
{
320+
MyInt = myInt;
284321
}
285322

286-
TestClassPublicCtr Somemap(object source)
323+
public MultiCtorAndInlineRecord(int myInt, string myString) : this(myInt)
287324
{
288-
var dest = new TestClassPublicCtr { X = 321 };
289-
var dest1 = source.Adapt(dest); // typeof(TSource) always return Type as Object. Need use dynamic or Cast to Runtime Type before Adapt
325+
MyString = myString;
326+
}
327+
328+
329+
public int MyInt { get; private set; }
330+
public string MyString { get; private set; }
331+
public string MyEmail { get; set; }
332+
public string InitData { get; init; }
333+
}
290334

291-
return dest;
335+
record MultiCtorRecord
336+
{
337+
public MultiCtorRecord(int myInt)
338+
{
339+
MyInt = myInt;
292340
}
293341

294-
#endregion NowNotWorking
342+
public MultiCtorRecord(int myInt, string myString) : this(myInt)
343+
{
344+
MyString = myString;
345+
}
295346

347+
public int MyInt { get; private set; }
348+
public string MyString { get; private set; }
296349
}
297350

351+
class InlinePoco501
352+
{
353+
public int MyInt { get; set; }
354+
public string MyString { get; set; }
355+
}
298356

299-
#region TestClasses
357+
record OnlyInitRecord501
358+
{
359+
public int MyInt { get; init; }
360+
public string MyString { get; init; }
361+
}
300362

301363
class PocoWithGuid
302364
{

0 commit comments

Comments
 (0)