Skip to content

Commit b9d403f

Browse files
authored
Merge branch 'development' into fix-interfaces-map-regression
2 parents 4241342 + 425a7a9 commit b9d403f

File tree

5 files changed

+125
-4
lines changed

5 files changed

+125
-4
lines changed
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
using Microsoft.VisualStudio.TestTools.UnitTesting;
2+
using Shouldly;
3+
4+
namespace Mapster.Tests;
5+
6+
[TestClass]
7+
public class WhenMappingInitProperty
8+
{
9+
10+
#region Tests
11+
/// <summary>
12+
/// From Issue #672
13+
/// https://github.com/MapsterMapper/Mapster/issues/672
14+
/// </summary>
15+
[TestMethod]
16+
public void WhenMappingToHiddenandNewInitFieldDestination()
17+
{
18+
var source = new Source672() { Id = 156};
19+
var c = source.Adapt<BDestination>();
20+
var s = source.Adapt(new BDestination());
21+
22+
((ADestination)c).Id.ShouldBe(156);
23+
s.Id.ShouldBe(156);
24+
}
25+
26+
[TestMethod]
27+
public void WhenMappingToHiddenandNewInitFieldWithConstructUsing()
28+
{
29+
TypeAdapterConfig<Source672, BDestination>.NewConfig().ConstructUsing(_ => new BDestination());
30+
31+
32+
var source = new Source672() { Id = 256 };
33+
var c = source.Adapt<BDestination>();
34+
var s = source.Adapt(new BDestination());
35+
36+
((ADestination)c).Id.ShouldBe(256);
37+
s.Id.ShouldBe(256);
38+
}
39+
40+
41+
#endregion Tests
42+
43+
44+
#region TestClasses
45+
46+
class Source672
47+
{
48+
public long Id { get; init; }
49+
}
50+
51+
class ADestination
52+
{
53+
public int Id { get; init; }
54+
}
55+
56+
class BDestination : ADestination
57+
{
58+
public new long Id { get; init; }
59+
}
60+
61+
62+
#endregion TestClasses
63+
}

src/Mapster.Tests/WhenMappingToInterface.cs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
using System;
44
using System.Collections.Generic;
55
using System.Linq;
6+
using System.Text.Json.Serialization;
7+
using Newtonsoft.Json;
68

79
namespace Mapster.Tests
810
{
@@ -266,6 +268,27 @@ public void MappingToInteraceWithReadonlyProps_AllPropsInitialized()
266268
);
267269
}
268270

271+
[TestMethod]
272+
public void MappingToInterface_VerifyReadonlyPropsInterfaceRule()
273+
{
274+
SampleInterfaceCls source = new SampleInterfaceCls
275+
{
276+
ActivityData = new SampleActivityData
277+
{
278+
Data = new SampleActivityParsedData
279+
{
280+
Steps = new List<string> { "A", "B", "C" }
281+
}
282+
}
283+
};
284+
285+
SampleInterfaceCls target = source.Adapt<SampleInterfaceCls>();
286+
target.ShouldNotBeNull();
287+
target.ShouldSatisfyAllConditions(
288+
() => target.ActivityData.ShouldBe(source.ActivityData)
289+
);
290+
}
291+
269292
public interface IInheritedDtoWithoutProperties : IInheritedDto
270293
{
271294
}
@@ -374,6 +397,42 @@ public class PropertyInitializationTestSource
374397
public int Property1 { get; set; }
375398
public int Property2 { get; set; }
376399
}
400+
401+
public interface IActivityData
402+
{
403+
404+
}
405+
406+
public class SampleInterfaceCls
407+
{
408+
[Newtonsoft.Json.JsonIgnore]
409+
public IActivityData? ActivityData { get; set; }
410+
411+
public SampleInterfaceCls()
412+
{
413+
414+
}
415+
416+
public SampleInterfaceCls(IActivityData data)
417+
{
418+
SetActivityData(data);
419+
}
420+
421+
public void SetActivityData(IActivityData data)
422+
{
423+
ActivityData = data;
424+
}
425+
}
426+
427+
public class SampleActivityData : IActivityData
428+
{
429+
public SampleActivityParsedData Data { get; set; }
430+
}
431+
432+
public class SampleActivityParsedData
433+
{
434+
public List<string> Steps { get; set; } = new List<string>();
435+
}
377436

378437
}
379438
}

src/Mapster/Adapters/ClassAdapter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ private static Expression SetValueByReflection(MemberMapping member, MemberExpre
183183
var typeofExpression = Expression.Constant(member.Destination!.Type);
184184
var getPropertyMethod = typeof(Type).GetMethod("GetProperty", new[] { typeof(string) })!;
185185
var getPropertyExpression = Expression.Call(typeofExpression, getPropertyMethod,
186-
Expression.Constant(member.DestinationMember.Name));
186+
Expression.Constant(member.DestinationMember.Name, member.DestinationMember.Type));
187187
var setValueMethod =
188188
typeof(PropertyInfo).GetMethod("SetValue", new[] { typeof(object), typeof(object) })!;
189189
var memberAsObject = adapt.To(typeof(object));

src/Mapster/Adapters/ReadOnlyInterfaceAdapter.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ internal class ReadOnlyInterfaceAdapter : ClassAdapter
1111
protected override bool CanMap(PreCompileArgument arg)
1212
{
1313
return arg.DestinationType.IsInterface;
14-
1514
}
1615

1716
protected override bool CanInline(Expression source, Expression? destination, CompileArgument arg)

src/Mapster/TypeAdapter.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,8 @@ public static TDestination Adapt<TSource, TDestination>(this TSource source, TDe
9696
/// <returns>Adapted destination type.</returns>
9797
public static TDestination Adapt<TSource, TDestination>(this TSource source, TDestination destination, TypeAdapterConfig config)
9898
{
99-
var sourceType = source.GetType();
100-
var destinationType = destination.GetType();
99+
var sourceType = source?.GetType();
100+
var destinationType = destination?.GetType();
101101

102102
if (sourceType == typeof(object)) // Infinity loop in ObjectAdapter if Runtime Type of source is Object
103103
return destination;

0 commit comments

Comments
 (0)