Skip to content

Commit

Permalink
Object To TDestination fixed
Browse files Browse the repository at this point in the history
  • Loading branch information
DocSvartz committed Oct 21, 2023
1 parent f678d12 commit 4f016de
Show file tree
Hide file tree
Showing 3 changed files with 184 additions and 44 deletions.
156 changes: 156 additions & 0 deletions src/Mapster.Tests/WhenMappingObjectRegression.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Shouldly;
using System;

namespace Mapster.Tests
{
[TestClass]
public class WhenMappingObjectRegression
{
/// <summary>
/// https://github.com/MapsterMapper/Mapster/issues/524
/// </summary>
[TestMethod]
public void TSourceIsObjectUpdate()
{
var source = new Source524 { X1 = 123 };
var _result = Somemap(source);

_result.X1.ShouldBe(123);
}

/// <summary>
/// https://github.com/MapsterMapper/Mapster/issues/524
/// </summary>
[TestMethod]
public void TSourceIsObjectUpdateUseDynamicCast()
{
var source = new Source524 { X1 = 123 };
var _result = SomemapWithDynamic(source);

_result.X1.ShouldBe(123);
}

[TestMethod]
public void UpdateManyDest()
{
var source = new Source524 { X1 = 123 };
var _result = SomemapManyDest(source);

_result.X1.ShouldBe(123);
_result.X2.ShouldBe(127);
}

[TestMethod]
public void UpdateToRealObject()
{
var source = new Source524 { X1 = 123 };
var RealObject = new Object();

var _result = source.Adapt(RealObject);

_result.ShouldBeOfType<Source524>();
((Source524)_result).X1.ShouldBe(source.X1);

}

[TestMethod]
public void RealObjectCastToDestination() /// Warning potential Infinity Loop in ObjectAdapter!!!
{
var source = new Source524 { X1 = 123 };
var RealObject = new Object();

var _result = RealObject.Adapt(source);

_result.ShouldBeOfType<Source524>();
((Source524)_result).X1.ShouldBe(source.X1);
}

[TestMethod]
public void UpdateObjectInsaider()
{
var _source = new InsaderObject() { X1 = 1 };
var _Destination = new InsaderObject() { X1 = 2 };

var _result = _source.Adapt(_Destination);

_result.X1.ShouldBe(_source.X1);
}

[TestMethod]
public void UpdateObjectInsaiderToObject()
{
var _source = new InsaderObject() { X1 = 1 };
var _Destination = new InsaderObject() { X1 = new Object() };

var _result = _source.Adapt(_Destination);

_result.X1.ShouldBe(_source.X1);
}

[TestMethod]
public void UpdateObjectInsaiderWhenObjectinTSource()
{
var _source = new InsaderObject() { X1 = new Object() };
var _Destination = new InsaderObject() { X1 = 3 };

var _result = _source.Adapt(_Destination);

_result.X1.ShouldBe(_source.X1);
}


#region TestFunctions

Dest524 Somemap(object source)
{
var dest = new Dest524 { X1 = 321 };
var dest1 = source.Adapt(dest);

return dest;
}

ManyDest524 SomemapManyDest(object source)
{
var dest = new ManyDest524 { X1 = 321, X2 = 127 };
var dest1 = source.Adapt(dest);

return dest;
}

Dest524 SomemapWithDynamic(object source)
{
var dest = new Dest524 { X1 = 321 };
var dest1 = source.Adapt(dest, source.GetType(), dest.GetType());

return dest;
}

#endregion TestFunctions

#region TestClasses
class Source524
{
public int X1 { get; set; }
}
class Dest524
{
public int X1 { get; set; }
}

class ManyDest524
{
public int X1 { get; set;}

public int X2 { get; set;}
}

class InsaderObject
{
public Object X1 { get; set;}
}


#endregion TestClasses
}
}
45 changes: 1 addition & 44 deletions src/Mapster.Tests/WhenMappingRecordRegression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public void AdaptRecordStructToRecordStruct()
var _structResult = _sourceStruct.Adapt(_destinationStruct);

_structResult.X.ShouldBe(1000);
object.ReferenceEquals(_destinationStruct, _structResult).ShouldBeFalse();
_structResult.X.ShouldNotBe(_destinationStruct.X);
}

[TestMethod]
Expand Down Expand Up @@ -194,26 +194,6 @@ public void UpdateNullable()

}

/// <summary>
/// https://github.com/MapsterMapper/Mapster/issues/524
/// </summary>
[TestMethod]
public void TSousreIsObjectUpdateUseDynamicCast()
{
var source = new TestClassPublicCtr { X = 123 };
var _result = SomemapWithDynamic(source);

_result.X.ShouldBe(123);
}

TestClassPublicCtr SomemapWithDynamic(object source)
{
var dest = new TestClassPublicCtr { X = 321 };
var dest1 = source.Adapt(dest,source.GetType(),dest.GetType());

return dest;
}

/// <summary>
/// https://github.com/MapsterMapper/Mapster/issues/569
/// </summary>
Expand Down Expand Up @@ -268,29 +248,6 @@ public void CollectionUpdate()
destination.Count.ShouldBe(_result.Count);
}

/// <summary>
/// https://github.com/MapsterMapper/Mapster/issues/524
/// Not work. Already has a special overload:
/// .Adapt(this object source, object destination, Type sourceType, Type destinationType)
/// </summary>
[Ignore]
[TestMethod]
public void TSousreIsObjectUpdate()
{
var source = new TestClassPublicCtr { X = 123 };
var _result = Somemap(source);

_result.X.ShouldBe(123);
}

TestClassPublicCtr Somemap(object source)
{
var dest = new TestClassPublicCtr { X = 321 };
var dest1 = source.Adapt(dest); // typeof(TSource) always return Type as Object. Need use dynamic or Cast to Runtime Type before Adapt

return dest;
}

#endregion NowNotWorking

}
Expand Down
27 changes: 27 additions & 0 deletions src/Mapster/TypeAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,37 @@ public static TDestination Adapt<TSource, TDestination>(this TSource source, TDe
/// <returns>Adapted destination type.</returns>
public static TDestination Adapt<TSource, TDestination>(this TSource source, TDestination destination, TypeAdapterConfig config)
{
var sourceType = source.GetType();
var destinationType = destination.GetType();

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

if (typeof(TSource) == typeof(object) || typeof(TDestination) == typeof(object))
return UpdateFuncFromPackedinObject(source, destination, config, sourceType, destinationType);

var fn = config.GetMapToTargetFunction<TSource, TDestination>();
return fn(source, destination);
}

private static TDestination UpdateFuncFromPackedinObject<TSource, TDestination>(TSource source, TDestination destination, TypeAdapterConfig config, Type sourceType, Type destinationType)
{
dynamic del = config.GetMapToTargetFunction(sourceType, destinationType);


if (sourceType.GetTypeInfo().IsVisible && destinationType.GetTypeInfo().IsVisible)
{
dynamic objfn = del;
return objfn((dynamic)source, (dynamic)destination);
}
else
{
//NOTE: if type is non-public, we cannot use dynamic
//DynamicInvoke is slow, but works with non-public
return (TDestination)del.DynamicInvoke(source, destination);
}
}

/// <summary>
/// Adapt the source object to the destination type.
/// </summary>
Expand Down

0 comments on commit 4f016de

Please sign in to comment.