Mapster icon indicating copy to clipboard operation
Mapster copied to clipboard

When using TypeAdapterConfig.GlobalSettings.Default.IgnoreNullValues(true), it causes the Mapper function to be called twice.

Open jiuzhou2019 opened this issue 1 year ago • 5 comments

There is example code following this. When Adapt() is called, it can be seen from the console that SummaryDetail runs twice. I would like to ask what is the reason for this and how to avoid it. I have also uploaded the test code for the entire project in the attachment. Thank you all for helping me answer this.

Please attach the test code file, and I will take a look to provide further assistance.

TestMapster.zip

Program.cs:

TypeAdapterConfig.GlobalSettings.Default.IgnoreNullValues(true);
TypeAdapterConfig.GlobalSettings.Scan(Assembly.Load("TestMapster"));

TestInput.cs:

public class TestInput
{
    public string Summary { get; set; }
}

public class TestView
{
    public string Summary { get; set; }
}

MapperConfig.cs

public class MapperConfig : IRegister
{
    public void Register(TypeAdapterConfig config)
    {
        config.ForType<TestInput, TestView>()
       .Map(dest => dest.Summary, src => SummaryDetail(src.Summary))
       ;
    }

    private static string SummaryDetail(string s)
    {
        Console.WriteLine($"================{s}================");
        return s + " plus";
    }
}

Controller.cs

    [HttpGet]
    public TestView Get()
    {
        var input = new TestInput { Summary = "Hello World" };
        return input.Adapt<TestView>();
    }

jiuzhou2019 avatar Nov 25 '24 11:11 jiuzhou2019

The attachment did not upload successfully, I am re-uploading it here. TestMapster.zip

jiuzhou2019 avatar Nov 25 '24 11:11 jiuzhou2019

Hello @jiuzhou2019

This cannot be avoided. Without caching the function result. (But there will still be two calls. Only second call the result will be obtained from the cache) You case is equivalent to the following code:

If (src.Summary != null)  // 1 call getter of Property src.Summary
 Destination.Summary = src.Summary  // 2 call getter of Property src.Summary

Where getter of Property src.Summary == call of func SummaryDetail(src.Summary) as per your setting.

DocSvartz avatar Jan 25 '25 16:01 DocSvartz

@jiuzhou2019 @stagep @andrerav

upd: Behavior matches design

It seems I've also gone crazy )) This really shouldn't work in the case of Map Only when MapToTarget ? Then it is bug ......

DocSvartz avatar Jan 30 '25 14:01 DocSvartz

Hm, Current tests expect this behavior in the Map case. and this. Then this is behavior by Design. And everything really works correctly.

DocSvartz avatar Jan 31 '25 16:01 DocSvartz

@jiuzhou2019 @stagep @andrerav

Or was the problem meant to be that the function call is incorrectly defined as allowing a Null return value?

I didn't quite figure out what exactly is being checked there )) In Mapster can add detection Null attiribute

[return:NotNull]
private static string SummaryDetail(string s)
{
    Console.WriteLine($"================{s}================");
    return s + " plus";
}

behavior now


.Lambda #Lambda1<System.Func`2[Mapster.Tests.WhenMappingRecordRegression+TestInput,Mapster.Tests.WhenMappingRecordRegression+TestView]>(Mapster.Tests.WhenMappingRecordRegression+TestInput $var1)
{
  .....
        $result = .New Mapster.Tests.WhenMappingRecordRegression+TestView();
        .Block() {
            .If (.Call Mapster.Tests.WhenMappingRecordRegression.SummaryDetail($var1.Summary) != null)  // check for null  annotation not detected
           {
                $result.Summary = .Call Mapster.Tests.WhenMappingRecordRegression.SummaryDetail($var1.Summary)
            } .Else {
                .Default(System.Void)
            }
  .........
}

behavior after


.Lambda #Lambda1<System.Func`2[Mapster.Tests.WhenMappingRecordRegression+TestInput,Mapster.Tests.WhenMappingRecordRegression+TestView]>(Mapster.Tests.WhenMappingRecordRegression+TestInput $var1)
{
......
        };
        $result = .New Mapster.Tests.WhenMappingRecordRegression+TestView();
        .Block() {
            $result.Summary = .Call Mapster.Tests.WhenMappingRecordRegression.SummaryDetail($var1.Summary) // not check, annotation using 
        };
............
}

DocSvartz avatar Feb 04 '25 11:02 DocSvartz