Mapo 1.1.1
dotnet add package Mapo --version 1.1.1
NuGet\Install-Package Mapo -Version 1.1.1
<PackageReference Include="Mapo" Version="1.1.1" />
<PackageVersion Include="Mapo" Version="1.1.1" />
<PackageReference Include="Mapo" />
paket add Mapo --version 1.1.1
#r "nuget: Mapo, 1.1.1"
#:package Mapo@1.1.1
#addin nuget:?package=Mapo&version=1.1.1
#tool nuget:?package=Mapo&version=1.1.1
Mapo
High-performance, compile-time object mapping for .NET.
Mapo is a Roslyn source generator that writes your mapping code at build time. You get the fluent API of AutoMapper with the runtime speed of hand-written C# — zero reflection, zero allocation overhead, NativeAOT-ready out of the box.
using Mapo.Attributes;
[Mapper]
public partial class UserMapper
{
public partial UserDto Map(User user);
static void Configure(IMapConfig<User, UserDto> config)
{
config.Map(d => d.FullName, s => s.FirstName + " " + s.LastName);
// AddressCity is auto-resolved from Address.City via intelligent flattening
}
}
That's it. Mapo generates a complete, null-safe, inlineable implementation at compile time.
Why Mapo?
- Zero overhead. Generated code allocates identically to hand-written code. No reflection. No expression tree compilation. No hidden dictionaries.
- Compile-time safety. Unmapped properties are caught as warnings (or errors in strict mode) before your code ever runs.
- Refactoring-safe. Lambda-based configuration means IDE renames propagate automatically — no magic strings.
- NativeAOT-ready. No
System.Reflection.Emit, no dynamic code generation. Works withdotnet publish -r linux-x64 --self-contained /p:PublishAot=true. - Familiar API. If you've used AutoMapper, you already know
Map(),Ignore(), andAddConverter().
Benchmarks
Measured with BenchmarkDotNet on .NET 10 mapping 10,000 complex orders with nested objects, collections, computed fields, and enum conversions:
| Method | Mean | Ratio | Allocated | Alloc Ratio |
|---|---|---|---|---|
| Mapo | 1,310 us | 0.99 | 3,898.74 KB | 1.00 |
| Mapperly | 1,323 us | 0.99 | 3,898.74 KB | 1.00 |
| Manual | 1,332 us | 1.00 | 3,898.74 KB | 1.00 |
| Mapster | 3,551 us | 2.67 | 4,914.43 KB | 1.26 |
| AutoMapper | 5,270 us | 3.96 | 6,420.91 KB | 1.65 |
Mapo generates code that is indistinguishable from hand-written C# — identical allocations and identical speed. See Benchmark Details.
Installation
dotnet add package Mapo
Requirements: .NET 6+ (or any runtime supporting netstandard2.0) with Roslyn 4.8+ (ships with .NET SDK 8+).
The NuGet package includes both the public API (Mapo.Attributes) and the source generator (Mapo.Generator). No extra configuration needed.
Quick Start
Step 1: Define your types
public class Product
{
public string SKU { get; set; } = "";
public string Name { get; set; } = "";
public decimal Price { get; set; }
public Category? Category { get; set; }
}
public record ProductDto(string SKU, string Name, string PriceDisplay, string CategoryName);
Step 2: Create a mapper
using Mapo.Attributes;
[Mapper(StrictMode = true)]
public partial class ProductMapper
{
public partial ProductDto Map(Product product);
static void Configure(IMapConfig<Product, ProductDto> config)
{
config.Map(d => d.PriceDisplay, s => s.Price.ToString("C"))
.Map(d => d.CategoryName, s => s.Category.Name);
}
}
Step 3: Use it
var mapper = new ProductMapper();
var dto = mapper.Map(product);
The generated code handles null-safety (Category?.Name ?? default), selects the best constructor, and uses [MethodImpl(AggressiveInlining)] for optimal JIT behavior.
Features
| Feature | Description |
|---|---|
| Basic Mapping | Auto-match properties by name (case-insensitive), classes and records |
| Flattening | Address.City auto-maps to AddressCity — recursive up to 4 levels |
| Property Renaming | [MapFrom("SourceName")] attribute for simple renames without Configure |
| Custom Mappings | Strongly-typed lambda expressions via IMapConfig<S,T> |
| Collections | List<T>, T[], IEnumerable<T> with devirtualized for loops |
| Enum Mapping | Enum-to-enum switch, enum-to-string .ToString(), string-to-enum Enum.Parse |
| Nullable Handling | string?→string (null-forgiving), MyClass? (null-conditional), List<T>? (empty list), int?→int (?? default) |
| Records & Constructors | Full support for immutable types, primary constructors, init-only, required |
| Update Mapping | Mutate existing objects with void mapping methods |
| Dependency Injection | Constructor-inject services, use them in Configure lambdas |
| Polymorphic Dispatch | [MapDerived] for inheritance hierarchies |
| Circular References | UseReferenceTracking prevents stack overflow in object graphs |
| Global Converters | AddConverter<TIn, TOut>() applies to all matching properties |
| Reverse Mapping | .ReverseMap() generates bidirectional mappers |
| Async Streaming | Auto-generated IAsyncEnumerable<T> extensions for EF Core |
| Strict Mode | Compile-time errors for unmapped properties |
| IDE Quick Fixes | Ctrl+. to auto-fix unmapped properties and non-partial classes |
Documentation
| Document | Description |
|---|---|
| Usage Guide | Complete reference with examples for every feature |
| Architecture | Internal design: parse, analyze, emit pipeline |
| Benchmarks | Detailed performance methodology and results |
| Comparison | Mapo vs AutoMapper, Mapperly, and Mapster |
| CLI Tool | Standalone code generation CLI |
| Changelog | Release history |
CLI Tool
For use outside the normal build pipeline (scripts, non-MSBuild toolchains, code inspection):
dotnet tool install --global Mapo.Cli
mapo gen src/ Generated/
This scans C# files for [Mapper] classes and writes generated .g.cs files. The output is identical to what the source generator produces during dotnet build. See CLI Documentation for details.
Repository Structure
src/
Mapo.Attributes/ Public API: [Mapper], [MapFrom], IMapConfig<S,T>, [MapDerived]
Mapo.Generator/ Roslyn incremental source generator
Mapo.Generator.CodeFixes/ IDE code fix provider for MAPO001 + MAPO003
tests/
Mapo.Generator.Tests/ Unit tests (Roslyn compilation testing)
Mapo.IntegrationTests/ Integration tests (runtime verification)
samples/
Mapo.Sample/ Full e-commerce scenario
Mapo.Benchmarks/ Performance comparison vs AutoMapper, Mapperly, Mapster
Mapo.Circular/ Circular reference tracking demo
Mapo.Polymorphic/ Polymorphic dispatch demo
Mapo.Aot/ NativeAOT compilation verification
Contributing
- Fork the repository
- Create a feature branch from
dev - Make your changes
- Run the full test suite:
dotnet test tests/Mapo.Generator.Tests/ --configuration Release dotnet test tests/Mapo.IntegrationTests/ --configuration Release - Open a pull request against
main
Please ensure all existing tests pass and add tests for new functionality.
License
MIT
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- 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.