ZMapper 1.2.2
See the version list below for details.
dotnet add package ZMapper --version 1.2.2
NuGet\Install-Package ZMapper -Version 1.2.2
<PackageReference Include="ZMapper" Version="1.2.2" />
<PackageVersion Include="ZMapper" Version="1.2.2" />
<PackageReference Include="ZMapper" />
paket add ZMapper --version 1.2.2
#r "nuget: ZMapper, 1.2.2"
#:package ZMapper@1.2.2
#addin nuget:?package=ZMapper&version=1.2.2
#tool nuget:?package=ZMapper&version=1.2.2
ZMapper
High-Performance Object Mapping for .NET
AutoMapper's fluent API + Mapperly's compile-time source generation = ZMapper
Features | Quick Start | Profiles & DI | Performance | API Reference
Features
- Near-Zero Overhead - Source-generated code runs as fast as hand-written mapping (~17 ns per object)
- Familiar API - AutoMapper-style fluent configuration (
CreateMap,ForMember,MapFrom) - Compile-Time Safety - All mapping code generated at build time, no runtime reflection
- Inheritance Support - Base class properties (e.g.
Id,CreatedAtfromBaseEntity) are mapped automatically through the full inheritance chain - Complex MapFrom Expressions - Navigation properties (
src.Client.Name), null-coalescing (src.Date ?? fallback), and arbitrary expressions - Nullable Type Handling - Safe mapping from
DateTime?toDateTime(and other nullable value types) with automatic?? default - Profiles - Organize mappings into reusable
IMapperProfileclasses (like AutoMapper profiles) - Dependency Injection - Auto-generated
AddZMapper()extension forIServiceCollection - Hooks -
BeforeMapandAfterMapcallbacks for custom pre/post-processing logic - Conditional Mapping - Map properties only when conditions are met (
When()) - PreCondition with Context - Runtime-parameterized conditions via
MappingContext(PreCondition((src, ctx) => ...)) - ConvertUsing - Whole-object conversion via lambda (
ConvertUsing(s => s.Id)) orITypeConverter<S,D>class; registered type converters auto-apply to matching properties across all mappings - ConstructUsing - Custom factory for destination construction (
ConstructUsing(s => new Dest(s.Id))) - Member ConvertUsing + Source Property - Per-member converter with explicit source (
ConvertUsing<T>(s => s.OtherProp)) - MemberList Validation -
MemberList.Source,.Destination, or.Nonefor compile-time coverage checks - Standalone Mapper -
config.CreateMapper()for non-DI scenarios (console apps, tools, tests) - Reverse Mapping - Bidirectional mappings with a single
.ReverseMap()call - Nested Objects - Full support for deep object graphs (any nesting depth)
- Collections - High-performance batch mapping with
ReadOnlySpan<T>, arrays, lists, andIEnumerable<T> - Extension Methods - Auto-generated
.ToXxx()extension methods for zero-ceremony mapping - Unmapped Property Detection - Compile-time ZMAP001 warning for destination properties with no matching source
- Modern C# -
init,required, nullable reference types, records, enums,DateOnly,Guid, etc.
Quick Start
Installation
dotnet add package ZMapper
Single NuGet package - includes both the runtime library and the compile-time source generator. No separate analyzer package needed.
Define Your Types
public class PersonDto
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
}
public class Person
{
public int Id { get; set; }
public string FullName { get; set; }
public string ContactEmail { get; set; }
}
Option A: Profile-Based Configuration (Recommended)
using ZMapper;
public class PersonProfile : IMapperProfile
{
public void Configure(MapperConfiguration config)
{
config.CreateMap<PersonDto, Person>()
.ForMember(dest => dest.FullName,
opt => opt.MapFrom(src => $"{src.FirstName} {src.LastName}"))
.ForMember(dest => dest.ContactEmail,
opt => opt.MapFrom(src => src.Email));
}
}
Option B: Inline Configuration (Original Pattern)
using ZMapper;
public partial class MyMapperConfig
{
public static IMapper Configure()
{
var config = new MapperConfiguration();
config.CreateMap<PersonDto, Person>()
.ForMember(dest => dest.FullName,
opt => opt.MapFrom(src => $"{src.FirstName} {src.LastName}"))
.ForMember(dest => dest.ContactEmail,
opt => opt.MapFrom(src => src.Email));
// The source generator creates this method at compile time
return CreateGeneratedMapper();
}
}
Map Objects
// With profiles: create the unified mapper
IMapper mapper = Mapper.Create();
// Or with DI (see Profiles & Dependency Injection section below)
// builder.Services.AddZMapper();
// Single object
var person = mapper.Map<PersonDto, Person>(dto);
// Or use the auto-generated extension method (even faster!)
var person = dto.ToPerson();
// Batch mapping with Span<T>
ReadOnlySpan<PersonDto> dtos = GetDtos();
Person[] people = mapper.MapArray<PersonDto, Person>(dtos);
// List mapping
List<Person> people = mapper.MapList<PersonDto, Person>(dtoList);
// IEnumerable mapping (LINQ queries, EF results, HashSets, etc.)
IEnumerable<PersonDto> filtered = dtos.Where(d => d.IsActive);
List<Person> activePeople = mapper.MapList<PersonDto, Person>(filtered);
Profiles & Dependency Injection
Organizing Mappings with Profiles
Profiles let you group related mappings into separate classes, just like AutoMapper:
using ZMapper;
// One profile per domain area
public class UserProfile : IMapperProfile
{
public void Configure(MapperConfiguration config)
{
config.CreateMap<UserDto, User>()
.ForMember(dest => dest.UserId, opt => opt.MapFrom(src => src.Id))
.ForMember(dest => dest.UserName, opt => opt.MapFrom(src => src.Username))
.ForMember(dest => dest.EmailAddress, opt => opt.MapFrom(src => src.Email))
.ForMember(dest => dest.FullName, opt => opt.Ignore());
}
}
public class AddressProfile : IMapperProfile
{
public void Configure(MapperConfiguration config)
{
config.CreateMap<AddressDto, Address>()
.ForMember(dest => dest.StreetAddress, opt => opt.MapFrom(src => src.Street))
.ForMember(dest => dest.Zip, opt => opt.MapFrom(src => src.PostalCode))
.ForMember(dest => dest.CountryName, opt => opt.MapFrom(src => src.Country));
}
}
The source generator discovers all IMapperProfile implementations at compile time and generates a unified mapper (Mapper) that combines all profile mappings into a single IMapper instance.
Dependency Injection
When your project references Microsoft.Extensions.DependencyInjection.Abstractions, ZMapper automatically generates an AddZMapper() extension method:
// In Program.cs or Startup.cs
builder.Services.AddZMapper();
// Then inject IMapper anywhere
public class UserService
{
private readonly IMapper _mapper;
public UserService(IMapper mapper)
{
_mapper = mapper;
}
public User GetUser(UserDto dto) => _mapper.Map<UserDto, User>(dto);
}
Manual Creation (Without DI)
If you don't use dependency injection, create the mapper directly:
// Without hooks
IMapper mapper = Mapper.Create();
// With hooks (from a MapperConfiguration)
var config = new MapperConfiguration();
new UserProfile().Configure(config);
IMapper mapper = Mapper.Create(config);
Performance
All benchmarks compare ZMapper against manual mapping (baseline), Mapperly (source generation), and AutoMapper (reflection-based).
Simple Object Mapping (Single)
| Method | Mean | Ratio | Allocated |
|---|---|---|---|
| ZMapper | 16.56 ns | 0.93x | 88 B |
| Manual Mapping | 17.79 ns | 1.00x | 88 B |
| Mapperly | 17.83 ns | 1.00x | 88 B |
| AutoMapper | 52.64 ns | 2.96x | 88 B |
ZMapper matches manual mapping speed and is 3x faster than AutoMapper.
Simple Batch Mapping (1,000 objects)
| Method | Mean | Ratio |
|---|---|---|
| Manual Loop | 18.79 us | 1.00x |
| ZMapper (Span) | 19.38 us | 1.03x |
| Mapperly Loop | 23.50 us | 1.25x |
| AutoMapper Loop | 54.38 us | 2.89x |
Span-based batch mapping is nearly identical to hand-written loops.
Complex Object Mapping (Nested objects, collections, enums)
| Method | Mean | Ratio |
|---|---|---|
| Manual (Order) | 168.35 ns | 1.00x |
| ZMapper (Order) | 172.59 ns | 1.03x |
| Mapperly (Order) | 214.79 ns | 1.28x |
| AutoMapper (Order) | 351.79 ns | 2.09x |
Even with deep object graphs (Order → OrderItems[] → OrderStatusInfo), ZMapper stays within 3% of manual mapping.
Complex Batch Mapping (1,000 orders)
| Method | Mean | Ratio |
|---|---|---|
| ZMapper (Span) | 122.75 us | 0.86x |
| Manual Loop | 142.93 us | 1.00x |
| Mapperly Loop | 167.91 us | 1.18x |
| AutoMapper Loop | 237.94 us | 1.67x |
ZMapper's Span-based batch mapping is faster than manual mapping for complex objects.
Why Is ZMapper Fast?
- Compile-time code generation - No runtime reflection or dictionary lookups
- Direct property access - Generated code reads/writes properties directly
ReadOnlySpan<T>batch operations - Zero-copy, stack-friendly iterationAggressiveInlining- Generated extension methods are JIT-inlined- No boxing - Value types stay on the stack
Run benchmarks yourself:
cd tests/ZMapper.Benchmarks
dotnet run -c Release
# Or filter specific benchmarks:
dotnet run -c Release -- --filter *Complex*
API Reference
CreateMap - Convention-Based Mapping
Properties with matching names are mapped automatically:
config.CreateMap<Source, Destination>();
ForMember - Explicit Property Mapping
Map properties with different names or custom expressions:
config.CreateMap<OrderDto, Order>()
.ForMember(dest => dest.OrderTotal,
opt => opt.MapFrom(src => src.Items.Sum(i => i.Price)));
ZMapper supports complex MapFrom expressions, including navigation properties and null-coalescing:
config.CreateMap<InvoiceEntity, InvoiceDto>()
// Navigation property flattening: src.Client.CompanyName -> dest.ClientName
.ForMember(dest => dest.ClientName,
opt => opt.MapFrom(src => src.Client != null ? src.Client.CompanyName : ""))
// Null-coalescing for nullable value types
.ForMember(dest => dest.IssueDate,
opt => opt.MapFrom(src => src.IssueDate ?? DateTime.UtcNow));
Ignore - Skip Properties
Prevent specific properties from being mapped:
config.CreateMap<UserDto, User>()
.ForMember(dest => dest.PasswordHash, opt => opt.Ignore())
.ForMember(dest => dest.InternalId, opt => opt.Ignore());
// Ignored properties retain their default values
Default Behavior - Unmapped Property Detection
ZMapper maps properties by name convention. If a destination property has no matching source property and is not explicitly configured, ZMapper emits a compile-time warning (ZMAP001):
warning ZMAP001: Destination property 'Address' on type 'Destination' has no matching source
property on 'Source'. Use .ForMember(d => d.Address, opt => opt.Ignore()) to explicitly ignore,
or .IgnoreNonExisting() to skip all non-matching properties.
You have two options to resolve:
// Option 1: Explicitly ignore individual properties
config.CreateMap<Source, Destination>()
.ForMember(dest => dest.Address, opt => opt.Ignore());
// Option 2: Opt out of unmapped property checks entirely
config.CreateMap<Source, Destination>()
.IgnoreNonExisting(); // All non-matching properties silently keep defaults
This is especially useful with hooks, where destination-only properties are set by BeforeMap/AfterMap:
config.CreateMap<InvoiceDto, Invoice>()
.IgnoreNonExisting() // CreatedAt, ProcessedBy are set by hooks below
.BeforeMap((src, dest) => dest.CreatedAt = DateTime.UtcNow)
.AfterMap((src, dest) => dest.ProcessedBy = "ZMapper");
Inheritance - Base Class Properties
ZMapper automatically maps properties from the entire inheritance chain. No extra configuration needed:
public abstract class BaseEntity
{
public int Id { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime UpdatedAt { get; set; }
}
public class Product : BaseEntity
{
public string Name { get; set; }
public decimal Price { get; set; }
}
public class ProductDto : BaseDto
{
public string Name { get; set; }
public decimal Price { get; set; }
}
// Id, CreatedAt, UpdatedAt from BaseEntity/BaseDto are mapped automatically
config.CreateMap<ProductDto, Product>();
This works with any inheritance depth (e.g. BaseEntity → AuditableEntity → Product). If a derived class hides a base property with new, the derived version takes precedence.
Nullable Value Types
When the source has nullable value types (DateTime?, int?) and the destination has non-nullable types, ZMapper safely maps using ?? default:
// Source: DateTime? IssueDate -> Destination: DateTime IssueDate
// Generated: destination.IssueDate = source.IssueDate ?? default;
// If source is null, destination gets default(DateTime)
config.CreateMap<NullableSource, NonNullableDestination>();
When - Conditional Mapping
Map a property only when a condition is true:
config.CreateMap<ProductDto, Product>()
.ForMember(dest => dest.Price, opt =>
{
opt.MapFrom(src => src.Price);
opt.When(src => src.Price > 0); // Only map positive prices
})
.ForMember(dest => dest.Description, opt =>
{
opt.MapFrom(src => src.Description!);
opt.When(src => src.Description != null); // Only map non-null
});
ConvertUsing - Whole-Object Conversion
Replace the entire property-by-property mapping with a single expression or converter class:
// Lambda: extract a single value from a complex type
config.CreateMap<ListDto, int>().ConvertUsing(s => s.Id);
config.CreateMap<ListDto, string>().ConvertUsing(s => s.Text);
// ITypeConverter class: reusable conversion logic (e.g., DateTimeOffset -> DateTime)
config.CreateMap<DateTimeOffset, DateTime>().ConvertUsing<DateTimeOffsetToDateTimeConverter>();
// Where:
public class DateTimeOffsetToDateTimeConverter : ITypeConverter<DateTimeOffset, DateTime>
{
public DateTime Convert(DateTimeOffset source) => source.UtcDateTime;
}
Automatic application of ITypeConverter across all mappings:
Once you register CreateMap<S, D>().ConvertUsing<TConverter>(), the converter is automatically applied to any property of that (source type, dest type) pair in any other mapping — no per-member configuration needed:
// Register once:
config.CreateMap<DateTimeOffset, DateTime>().ConvertUsing<DateTimeOffsetToDateTimeConverter>();
// Now any property with (DateTimeOffset → DateTime) uses the converter:
config.CreateMap<EventSourceDto, EventEntity>();
// Generated: destination.CreatedAt = new DateTimeOffsetToDateTimeConverter().Convert(source.CreatedAt);
This matches AutoMapper's global type converter behavior and is ideal for cross-cutting concerns like DateTimeOffset ⇄ DateTime or currency units.
ConstructUsing - Custom Factory
Use when the destination type has no parameterless constructor. Property mapping still applies after construction:
config.CreateMap<PersonDto, ImmutablePerson>()
.ConstructUsing(s => new ImmutablePerson(s.Id, s.Name))
.IgnoreNonExisting(); // Id, Name are read-only (set via constructor)
// After ConstructUsing, mutable properties (e.g., Age) are still mapped by convention
PreCondition - Context-Aware Conditional Mapping
Map properties conditionally based on runtime parameters passed via MappingContext:
config.CreateMap<CompanyDto, Company>()
.ForMember(d => d.Region,
opt => opt.PreCondition((src, ctx) => !ctx.GetOrDefault<bool>("IgnoreNested")))
.ForMember(d => d.Stream,
opt => opt.PreCondition((src, ctx) => !ctx.GetOrDefault<bool>("IgnoreNested")));
// Usage: pass context to skip nested properties
var ctx = new MappingContext();
ctx["IgnoreNested"] = true;
var company = mapper.Map<CompanyDto, Company>(dto, ctx);
// company.Region and company.Stream are null (skipped by PreCondition)
MemberList - Validation Mode
Control which side of the mapping is validated for property coverage:
// Default: MemberList.Destination — every dest property must have a source (ZMAP001 warning)
config.CreateMap<UserDto, User>();
// Source: every source property must be used (ZMAP003 warning for unused)
config.CreateMap<UserDto, User>(MemberList.Source);
// None: no validation warnings at all
config.CreateMap<UserDto, User>(MemberList.None);
ConvertUsing with Source Property - Per-Member Converter
Use a member converter with an explicit source property (when names differ):
config.CreateMap<InvoiceEntity, InvoiceDto>()
.ForMember(d => d.IssuanceDate,
opt => opt.ConvertUsing<ToDDMMYYYYConverter, DateTime>(s => s.IssuanceDateOffset));
// ^^^^^^^^^^^^^^^^^^^^^^
// source property name differs from destination (IssuanceDateOffset vs IssuanceDate)
Standalone Mapper (Without DI)
Create mapper instances without dependency injection:
// Option 1: Use Mapper.Create() directly
IMapper mapper = Mapper.Create();
// Option 2: Use config.CreateMapper() (AutoMapper-compatible pattern)
var config = new MapperConfiguration();
new UserProfile().Configure(config);
IMapper mapper = config.CreateMapper();
// Option 3: Use .ToXxx() extension methods (no mapper instance needed!)
var user = dto.ToUser();
ReverseMap - Bidirectional Mapping
Create mappings in both directions with a single call:
config.CreateMap<OrderDto, Order>()
.ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.OrderId))
.ForMember(dest => dest.Customer, opt => opt.MapFrom(src => src.CustomerName))
.ReverseMap();
// Now both OrderDto -> Order and Order -> OrderDto work
BeforeMap / AfterMap - Hooks
Execute custom logic before or after the mapping:
config.CreateMap<InvoiceDto, Invoice>()
.ForMember(dest => dest.InvoiceId, opt => opt.MapFrom(src => src.Id))
.BeforeMap((src, dest) =>
{
// Runs BEFORE property mapping
dest.CreatedAt = DateTime.UtcNow;
})
.AfterMap((src, dest) =>
{
// Runs AFTER property mapping
dest.ProcessedBy = "ZMapper";
dest.TotalWithTax = dest.Total * 1.21m;
});
Hooks are useful for:
- Setting audit fields (timestamps, user info)
- Computing derived values after mapping
- Logging or validation
- Normalizing data before mapping
Collection Mapping
ZMapper supports multiple collection mapping strategies:
// Span-based array mapping (fastest, zero-copy iteration)
Person[] people = mapper.MapArray<PersonDto, Person>(dtos.AsSpan());
// List mapping from ReadOnlySpan<T>
List<Person> people = mapper.MapList<PersonDto, Person>(dtos.AsSpan());
// IEnumerable<T> mapping (works with LINQ, EF, HashSet, etc.)
IEnumerable<PersonDto> query = dtos.Where(d => d.IsActive);
List<Person> activePeople = mapper.MapList<PersonDto, Person>(query);
Nested Object Mapping
Register mappings for each type in the object graph. ZMapper handles the nesting automatically:
// Register from leaf types up
config.CreateMap<AddressDto, Address>();
config.CreateMap<CustomerDto, Customer>(); // Customer has Address property
config.CreateMap<OrderItemDto, OrderItem>();
config.CreateMap<OrderDto, Order>(); // Order has Customer + List<OrderItem>
var order = mapper.Map<OrderDto, Order>(orderDto);
// Entire object graph is mapped, including nested collections
Null nested objects are handled safely (result is null, no exceptions).
Map to Existing Instance
Map into an already-constructed object instead of creating a new one:
var existingUser = GetFromDatabase();
mapper.Map<UserDto, User>(dto, existingUser);
// existingUser's properties are updated in-place
Extension Methods
For every registered mapping, ZMapper generates a .ToXxx() extension method:
// Given: config.CreateMap<UserDto, User>()
// Generated: public static User ToUser(this UserDto source)
var user = dto.ToUser(); // Clean, discoverable, inlined by JIT
These methods are marked with [MethodImpl(MethodImplOptions.AggressiveInlining)] for maximum performance.
Limitation: Extension methods do not invoke
BeforeMap/AfterMaphooks (they bypass the runtime hook infrastructure for zero overhead). If you rely on hooks, callmapper.Map<S, D>()orconfig.CreateMapper().Map<S, D>()instead. Built-in destination types (int,string,DateTime, etc.) don't get extension methods at all to avoid shadowingObject.ToString()/Convert.ToInt32()— usemapper.Map<S, D>()for those.
Supported Types
ZMapper handles all common .NET types out of the box:
| Category | Types |
|---|---|
| Primitives | int, long, double, decimal, bool, char, byte, etc. |
| Strings | string, including null, empty, unicode, and long strings |
| Date/Time | DateTime, DateTimeOffset, DateOnly, TimeOnly, TimeSpan |
| Identifiers | Guid, Uri |
| Enums | All enum types (mapped by value) |
| Nullable | int?, DateTime?, MyEnum?, etc. (auto-handled with ?? default) |
| Collections | List<T>, T[], IReadOnlyList<T>, IEnumerable<T> |
| Inheritance | Properties from base classes (abstract/concrete, any depth) |
| Modern C# | init setters, required properties, records |
Architecture
Your Code (Profiles or Fluent Config)
|
v
Source Generator <-- Compile Time (Roslyn)
|
v
Generated C# Code
- Per-class mapper (CreateMap pattern)
- Unified mapper (Profile pattern)
- Generic Map<TSource, TDest>() dispatcher
- ToB() extension methods
- MapArray / MapList batch methods
- AddZMapper() DI extension
|
v
Runtime Execution <-- Zero Overhead
NuGet Packages
| Package | Purpose |
|---|---|
| ZMapper | Core library + interfaces + Roslyn source generator (all-in-one NuGet) |
What Gets Generated?
Given this profile configuration:
public class UserProfile : IMapperProfile
{
public void Configure(MapperConfiguration config)
{
config.CreateMap<UserDto, User>()
.ForMember(dest => dest.UserId, opt => opt.MapFrom(src => src.Id))
.ForMember(dest => dest.UserName, opt => opt.MapFrom(src => src.Username));
}
}
The source generator emits (all in namespace ZMapper):
// 1. Unified mapper with all profile mappings combined (namespace ZMapper)
public sealed class Mapper : IMapper
{
public User Map_UserDto_To_User(UserDto source)
{
var destination = new User();
destination.UserId = source.Id;
destination.UserName = source.Username;
return destination;
}
// + MapArray, MapList, MapList (IEnumerable), Map<T,T> dispatcher
// + static Create() factory method
public static Mapper Create() => new();
}
// 2. Extension method (inlined)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static User ToUser(this UserDto source)
{
var destination = new User();
destination.UserId = source.Id;
destination.UserName = source.Username;
return destination;
}
// 3. DI extension (only when M.E.DI.Abstractions is referenced)
public static IServiceCollection AddZMapper(this IServiceCollection services)
{
services.AddSingleton<IMapper>(new Mapper());
return services;
}
Troubleshooting
Single Namespace
Everything lives in the ZMapper namespace — all interfaces, generated Mapper class, .ToXxx() extension methods, and AddZMapper() DI extension. Just one using needed:
using ZMapper; // MapperConfiguration, IMapper, IMapperProfile, Mapper, .ToXxx(), AddZMapper()
Compile-Time Diagnostics
| Code | Severity | Description |
|---|---|---|
| ZMAP001 | Warning | Unmapped destination property (use Ignore() or IgnoreNonExisting()) |
| ZMAP002 | Error | Profile class not declared as partial |
| ZMAP003 | Warning | Unused source property (when MemberList.Source is active) |
Profile Classes Must Be partial
The source generator creates a partial counterpart for profile classes. Missing partial causes CS0260:
public partial class UserProfile : IMapperProfile // partial required
Inspecting Generated Code
To see what the source generator produces, add to your .csproj:
<PropertyGroup>
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
<CompilerGeneratedFilesOutputPath>Generated</CompilerGeneratedFilesOutputPath>
</PropertyGroup>
<ItemGroup>
<Compile Remove="$(CompilerGeneratedFilesOutputPath)/**" />
</ItemGroup>
Important: If you later remove
EmitCompilerGeneratedFiles, delete theGenerated/folder manually to avoid CS0101 duplicate definition errors.
Project Structure
ZMapper/
src/
ZMapper/ # Core library + interfaces (IMapper, IMapperProfile, etc.)
ZMapper.SourceGenerator/ # Roslyn source generator
tests/
ZMapper.Tests/ # Unit tests (176 tests)
ZMapper.Benchmarks/ # BenchmarkDotNet suite
examples/
ZMapper.Example/ # Working example project (Profile pattern)
License
MIT License - see LICENSE file for details.
Acknowledgments
- AutoMapper - Inspiration for the fluent API and profile pattern
- Mapperly - Pioneering source generation for object mapping
- Roslyn - Source generator infrastructure
| 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 is compatible. 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
- System.Memory (>= 4.5.5)
-
net10.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.
ZMapper v1.2.2 adds ConvertUsing, ConstructUsing for custom factories, PreCondition with runtime MappingContext, per-member ConvertUsing of T (s => s.X), MemberList validation (Destination/Source/None), and config.CreateMapper() for standalone scenarios without DI.