Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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);
Copy link
Contributor Author

@DocSvartz DocSvartz Jan 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Base.Adapt(Derived) case

But this behavior is completely consistent with the access that the IActivityData interface itself provides - it does not have access to the Data property. If you add it, the state transfer will be carried out


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

}
}
Loading