Inheritance mapping with null source
Hello
I am experiencing an error with an edge-case of inheritance mapping.
When mapping between two abstract classes, Mapster cannot handle when the source-object is null.
An example of this can be seen with the following code
using Mapster;
public class Program
{
public abstract class DomainBase {}
public abstract class DtoBase {}
public class DomainDerived : DomainBase
{
public int Number { get; set; }
}
public class DtoDerived : DtoBase
{
public int Number { get; set; }
}
public static void Main(string[] args)
{
TypeAdapterConfig.GlobalSettings.NewConfig<DomainBase, DtoBase>()
.TwoWays()
.Include<DomainDerived, DtoDerived>();
DtoBase dto = null;
DomainBase mapped = dto.Adapt<DtoBase, DomainBase>();
}
}
where Mapster will complain that instantiating DomainBase is not possible.
Using ExpressionDebugger to show the mapping logic, i can see why this is a problem - see generated script below.
public Program.DomainBase Main(Program.DtoBase p1)
{
Program.DtoDerived p2 = p1 as Program.DtoDerived;
if (p2 != null)
{
return p2 == null ? null : new Program.DomainDerived() {Number = p2.Number};
}
throw new InvalidOperationException("Cannot instantiate type: DomainBase");
}
Is this intended behavior or a small bug? To me it seems that returning null could be a sane solution - but maybe some more logic is needed.
If anyone knows a workaround or something of the sorts, advice is appreciated. It should be avoidable with null-checks but that gets ugly fast.
Thank you for maintaining this project!
It is not clear what do you want to do in the first place. Add a use case, please.
Make DomainBase not abstarct if you want to adapt from DerivedDto to DomainBase, like:
DomainBase mapped = dto.Adapt<DtoDerived, DomainBase>();
or you can do
DomainBase mapped = dto.Adapt<DtoDerived, DomainDerived>();
I am not sure that passing null to adapt as a source is a Mapster problem.
Thank you for the reply. I will try to elaborate my use case as well as i can.
Essentially i have two abstract classes (one domain and one dto) like in the example, but they both have several inheritors. They are used in a method that takes an object of (my equivalent of) DtoBase and returns a type that contains several others, one of them being DomainBase. For this reason, i cannot just make any of the classes concrete.
Regarding whether it is a Mapster problem to handle null source objects, this is indeed some of what my original question tries to understand. However, it seems that this is handled fine in other cases e.g. when mapping directly between two concrete classes.
When using the following syntax, "mapped" is just null.
DtoBase dto = null;
var mapped = dto.Adapt<DomainBase>();
but that produces an exception on runtime if dto is an actual instance of a subclass. Experiencing that led me to read the docs where i found out about the syntax that gives two type arguments to Adapt, which works fine in all cases except for when source is null.
I hope that this make it more clear.
DtoBase dto = null; var mapped = dto.Adapt<DomainBase>();
but that produces an exception on runtime if dto is an actual instance of a subclass. Experiencing that led me to read the docs where i found out about the syntax that gives two type arguments to Adapt, which works fine in all cases except for when source is null. I hope that this make it more clear.
I think that is a bad design. Although it is perfectly fine to call extention methods on null references in C# you should never do that just for cross-language compatibility. If your business logic implies that there are nulls then handle them in your code.
In order to identify issues that are still active, we are closing issues that we believe are either resolved or are dormant. If your issue is still active then please reopen. Thanks.