Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
jiuzhou2019 opened this issue Nov 25, 2024 · 5 comments
Assignees

Comments

@jiuzhou2019
Copy link

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
Copy link
Author

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

@DocSvartz
Copy link

DocSvartz commented Jan 25, 2025

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
Copy link

DocSvartz commented Jan 30, 2025

@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
Copy link

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

@DocSvartz
Copy link

@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 
        };
............
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants