Skip to content

Commit

Permalink
Final Update of Fix
Browse files Browse the repository at this point in the history
  • Loading branch information
DocSvartz committed Oct 21, 2023
1 parent 8cdb093 commit d7c73e3
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 18 deletions.
27 changes: 27 additions & 0 deletions src/Mapster.Tests/WhenMappingObjectRegression.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Shouldly;
using System;

namespace Mapster.Tests
{
Expand Down Expand Up @@ -40,6 +41,32 @@ public void UpdateManyDest()
_result.X2.ShouldBe(127);
}

[TestMethod]
public void UpdateToRealObject() /// Warning potential Infinity Loop in ObjectAdapter!!!
{
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);
}


#region TestFunctions

Dest524 Somemap(object source)
Expand Down
11 changes: 11 additions & 0 deletions src/Mapster/Adapters/ObjectAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,16 @@ protected override Expression CreateInlineExpression(Expression source, CompileA
{
return CreateInstantiationExpression(source, arg);
}

protected override Expression CreateExpressionBody(Expression source, Expression? destination, CompileArgument arg)
{
var srcType = arg.SourceType;
var destType = arg.DestinationType;

if (destination != null && srcType == typeof(object)) // Infinity Loop Breaker When Update use real instanse of Object _Object.Adapt(_TDestination);
return destination;

return base.CreateExpressionBody(source, destination, arg);
}
}
}
46 changes: 28 additions & 18 deletions src/Mapster/TypeAdapter.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Reflection;
using System.Security.AccessControl;

namespace Mapster
{
Expand Down Expand Up @@ -93,28 +94,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)
{
if (typeof(TSource) == typeof(object) || typeof(TDestination) == typeof(object))
{
var sourceType = source.GetType();
var destinationType = destination.GetType();

var 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);
}
}
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 d7c73e3

Please sign in to comment.