Skip to content

Commit 3bf9e6b

Browse files
authored
Merge pull request #645 from DocSvartz/ObjectModFix
Fix issue #524. Adding support for working with Types packed into an object to the standard adapter
2 parents baedf16 + cd6ebe5 commit 3bf9e6b

File tree

2 files changed

+183
-0
lines changed

2 files changed

+183
-0
lines changed
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
using Microsoft.VisualStudio.TestTools.UnitTesting;
2+
using Shouldly;
3+
using System;
4+
5+
namespace Mapster.Tests
6+
{
7+
[TestClass]
8+
public class WhenMappingObjectRegression
9+
{
10+
/// <summary>
11+
/// https://github.com/MapsterMapper/Mapster/issues/524
12+
/// </summary>
13+
[TestMethod]
14+
public void TSourceIsObjectUpdate()
15+
{
16+
var source = new Source524 { X1 = 123 };
17+
var _result = Somemap(source);
18+
19+
_result.X1.ShouldBe(123);
20+
}
21+
22+
/// <summary>
23+
/// https://github.com/MapsterMapper/Mapster/issues/524
24+
/// </summary>
25+
[TestMethod]
26+
public void TSourceIsObjectUpdateUseDynamicCast()
27+
{
28+
var source = new Source524 { X1 = 123 };
29+
var _result = SomemapWithDynamic(source);
30+
31+
_result.X1.ShouldBe(123);
32+
}
33+
34+
[TestMethod]
35+
public void UpdateManyDest()
36+
{
37+
var source = new Source524 { X1 = 123 };
38+
var _result = SomemapManyDest(source);
39+
40+
_result.X1.ShouldBe(123);
41+
_result.X2.ShouldBe(127);
42+
}
43+
44+
[TestMethod]
45+
public void UpdateToRealObject()
46+
{
47+
var source = new Source524 { X1 = 123 };
48+
var RealObject = new Object();
49+
50+
var _result = source.Adapt(RealObject);
51+
52+
_result.ShouldBeOfType<Source524>();
53+
((Source524)_result).X1.ShouldBe(source.X1);
54+
55+
}
56+
57+
[TestMethod]
58+
public void RealObjectCastToDestination() /// Warning potential Infinity Loop in ObjectAdapter!!!
59+
{
60+
var source = new Source524 { X1 = 123 };
61+
var RealObject = new Object();
62+
63+
var _result = RealObject.Adapt(source);
64+
65+
_result.ShouldBeOfType<Source524>();
66+
((Source524)_result).X1.ShouldBe(source.X1);
67+
}
68+
69+
[TestMethod]
70+
public void UpdateObjectInsaider()
71+
{
72+
var _source = new InsaderObject() { X1 = 1 };
73+
var _Destination = new InsaderObject() { X1 = 2 };
74+
75+
var _result = _source.Adapt(_Destination);
76+
77+
_result.X1.ShouldBe(_source.X1);
78+
}
79+
80+
[TestMethod]
81+
public void UpdateObjectInsaiderToObject()
82+
{
83+
var _source = new InsaderObject() { X1 = 1 };
84+
var _Destination = new InsaderObject() { X1 = new Object() };
85+
86+
var _result = _source.Adapt(_Destination);
87+
88+
_result.X1.ShouldBe(_source.X1);
89+
}
90+
91+
[TestMethod]
92+
public void UpdateObjectInsaiderWhenObjectinTSource()
93+
{
94+
var _source = new InsaderObject() { X1 = new Object() };
95+
var _Destination = new InsaderObject() { X1 = 3 };
96+
97+
var _result = _source.Adapt(_Destination);
98+
99+
_result.X1.ShouldBe(_source.X1);
100+
}
101+
102+
103+
#region TestFunctions
104+
105+
Dest524 Somemap(object source)
106+
{
107+
var dest = new Dest524 { X1 = 321 };
108+
var dest1 = source.Adapt(dest);
109+
110+
return dest;
111+
}
112+
113+
ManyDest524 SomemapManyDest(object source)
114+
{
115+
var dest = new ManyDest524 { X1 = 321, X2 = 127 };
116+
var dest1 = source.Adapt(dest);
117+
118+
return dest;
119+
}
120+
121+
Dest524 SomemapWithDynamic(object source)
122+
{
123+
var dest = new Dest524 { X1 = 321 };
124+
var dest1 = source.Adapt(dest, source.GetType(), dest.GetType());
125+
126+
return dest;
127+
}
128+
129+
#endregion TestFunctions
130+
131+
#region TestClasses
132+
class Source524
133+
{
134+
public int X1 { get; set; }
135+
}
136+
class Dest524
137+
{
138+
public int X1 { get; set; }
139+
}
140+
141+
class ManyDest524
142+
{
143+
public int X1 { get; set;}
144+
145+
public int X2 { get; set;}
146+
}
147+
148+
class InsaderObject
149+
{
150+
public Object X1 { get; set;}
151+
}
152+
153+
154+
#endregion TestClasses
155+
}
156+
}

src/Mapster/TypeAdapter.cs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,10 +96,37 @@ 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();
101+
102+
if (sourceType == typeof(object)) // Infinity loop in ObjectAdapter if Runtime Type of source is Object
103+
return destination;
104+
105+
if (typeof(TSource) == typeof(object) || typeof(TDestination) == typeof(object))
106+
return UpdateFuncFromPackedinObject(source, destination, config, sourceType, destinationType);
107+
99108
var fn = config.GetMapToTargetFunction<TSource, TDestination>();
100109
return fn(source, destination);
101110
}
102111

112+
private static TDestination UpdateFuncFromPackedinObject<TSource, TDestination>(TSource source, TDestination destination, TypeAdapterConfig config, Type sourceType, Type destinationType)
113+
{
114+
dynamic del = config.GetMapToTargetFunction(sourceType, destinationType);
115+
116+
117+
if (sourceType.GetTypeInfo().IsVisible && destinationType.GetTypeInfo().IsVisible)
118+
{
119+
dynamic objfn = del;
120+
return objfn((dynamic)source, (dynamic)destination);
121+
}
122+
else
123+
{
124+
//NOTE: if type is non-public, we cannot use dynamic
125+
//DynamicInvoke is slow, but works with non-public
126+
return (TDestination)del.DynamicInvoke(source, destination);
127+
}
128+
}
129+
103130
/// <summary>
104131
/// Adapt the source object to the destination type.
105132
/// </summary>

0 commit comments

Comments
 (0)