Skip to content

Commit 4f016de

Browse files
committed
Object To TDestination fixed
1 parent f678d12 commit 4f016de

3 files changed

Lines changed: 184 additions & 44 deletions

File tree

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.Tests/WhenMappingRecordRegression.cs

Lines changed: 1 addition & 44 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+
_structResult.X.ShouldNotBe(_destinationStruct.X);
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>
@@ -268,29 +248,6 @@ public void CollectionUpdate()
268248
destination.Count.ShouldBe(_result.Count);
269249
}
270250

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);
282-
283-
_result.X.ShouldBe(123);
284-
}
285-
286-
TestClassPublicCtr Somemap(object source)
287-
{
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
290-
291-
return dest;
292-
}
293-
294251
#endregion NowNotWorking
295252

296253
}

src/Mapster/TypeAdapter.cs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,37 @@ public static TDestination Adapt<TSource, TDestination>(this TSource source, TDe
9393
/// <returns>Adapted destination type.</returns>
9494
public static TDestination Adapt<TSource, TDestination>(this TSource source, TDestination destination, TypeAdapterConfig config)
9595
{
96+
var sourceType = source.GetType();
97+
var destinationType = destination.GetType();
98+
99+
if (sourceType == typeof(object)) // Infinity loop in ObjectAdapter if Runtime Type of source is Object
100+
return destination;
101+
102+
if (typeof(TSource) == typeof(object) || typeof(TDestination) == typeof(object))
103+
return UpdateFuncFromPackedinObject(source, destination, config, sourceType, destinationType);
104+
96105
var fn = config.GetMapToTargetFunction<TSource, TDestination>();
97106
return fn(source, destination);
98107
}
99108

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

0 commit comments

Comments
 (0)