ConventionMapper.SourceGenerator
1.2.0
See the version list below for details.
dotnet add package ConventionMapper.SourceGenerator --version 1.2.0
NuGet\Install-Package ConventionMapper.SourceGenerator -Version 1.2.0
<PackageReference Include="ConventionMapper.SourceGenerator" Version="1.2.0"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
<PackageVersion Include="ConventionMapper.SourceGenerator" Version="1.2.0" />
<PackageReference Include="ConventionMapper.SourceGenerator"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
paket add ConventionMapper.SourceGenerator --version 1.2.0
#r "nuget: ConventionMapper.SourceGenerator, 1.2.0"
#:package ConventionMapper.SourceGenerator@1.2.0
#addin nuget:?package=ConventionMapper.SourceGenerator&version=1.2.0
#tool nuget:?package=ConventionMapper.SourceGenerator&version=1.2.0
ConventionMapper.SourceGenerator
Build-time object mapping. You declare partial mapping methods; the generator writes the implementation into your project when it compiles.
- No reflection at runtime. The output is plain C# assignments, loops and constructor calls.
- Native AOT and trimming safe. The package has no runtime dependency, not even on
ConventionMapper. - As fast as hand-written code. There is no configuration lookup, no boxing, no delegate per member.
- Debuggable. Step into the generated method like any other code (in Visual Studio: Go To Definition on the method, or look under Dependencies → Analyzers → ConventionMapper.SourceGenerator).
- Mistakes are build errors. An unmapped destination member fails the build (
CM0001) instead of showing up at runtime.
dotnet add package ConventionMapper.SourceGenerator
Requires the .NET 8 SDK or later (Visual Studio 2022 17.8+) and C# 9 or later. The generated code itself runs on every target framework, including .NET Framework and netstandard2.0.
Declaring a mapper
using ConventionMapper;
[GeneratedMapper]
public static partial class OrderMapper
{
// TDestination Map(TSource): creates a new object
public static partial OrderDto ToDto(this Order order);
// void Map(TSource, TTarget): updates an existing object
public static partial void Update(OrderDto source, Order target);
// collections, enums and other types work at the root too
public static partial List<OrderLineDto> ToDtos(IEnumerable<OrderLine> lines);
}
OrderDto dto = order.ToDto();
Mappers can be static or instance classes, nested inside other partial types, and methods can be extension methods. The attributes are added to your project by the generator and are removed from the compiled assembly.
What gets mapped
| Feature | Example |
|---|---|
| Same name (case-insensitive) | Name → Name |
| Flattening, null-safe | Customer.Address.City → CustomerAddressCity (source.Customer?.Address?.City) |
Get methods |
GetTotal() → Total |
| Constructors and records | record PersonDto(string FirstName, int Age), picking the constructor with the most parameters that can all be mapped |
init and required members |
set in the object initializer |
| Nested objects | a mapping method you declared for the pair is reused; otherwise a private helper is generated (recursive types work) |
| Collections | arrays, List<T>, IList<T>, ICollection<T>, IEnumerable<T>, IReadOnlyList<T>, IReadOnlyCollection<T>, HashSet<T>, ISet<T>, with indexed for loops and pre-sized lists when the source has a count |
| Dictionaries | Dictionary<K,V>, IDictionary<K,V>, IReadOnlyDictionary<K,V> (keys and values converted) |
| Enums | by name with a switch; [Flags] enums by value; enum ↔ string, enum ↔ integer |
| Numbers | implicit conversions directly, narrowing conversions in a checked(...) cast |
| Strings | ToString() from any scalar; T.Parse(s, CultureInfo.InvariantCulture) to any type with a Parse method |
| Nullable | int? ↔ int (GetValueOrDefault()), int? ↔ long? |
| Null collections | become empty collections |
Values of the same type are assigned as they are (reference types are not cloned).
Configuring members
[MapMember("Customer.Email", "ContactEmail")] // source path -> destination member (or constructor parameter)
[MapIgnore("InternalNotes")] // leave a destination member out
public static partial OrderDto ToDto(Order order);
Diagnostics
| Id | Severity | Meaning |
|---|---|---|
| CM0001 | Error | A destination member has no matching source member. Add [MapMember] or [MapIgnore]. |
| CM0002 | Error | A source member exists but its type cannot be converted to the destination type. |
| CM0003 | Info | A nullable source is mapped onto a non-nullable destination; null becomes the default value. |
| CM0004 | Error | The destination has no accessible constructor whose parameters can all be mapped. |
| CM0005 | Error | The mapper class (and every class containing it) must be partial. |
| CM0006 | Error | The method signature is not a supported mapping method. |
| CM0007 | Warning | A source enum value has no destination value with the same name; mapping it throws. |
| CM0008 | Warning | [MapMember] / [MapIgnore] names a member that does not exist. |
Severities can be changed in .editorconfig, for example dotnet_diagnostic.CM0003.severity = warning.
Source generator or runtime mapper?
Use the generator for hot paths, Native AOT, trimming and when you want compile-time guarantees. Use the runtime ConventionMapper package for ProjectTo (LINQ / EF Core), DI-resolved resolvers and converters, Patch, collection merging by key and other configuration-driven features. Both packages can be used in the same project.
Learn more about Target Frameworks and .NET Standard.
This package has no dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.