riok / mapperly

A .NET source generator for generating object mappings. No runtime reflection.
https://mapperly.riok.app
Apache License 2.0
2.52k stars 138 forks source link

Include mapping configuration #513

Open latonz opened 1 year ago

latonz commented 1 year ago

Introduce two new attributes to include the mapping configuration of another mapper / mapping method. Each mapping configuration is identified by a name which is by default the name of the method, but can be overwritten by NamedMappingAttribute, eg. [NamedMapping("myName")]. A mapping configuration can be applied to the current mapping method by applying IncludeMappingConfigurationAttribute: [IncludeMappingConfiguration("myName")] / [IncludeMappingConfiguration(nameof(OtherMappingMethod))]. If an IncludeMappingConfigurationAttribute references an ambiguous mapping configuration, a diagnostic should be emitted.

Proposed API:

[AttributeUsage(AttributeTargets.Method)]
public class IncludeMappingConfigurationAttribute : Attribute
{
    public IncludeMappingConfigurationAttribute(string name);
}

[AttributeUsage(AttributeTargets.Method)]
public class NamedMappingAttribute : Attribute
{
    public NamedMappingAttribute(string name);
}

Usage:

class Fruit { public string Name { get; set; } public decimal PricePerUnit { get; set; } }
class FruitDto { public string Title { get; set; } }

class Apple : Fruit { public int Weight { get; set; } }
class AppleDto : FruitDto { public int Weight { get; set; } }

[Mapper]
public partial static class MyMapper
{
    [MapProperty(nameof(Fruit.Name), nameof(FruitDto.Title))]
    [MapperIgnoreSource(nameof(Fruit.PricePerUnit))]
    private partial FruitDto ToFruit(Fruit fruit);

    [IncludeMappingConfiguration(nameof(ToFruit))]
    public partial static AppleDto Map(Apple apple);
}
mutzl commented 1 year ago

What if the (named) mapping configuration is defined in another (different) Mapping class? (Happens a lot in my projects.)

Will/should it work anyway?

latonz commented 1 year ago

@mutzl it will work as long as it is in the same project and via explicit name. We could probably also add a constructor overload to include the mapper type and generate the name based on the name of the mapper + the name of the mapping method.

nicholass-alcidion commented 5 months ago

Being able to reuse mappings from a base type would be critical for a number of usecases we have

latonz commented 2 months ago

This should also work for reverse mappings with an additional property bool Reverse and on existing target instance mappings.

dotnetshadow commented 1 month ago

What is the current guidance to work around this issue since the attribute isn't available. Would you advise passing in the mapper as a property to other mappers?

For the example public partial static AppleDto Map(Apple apple); currently nothing would be automatically mapped since Mapperly doesn't know that a mapper exists for this is that correct?