Mapster icon indicating copy to clipboard operation
Mapster copied to clipboard

Configure a mapper from string to List<string> and from List<string> to string

Open ascariz opened this issue 3 years ago • 5 comments

I am trying to configure Napster of these two entities to pass from List to string but it gives me an error. any ideas. Thank you

public class  EntidadVM 
     { public List<string> CCC}

public class  EntidadDto 
     { public string CCC}

I'm doing them like this, but it gives me an error

TypeAdapterConfig<MailingDto, MailingVM>.NewConfig()
 .Map(dest => dest.CCC, src => new List<string>(src.CCC.Split(',')).ToList() );

TypeAdapterConfig<MailingDto, MailingVM>.NewConfig()
 .Map(dest => dest.CCC, src => src.CCC.Split(',').ToList() );

ascariz avatar Jun 02 '22 09:06 ascariz

@ascariz

[TestMethod]
public void MapToTarget()
{
    var dto = new EntidadDto { CCC = "one,two,three", };

    // expression tree cannot contain call which contains optional arguments, so specify explicitly
    var config = TypeAdapterConfig<EntidadDto, EntidadVM>.NewConfig()
        .Map(dest => dest.CCC, src => new List<string>(src.CCC.Split(',', StringSplitOptions.None)).ToList());
    var vm = dto.Adapt<EntidadVM>(config.Config);
    vm.CCC.ShouldBe(new[] { "one", "two", "three" });

    config = TypeAdapterConfig<EntidadDto, EntidadVM>.NewConfig()
        .Map(dest => dest.CCC, src => src.CCC.Split(',', StringSplitOptions.None).ToList());
    vm = dto.Adapt<EntidadVM>(config.Config);
    vm.CCC.ShouldBe(new[] { "one", "two", "three" });

    // or use after mapping
    config = TypeAdapterConfig<EntidadDto, EntidadVM>.NewConfig()
        .Ignore(x => x.CCC)
        .AfterMapping((src, dest) => dest.CCC = src.CCC.Split(',').ToList());
    vm = dto.Adapt<EntidadVM>(config.Config);
    vm.CCC.ShouldBe(new[] { "one", "two", "three" });

    config = TypeAdapterConfig<EntidadDto, EntidadVM>.NewConfig()
        .Ignore(x => x.CCC)
        .AfterMapping((src, dest) => dest.CCC = new List<string>(src.CCC.Split(',')).ToList());
    vm = dto.Adapt<EntidadVM>(config.Config);
    vm.CCC.ShouldBe(new[] { "one", "two", "three" });
}

devbased avatar Jun 02 '22 19:06 devbased

And is it possible to map from List<string> to string? (The idea being, converting a list of strings to a string that contains each item separated by a comma.)

With this configuration:

TypeAdapterConfig<List<string>, string>
    .NewConfig()
    .Map(dest => dest, src => string.Join(", ", src));

When running this:

var list = new List<string> {"one", "two", "three"};
var result = list.Adapt<string>();

Then result contains System.Collections.Generic.List`1[System.String], instead of the expected "one, two, three".

According to the documentation:

When Mapster maps other types to string, Mapster will use ToString method

And that's what's happening.

Is it possible to override that behavior or do you recommend using something like an extension method on the List<string> type in this particular case?

ignacioerrico avatar Jul 02 '23 16:07 ignacioerrico

@ignacioerrico In the documentation, it is mentioned that you need to use MapWith. Please refer to: https://github.com/MapsterMapper/Mapster/wiki/Custom-conversion-logic For more complex situations, you can always resort to building a LambdaExpression

E.g.

var c = x.When(argument => argument.DestinationType == typeof(string) && argument.SourceType == typeof(List<string>));

c.Settings.ConverterFactory = argument =>
{
    var input = Expression.Parameter(typeof(List<string>), "list");

    var joinMethod = typeof(string).GetMethod("Join", new[] { typeof(string), typeof(IEnumerable<string>) })
        ?? throw new InvalidOperationException("Method 'Join' not found.");

    var delimiter = Expression.Constant(",", typeof(string));

    var call = Expression.Call(joinMethod, delimiter, input);

    var lambda = Expression.Lambda<Func<List<string>, string>>(call, input);

    return lambda;
};

devbased avatar Jul 02 '23 20:07 devbased

Thanks a lot for your prompt reply, @devbased. You may close this issue, since both directions have been covered (mapping from List<string> to string and vice versa).

ignacioerrico avatar Jul 02 '23 21:07 ignacioerrico

@ignacioerrico I don't have the right to manage the issue 😅 It just turned out that I'm subscribed to this topic, so I quickly replied to you 😊

devbased avatar Jul 02 '23 22:07 devbased