Introduction
Anchor classes
To emit mappings MappingGenerator needs “anchor” class, i.e. user defined class that can be extended by generated code.
Any class marked with MappingGeneratorAttribute considered anchor for mappers defined by this attribute. For example class:
[MappingGenerator(typeof(Source), typeof(Destination))]
public class Mapper
{}
Will be “extended” to contain mapping logic from Source to Destination.
On compilation stage, for each anchor class MappingGenerator will create corresponding partial class containing mapping logic. For example, for anchor class above MappingGenerator will create:
partial class Mapper : IMapper<Source, Destination>
{
...
public Destination Map(Source source)
{
...
}
...
}
Anchor classes have the following requirements:
Anchor class needs to be
partial.Anchor class can’t be nested class.
Anchor class can’t be
static.
Anchor class may:
Contain other fields/properties/methods.
Have any access modifiers.
Have constructors (for more information see Nested Mappings section).
Have nested classes.
Be anchor for one or more mappers (form more information see Multiple Mappers section).
How it works
MappingGenerator goes though destination type and builds list of properties that are mapping candidates.
Non writable properties that are not collections removed from candidates.
If custom constructor have been provided MappingGenerator will use it.
Otherwise MappingGenerator ties to find destination type constructor with the most parameters that can be called with mappings from source.
Init only properties are mapped.
Remaining properties are mapped.
If destination has unmapped properties MappingGenerator produces error, or warning according to configuration.
The matching performed in the following way:
Constructor parameters are matched by name (case insensitive).
Properties are matched by name (case sensitive).
Implicit, explicit or custom type conversion should exist between source and destination.
Note. If match is found, destination property is removed from candidates list (e.g. if MappingGenerator matched constructor argument someValue it will not map property SomeValue since it considers them the same).
Mapping strategies are applied in the following order:
User defined fields/properties of anchor class of type
IMapper.Internal mappers (generated mappers that are generated within same anchor class).
External mappers (generated mappers in other anchor classes)
Source type properties.
Note. If strategy produced mapping resolution process stops.
What is generated
In general for:
[MappingGenerator(typeof(Source), typeof(Destination))]
public partial class Mapper
{}
By default MappingGenerator generates the following:
Partial class
MapperimplementingIMapper<Source, Destination>interface.Implicit implementation for
IMapper<Source, Destination>.Mapmethod.CreateDestinationmethod to construct Destination.Partial
AfterMap(Source, ref Destination)method.Private fields for other mappers current mapper depends on.
Constructor to initialize these fields.
Limitations
MappingGenerator can’t access members of source and destination objects if they are not accessible from anchor class (e.g. no access to
privatemembers).For source property to be considered for mapping there should exist type conversion (implicit or explicit) to destination property type (e.g. can’t assign
stringtoint).
The most important thing
Code generated by MappingGenerator must be valid and compilable code. For example:
[MappingGenerator(typeof(A<>), typeof(B<>))]
public partial Mapper<TA, TB>
{}
Will fail because at compile time there is no known conversion from generic TA to generic TB. In this cases you can help MappingGenerator by providing custom type converter.