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

  1. MappingGenerator goes though destination type and builds list of properties that are mapping candidates.

  2. Non writable properties that are not collections removed from candidates.

  3. If custom constructor have been provided MappingGenerator will use it.

  4. Otherwise MappingGenerator ties to find destination type constructor with the most parameters that can be called with mappings from source.

  5. Init only properties are mapped.

  6. Remaining properties are mapped.

  7. 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:

  1. Custom mapping methods.

  2. User defined fields/properties of anchor class of type IMapper.

  3. Internal mappers (generated mappers that are generated within same anchor class).

  4. External mappers (generated mappers in other anchor classes)

  5. 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 Mapper implementing IMapper<Source, Destination> interface.

  • Implicit implementation for IMapper<Source, Destination>.Map method.

  • CreateDestination method 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 private members).

  • 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 string to int).

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.