Mapster icon indicating copy to clipboard operation
Mapster copied to clipboard

Ignore on base class mapper ignores on inherited class mapper

Open thomas-hockings-cs opened this issue 2 years ago • 2 comments

I've noticed what I consider to be an issue with Mapster and can't see another issue related to this. It may also be a lack of understanding on my part. So apologies if either of those are the case!

The issue is that when you have a mapper for a base class to a mapped class and a mapper for a class that inherits from that base class to the same mapped class, then ignores on base -> mapped also ignore on inherited -> mapped. Code to reproduce is given below. I can change the base class mapper to map to the default value instead of using .Ignore and it works as I would expect it to. I realise that I could probably set RequireDestinationMemberSource to false but in the project where I originally discovered this issue we want to have RequireDestinationMemberSource = true.

My expectation would be that I could ignore something in the mapper for the base class but have some code to map that field for the inherited class.

In the relevant project I've modified the base class mapper to map to default values for fields that will be mapped in the derived class but I would prefer to use .Ignore. Is this an issue or is there something else I can use in Mapster to achieve the required effect? I've scanned through the documentation and can't find any solution to this that works for me.

Code to reproduce the issue

// Program.cs
using Mapster;

TypeAdapterConfig.GlobalSettings
    .NewConfig<BaseClass, MappedClass>()
    .Map(dest => dest.Base, src => src.Base)
    .Ignore(dest => dest.Inherited!);
        
TypeAdapterConfig.GlobalSettings
    .NewConfig<InheritedClass, MappedClass>()
    .Map(dest => dest.Base, src => src.Base)
    .Map(dest => dest.Inherited, src => src.Inherited);
  
var inheritedMapped = new InheritedClass
{
    Base = "base",
    Inherited = "inherited"
}.Adapt<MappedClass>();
        
Console.WriteLine("inherited class: {0}", inheritedMapped.Inherited); 
// output: inherited class:
// expected output: inherited class: inherited

internal class BaseClass
{
    public string? Base { get; set; }
}

internal class InheritedClass : BaseClass
{
    public string? Inherited { get; set; }
}

internal class MappedClass
{
    public string? Base { get; set; }
        
    public string? Inherited { get; set; }
}

thomas-hockings-cs avatar Aug 16 '23 12:08 thomas-hockings-cs

Hello @thomas-hockings-cs

I don't quite understand what exactly you want to get? In your example, the Base class does not contain the Inherited field When converting the Base Class to the MappedClass, nothing will be transferred anyway.

.Ignore(dest => dest.Inherited!); With this directive you prohibit the MappedClass from mapping anything to this field Inherited for your class hierarchy.(it real strange 🤔)

*Update

With this directive you prohibit the MappedClass from mapping anything to this field Inherited for your class hierarchy.(it real strange 🤔)

This is the default behavior You must use TypeAdapterConfig.GlobalSettings.AllowImplicitDestinationInheritance = false; but then you will lose the entire mapping configuration from the base class

DocSvartz avatar Oct 17 '23 11:10 DocSvartz

Perhaps you wanted this result?

 [TestMethod]
 public void IgnogbaseClass()
 {
     TypeAdapterConfig.GlobalSettings
     .NewConfig<BaseClass621, MappedClass621>()
     .Map(dest => dest.Base, src => src.Base)
     .Map(dest=> dest.Inherited, src=> src.Inherited, src=> src.GetType() != typeof(BaseClass621))
     .IgnoreNullValues(true);;

     var _BaseClass = new BaseClass621 { Base = "Me", Inherited = "Hello" };


     var _TestBaseClassAdapt = _BaseClass.Adapt<MappedClass621>(); // { Base = "Me", Inherited = null }


     var inheritedMapped = new InheritedClass621 // { Base = "base", Inherited = "inherited" }
     {
         Base = "base",
         Inherited = "inherited"
     }.Adapt<MappedClass621>();

  var MappedClassToUpdate = new MappedClass621() { Base = "Update", Inherited = "Update" };

  var _NoUpdate = _BaseClass.Adapt(MappedClassToUpdate);  // { Base = "Me", Inherited = Update }; //  it work with .IgnoreNullValues(true);

 }
    internal class BaseClass621
    {
        public string? Base { get; set; }

        public string? Inherited { get; set; }
    }

    internal class InheritedClass621 : BaseClass621
    {
       
    }

    internal class MappedClass621
    {
        public string? Base { get; set; }

        public string? Inherited { get; set; }
    }

DocSvartz avatar Oct 17 '23 11:10 DocSvartz