Skip to content

Commit

Permalink
Merge pull request #758 from DocSvartz/fix-interfaces-map-regression
Browse files Browse the repository at this point in the history
 Fix issue #755 - revert to behavior from 7.4.0 and new features
  • Loading branch information
andrerav authored Jan 13, 2025
2 parents 44b078c + b9d403f commit 155a723
Show file tree
Hide file tree
Showing 2 changed files with 204 additions and 1 deletion.
184 changes: 184 additions & 0 deletions src/Mapster.Tests/WhenMappingRecordRegression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,83 @@ public void MultiCtorAndInlineRecordWorked()
}


[TestMethod]
public void MappingInterfaceToInterface()
{
TypeAdapterConfig<IActivityData, IActivityDataExtentions>
.ForType()
.Map(dest => dest.TempLength, src => src.Temp.Length);


var sourceBase = new SampleInterfaceClsBase
{
ActivityData = new SampleActivityData
{
Data = new SampleActivityParsedData
{
Steps = new List<string> { "A", "B", "C" }
},
Temp = "Temp data"

}

};
var sourceDerived = new SampleInterfaceClsDerived
{
ActivityData = new SampleActivityData
{
Data = new SampleActivityParsedData
{
Steps = new List<string> { "X", "Y", "Z" }
},
Temp = "Update Temp data"

}

};

var sourceExt = new SampleInterfaceClsExtentions
{
ActivityData = new SampleActivityDataExtentions
{
Data = new SampleActivityParsedData
{
Steps = new List<string> { "o", "o", "o" }
},
Temp = "Extentions data",
TempLength = "Extentions data".Length

}

};

var TargetBase = sourceBase.Adapt<SampleInterfaceClsBase>();
var targetDerived = sourceDerived.Adapt<SampleInterfaceClsDerived>();
var update = targetDerived.Adapt(TargetBase);

var targetExtention = sourceExt.Adapt<SampleInterfaceClsExtentions>();


var updExt = targetDerived.Adapt(targetExtention);

targetDerived.ShouldNotBeNull();
targetDerived.ShouldSatisfyAllConditions(
() => targetDerived.ActivityData.ShouldBe(sourceDerived.ActivityData),
() => update.ActivityData.ShouldBe(targetDerived.ActivityData),

()=> updExt.ActivityData.ShouldBe(targetExtention.ActivityData),
() => ((SampleActivityDataExtentions)updExt.ActivityData).Temp.ShouldBe(sourceDerived.ActivityData.Temp),
() => ((SampleActivityDataExtentions)updExt.ActivityData).TempLength.ShouldBe(sourceDerived.ActivityData.Temp.Length),
// IActivityData interface and all its derivatives do not provide access to the Data property for all implementations of the SampleActivityData class,
// so this property will not be changed by mapping
() => ((SampleActivityDataExtentions)updExt.ActivityData).Data.ShouldBe(((SampleActivityDataExtentions)targetExtention.ActivityData).Data)

);

}



#region NowNotWorking

/// <summary>
Expand Down Expand Up @@ -305,6 +382,104 @@ public void CollectionUpdate()

#region TestClasses

public interface IActivityDataExtentions : IActivityData
{
public int TempLength { get; set; }
}

public interface IActivityData : IActivityDataBase
{
public string Temp { get; set; }
}

public interface IActivityDataBase
{

}


public class SampleInterfaceClsExtentions
{
public IActivityDataExtentions? ActivityData { get; set; }

public SampleInterfaceClsExtentions()
{

}

public SampleInterfaceClsExtentions(IActivityDataExtentions data)
{
SetActivityData(data);
}

public void SetActivityData(IActivityDataExtentions data)
{
ActivityData = data;
}
}



public class SampleInterfaceClsBase
{
public IActivityDataBase? ActivityData { get; set; }

public SampleInterfaceClsBase()
{

}

public SampleInterfaceClsBase(IActivityDataBase data)
{
SetActivityData(data);
}

public void SetActivityData(IActivityDataBase data)
{
ActivityData = data;
}
}

public class SampleInterfaceClsDerived
{
public IActivityData? ActivityData { get; set; }

public SampleInterfaceClsDerived()
{

}

public SampleInterfaceClsDerived(IActivityData data)
{
SetActivityData(data);
}

public void SetActivityData(IActivityData data)
{
ActivityData = data;
}
}

public class SampleActivityDataExtentions : IActivityDataExtentions
{
public SampleActivityParsedData Data { get; set; }
public string Temp { get; set; }
public int TempLength { get; set; }
}

public class SampleActivityData : IActivityData
{
public SampleActivityParsedData Data { get; set; }
public string Temp { get; set; }
}

public class SampleActivityParsedData
{
public List<string> Steps { get; set; } = new List<string>();
}



class MultiCtorAndInlinePoco
{
public int MyInt { get; set; }
Expand Down Expand Up @@ -499,5 +674,14 @@ sealed record TestSealedRecord()

sealed record TestSealedRecordPositional(int X);










#endregion TestClasses
}
21 changes: 20 additions & 1 deletion src/Mapster/Adapters/ReadOnlyInterfaceAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ internal class ReadOnlyInterfaceAdapter : ClassAdapter

protected override bool CanMap(PreCompileArgument arg)
{
return arg.DestinationType.IsInterface && arg.DestinationType.GetProperties().Length > 0;
return arg.DestinationType.IsInterface;
}

protected override bool CanInline(Expression source, Expression? destination, CompileArgument arg)
Expand Down Expand Up @@ -45,5 +45,24 @@ protected override Expression CreateInstantiationExpression(Expression source, E
return base.CreateInstantiationExpression(source,destination, arg);
}

protected override Expression CreateExpressionBody(Expression source, Expression? destination, CompileArgument arg)
{
if (source.Type.IsInterface)
{
if (!arg.DestinationType.IsAssignableFrom(arg.SourceType))
return base.CreateExpressionBody(source, destination, arg);

if (arg.MapType != MapType.MapToTarget)
return Expression.Convert(source, arg.DestinationType);

if (arg.MapType == MapType.MapToTarget)
return source;

return base.CreateExpressionBody(source, destination, arg);
}

return base.CreateExpressionBody(source, destination, arg);
}

}
}

0 comments on commit 155a723

Please sign in to comment.