User-implemented mapping methods
If Mapperly cannot generate a mapping, one can implement it manually simply by providing a method body in the mapper declaration:
[Mapper]
public partial class CarMapper
{
public partial CarDto CarToCarDto(Car car);
private int TimeSpanToHours(TimeSpan t) => t.Hours;
}
Whenever Mapperly needs a mapping from TimeSpan
to int
inside the CarMapper
implementation, it will use the provided implementation.
The types of the user-implemented mapping method need to match the types to map exactly, including nullability.
If there are multiple user-implemented mapping methods suiting the given type-pair, by default, the first one is used. This can be customized by using automatic user-implemented mapping method discovery and default mapping method.
Automatic user-implemented mapping method discovery
By default, user implemented mapping methods are discovered automatically.
This can be disabled by setting AutoUserMappings
to false
.
With AutoUserMappings
disabled, only methods marked by the UserMappingAttribute
are discovered by Mapperly.
[Mapper(AutoUserMappings = false)]
public partial class CarMapper
{
public partial CarDto CarToCarDto(Car car);
// mark as user-implemented mapping
[UserMapping]
private int TimeSpanToHours(TimeSpan t) => t.Hours;
private int IgnoredTimeSpanToHours(TimeSpan t) => t.Minutes / 60;
}
The AutoUserMappings
value also applies to the usage of external mappers:
With AutoUserMappings
enabled all methods with a mapping method signature are discovered.
With AutoUserMappings
disabled, only methods with a UserMappingAttribute
and,
if the containing class has a MapperAttribute
, partial methods are discovered.
Ignoring a user-implemented mapping method
To ignore a user-implemented mapping method with enabled AutoUserMappings
,
[UserMapping(Ignore = true)]
can be applied.
[Mapper]
public partial class CarMapper
{
public partial CarDto CarToCarDto(Car car);
// discovered and used by default (AutoUserMappings is true by default)
private int TimeSpanToHours(TimeSpan t) => t.Hours;
// ignored user-implemented mapping
[UserMapping(Ignore = true)]
private int IgnoredTimeSpanToHours(TimeSpan t) => t.Minutes / 60;
}
Default mapping methods
Whenever Mapperly will need a mapping for a given type-pair,
it will use the default mapping.
A user-implemented or user-defined mapping is considered the default mapping for a type-pair
if Default = true
is set on the UserMapping
attribute.
If no user-implemented mapping with Default = true
exists and AutoUserMappings
is enabled,
the first user-implemented mapping which has an unspecified Default
value is used.
For each type-pair only one default mapping can exist.
If multiple mappings exist for the same type-pair without a default mapping, RMG060
is reported.
By default RMG060
has a severity of warning,
which can be changed using the .editorconfig
.
Map properties using user-implemented mappings
See user-implemented property conversions.
Use external mappings
Mapperly can also consider mappings implemented in other classes.
In order for Mapperly to find the mappings, they must be made known with UseMapper
/ UseStaticMapper
.
- Static
- Instance
For static mappings, UseStaticMapper
can be used:
[Mapper]
[UseStaticMapper(typeof(BananaMapper))]
public static partial class BoxMapper
{
public static partial BananaBox MapBananaBox(BananaBoxDto dto);
}
public static class BananaMapper
{
public static Banana MapBanana(BananaDto dto)
=> new Banana(dto.Weigth);
}
To use the mappings of an object instance UseMapper
can be used:
[Mapper]
public static partial class BoxMapper
{
[UseMapper]
private readonly BananaMapper _bananaMapper = new();
public static partial BananaBox MapBananaBox(BananaBoxDto dto);
}
public static class BananaMapper
{
public static Banana MapBanana(BananaDto dto)
=> new Banana(dto.Weigth);
}
The initialization of fields and properties annotated with UseMapper
needs to be done by the user.
Whenever Mapperly needs a mapping from BananaBox
to BananaBoxDto
inside the BoxMapper
implementation,
it will use the provided implementation by the BananaMapper
.
Used mappers themselves can be Mapperly backed classes.
The AutoUserMappings
value also applies to the usage of external mappers.