VelocityMapper 1.2.1-preview
dotnet add package VelocityMapper --version 1.2.1-preview
NuGet\Install-Package VelocityMapper -Version 1.2.1-preview
<PackageReference Include="VelocityMapper" Version="1.2.1-preview" />
<PackageVersion Include="VelocityMapper" Version="1.2.1-preview" />
<PackageReference Include="VelocityMapper" />
paket add VelocityMapper --version 1.2.1-preview
#r "nuget: VelocityMapper, 1.2.1-preview"
#:package VelocityMapper@1.2.1-preview
#addin nuget:?package=VelocityMapper&version=1.2.1-preview&prerelease
#tool nuget:?package=VelocityMapper&version=1.2.1-preview&prerelease
VelocityMapper
The fastest .NET mapper. Zero reflection. Zero overhead. Powered by Source Generators.
VelocityMapper uses Source Generators to generate optimized mapping code at compile-time. Familiar AutoMapper-style API with superior performance.
๐ฆ Installation
dotnet add package VelocityMapper
Supported frameworks: .NET 6, 8, 9, 10
โ ๏ธ Required: Enable Source Generator in Your Project
VelocityMapper requires the Source Generator to work. Add this to your .csproj:
<ItemGroup>
<ProjectReference Include="path/to/VelocityMapper.Generators.csproj"
OutputItemType="Analyzer"
ReferenceOutputAssembly="false" />
</ItemGroup>
If you installed via NuGet, the analyzer is automatically included - no additional configuration needed.
If you're referencing the source project, you must add the reference above to enable code generation at compile-time.
๐ Quick Start
1. Create your models
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public Address Address { get; set; }
}
public class UserDto
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public AddressDto Address { get; set; }
}
2. Configure mappings
using VelocityMapper;
public static class AppMapperConfig
{
[MapperConfiguration]
public static void ConfigureMappers()
{
MapperSetup.CreateMap<User, UserDto>();
MapperSetup.CreateMap<Address, AddressDto>();
}
}
3. Use the mapper
var user = new User { Id = 1, Name = "John", Email = "john@email.com" };
// โก Create new instance
var dto = Mapper.To<UserDto>(user);
// Zero allocation - map to existing object
var existingDto = new UserDto();
Mapper.To(user, existingDto);
๐ API
Basic Mapping
// New instance
var dto = Mapper.To<UserDto>(user);
// To existing object (zero allocation)
Mapper.To(user, existingDto);
Collection Mapping
// โก NEW API - Cleaner and faster with Span!
var users = GetUsers(); // List<User>, User[], IEnumerable<User>
// ToList - Auto-optimized with CollectionsMarshal.AsSpan (.NET 8+)
List<UserDto> dtos = Mapper.ToList<UserDto>(users);
// ToArray - Optimized with Span zero-copy
UserDto[] array = Mapper.ToArray<UserDto>(users);
// ToEnumerable - Lazy evaluation (deferred execution)
IEnumerable<UserDto> enumerable = Mapper.ToEnumerable<UserDto>(users);
var filtered = enumerable.Where(x => x.Id > 10).ToList();
// ToSpan - TRUE zero allocation (advanced)
Span<UserDto> destination = stackalloc UserDto[100];
Mapper.ToSpan(users.AsSpan(), destination);
// Legacy API (still supported, but ToList/ToArray are faster)
List<UserDto> dtos2 = CollectionMapper.MapToList(users, Mapper.To<UserDto>);
๐ Mapping Behavior
Extra Properties are Automatically Ignored
VelocityMapper maps based on destination properties. Properties that exist only in the source are automatically ignored:
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string PasswordHash { get; set; } // Only exists in entity
}
public class UserDto
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
// PasswordHash doesn't exist โ ignored automatically!
}
var dto = Mapper.To<UserDto>(user);
// dto will have: Id, Name, Email
// PasswordHash is silently ignored โ
| Scenario | Behavior |
|---|---|
| Property exists in both | โ Maps |
| Property only in source | โ Silently ignores |
| Property only in destination | โ Keeps default value |
Attributes
public class UserDto
{
public int Id { get; set; }
[MapFrom("FirstName")] // Map from differently named property
public string Name { get; set; }
[IgnoreMap] // Explicitly ignore (documentation)
public string CacheKey { get; set; }
}
๐๏ธ Performance
Benchmark on .NET 10 (Intel Core i5-14600KF):
| Mapper | Time | Comparison |
|---|---|---|
| VelocityMapper | 12.03 ns | Fastest |
| Manual | 12.22 ns | baseline |
| Mapperly | 12.29 ns | 2% slower |
| Mapster | 18.91 ns | 57% slower |
| AutoMapper | 32.87 ns | 173% slower |
VelocityMapper is faster than hand-written code.
๐ง How It Works
The Source Generator analyzes your code at compile-time and generates optimized methods:
// You write:
Mapper.CreateMap<User, UserDto>();
var dto = Mapper.To<UserDto>(user);
// The generator automatically creates:
public static UserDto To(User source)
{
return new UserDto
{
Id = source.Id, // Value types first (cache-friendly)
Age = source.Age,
Name = source.Name, // Reference types after
Email = source.Email,
Address = source.Address is { } addr ? To(addr) : null // Nested mapping
};
}
๐ Quick Reference
| Method | Usage | Allocation | Performance |
|---|---|---|---|
Mapper.To<TDest>(source) |
New instance | DTO size | โกโกโก 12ns |
Mapper.To(source, dest) |
Existing object | 0 B | โกโกโก Zero alloc |
Mapper.ToList<TDest>(enumerable) |
IEnumerable โ List | List + DTOs | โกโกโก Span-optimized |
Mapper.ToArray<TDest>(enumerable) |
IEnumerable โ Array | Array + DTOs | โกโกโก Span zero-copy |
Mapper.ToEnumerable<TDest>(enumerable) |
IEnumerable โ IEnumerable | Lazy | โกโกโก Deferred execution |
Mapper.ToSpan(src, dest) |
Span โ Span | 0 B | โกโกโก TRUE zero alloc |
CollectionMapper.* (legacy) |
Compatibility | List + DTOs | โกโก Slower |
New API: ToList, ToArray and ToEnumerable automatically detect List/Array and use fast-path with Span!
๐ License
MIT License - see LICENSE
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net6.0 is compatible. 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 is compatible. 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 is compatible. 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. |
-
net10.0
- No dependencies.
-
net6.0
- No dependencies.
-
net8.0
- No dependencies.
-
net9.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.
| Version | Downloads | Last Updated |
|---|