![]() |
VOOZH | about |
dotnet add package ZeroAlloc.Mapping --version 1.6.0
NuGet\Install-Package ZeroAlloc.Mapping -Version 1.6.0
<PackageReference Include="ZeroAlloc.Mapping" Version="1.6.0" />
<PackageVersion Include="ZeroAlloc.Mapping" Version="1.6.0" />Directory.Packages.props
<PackageReference Include="ZeroAlloc.Mapping" />Project file
paket add ZeroAlloc.Mapping --version 1.6.0
#r "nuget: ZeroAlloc.Mapping, 1.6.0"
#:package ZeroAlloc.Mapping@1.6.0
#addin nuget:?package=ZeroAlloc.Mapping&version=1.6.0Install as a Cake Addin
#tool nuget:?package=ZeroAlloc.Mapping&version=1.6.0Install as a Cake Tool
👁 NuGet
👁 Build
👁 AOT
👁 GitHub Sponsors
ZeroAlloc.Mapping is a Roslyn source generator that emits strongly-typed Command→Domain→DTO mappers at compile time. No reflection. No expression trees. No runtime configuration. The success path runs with zero allocation beyond the destination instance itself, and the generated code is fully Native AOT compatible.
dotnet add package ZeroAlloc.Mapping
The generator runs automatically as part of dotnet build — there is no DI registration or runtime configuration.
using ZeroAlloc.Mapping;
// 1. Define source and destination
public sealed record OrderRequest(int Id, string Notes);
public sealed record Order(int Id, string Notes);
// 2. Declare the mapper — generator fills in the partial
[Map<OrderRequest, Order>]
public static partial class AppMappings { }
// 3. Use it
var order = AppMappings.Map(new OrderRequest(42, "rush"));
What the generator emits is a single direct constructor call — no intermediate buffer, no boxing, no closure:
public static Order Map(OrderRequest src)
=> new Order(Id: src.Id, Notes: src.Notes);
ZeroAlloc.Mapping matches Mapperly (the other source-generator mapper) on hot paths and is 2–18× faster than AutoMapper with allocation parity. Benchmarks below run on .NET 10.0.7, i9-12900HK, BenchmarkDotNet v0.15.8.
| Scenario | ZeroAlloc | Mapperly | AutoMapper | HandWritten |
|---|---|---|---|---|
| FlatIdentity (record copy) | 30.8 ns | 26.3 ns | 76.4 ns | 32.4 ns |
| FlatConversion (string→int) | 185.8 ns | 201.9 ns | 327.2 ns | 167.9 ns |
Flattening (a.b.c → d) |
22.9 ns | 23.0 ns | 70.8 ns | 29.2 ns |
| Polymorphic dispatch | 11.4 ns | 11.0 ns | 48.8 ns | 11.3 ns |
| UpdateInPlace | 6.1 ns | 6.0 ns | 83.9 ns (~18×) | 4.7 ns |
| TryMap (Result<T,Error>) | 208.4 ns | 195.4 ns (no native) | — | 222.6 ns |
| Collection (1000 items) | 38.6 µs | 41.1 µs | 30.4 µs | 39.6 µs |
Allocation: identical across mappers except Collection where AutoMapper allocates 11% more (86.5 KB vs 78.2 KB).
See docs/performance.md for the full BenchmarkDotNet output, methodology, and the enforced per-call allocation budgets (CI fails on regression).
[Map<TSrc, TDst>] — direct property/constructor mapping with case-sensitive matching and compile-time diagnostics on mismatch[TryMap<TSrc, TDst>] — fallible mapping returning Result<TDst, MappingError> (integrates with ZeroAlloc.Results smart constructors)[MapProperty] flattening — "Customer.Address.City" → City via dotted paths[BeforeMap] / [AfterMap] hooks — zero overhead when bodies are empty[PolymorphicMap] — type-switch dispatch generated at compile time[ReverseMap] — symmetric Domain↔DTO with a single declarationvoid Map(src, ref dst) overloads, zero destination allocationList<T>, T[], IEnumerable<T>, IReadOnlyList<T> auto-emitted (opt-out via [SkipCollectionOverloads])[MappingCulture] — culture-aware decimal.Parse / DateTime.Parse per-mapperTryMap as MappingError.SmartCtorRejectedMakeGenericType, no expression compilation; trim/AOT warnings treated as errors in the AOT smoke gate| Page | Description |
|---|---|
| Getting Started | Install + first mapper in five minutes |
| Basic Mapping | Property matching, conversions, customisation |
| Flattening | Dotted source paths via [MapProperty] |
| Collections | Auto-emitted overloads + nested elements |
| Polymorphic | Type-switch dispatch |
| Reverse Mapping | Symmetric Domain↔DTO |
| Update In Place | Allocation-free destination reuse |
| Hooks | [BeforeMap] / [AfterMap] |
| Culture & Strict | [MappingCulture] and strict mode |
| Performance | Benchmarks, allocation budgets, AOT |
| Diagnostics | All ZAMAP* diagnostic IDs |
| Testing | How to unit-test generated mappers |
| Advanced | Edge cases, generator internals |
MIT. See .
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 net8.0 is compatible. net8.0-android net8.0-android was computed. net8.0-browser net8.0-browser was computed. net8.0-ios net8.0-ios was computed. net8.0-maccatalyst net8.0-maccatalyst was computed. net8.0-macos net8.0-macos was computed. net8.0-tvos net8.0-tvos was computed. net8.0-windows net8.0-windows was computed. net9.0 net9.0 is compatible. net9.0-android net9.0-android was computed. net9.0-browser net9.0-browser was computed. net9.0-ios net9.0-ios was computed. net9.0-maccatalyst net9.0-maccatalyst was computed. net9.0-macos net9.0-macos was computed. net9.0-tvos net9.0-tvos was computed. net9.0-windows net9.0-windows was computed. net10.0 net10.0 is compatible. net10.0-android net10.0-android was computed. net10.0-browser net10.0-browser was computed. net10.0-ios net10.0-ios was computed. net10.0-maccatalyst net10.0-maccatalyst was computed. net10.0-macos net10.0-macos was computed. net10.0-tvos net10.0-tvos was computed. net10.0-windows net10.0-windows was computed. |
This package is not used by any NuGet packages.
This package is not used by any popular GitHub repositories.