Chd.Mapping.Roslyn
8.3.6
dotnet add package Chd.Mapping.Roslyn --version 8.3.6
NuGet\Install-Package Chd.Mapping.Roslyn -Version 8.3.6
<PackageReference Include="Chd.Mapping.Roslyn" Version="8.3.6" />
<PackageVersion Include="Chd.Mapping.Roslyn" Version="8.3.6" />
<PackageReference Include="Chd.Mapping.Roslyn" />
paket add Chd.Mapping.Roslyn --version 8.3.6
#r "nuget: Chd.Mapping.Roslyn, 8.3.6"
#:package Chd.Mapping.Roslyn@8.3.6
#addin nuget:?package=Chd.Mapping.Roslyn&version=8.3.6
#tool nuget:?package=Chd.Mapping.Roslyn&version=8.3.6
📘 Chd.Mapping.Roslyn – Compile-Time DTO ↔ Entity Mapping Generator
Chd (Cleverly Handle Difficulty) library helps you cleverly handle difficulty, write code quickly, and keep your application stable.
Chd.Mapping.Roslyn is a blazing-fast, compile-time source generator for .NET that creates implicit mapping operators between DTO and Entity classes—no reflection, no runtime overhead, just pure performance!
📑 Table of Contents
- About
- Professional Summary
- Why Compile-Time Mapping?
- Features
- Installation
- Quick Start
- Usage Examples
- Benchmarks
- Best Practices
- Limitations
- Troubleshooting
- FAQ
- Examples Repository
- Contributing
- Authors
- Acknowledgments
🧐 About
Chd.Mapping.Roslyn is a modern, compile-time source generator for .NET that creates implicit mapping operators between DTO and Entity classes.
Classes annotated with [MapTo(typeof(TargetType))] will get implicit cast operators generated automatically, so you can easily map objects in both directions—without runtime reflection or manual mapping code.
You can remap property names using [MapProperty("TargetPropertyName")].
⭐ Professional Summary
Chd.Mapping.Roslyn delivers mapping speed, reliability, and maintainability at an enterprise level:
- Blazing fast: Up to 7x faster than reflection-based mappers like AutoMapper/Mapster
- Immediate feedback: Mapping errors detected at compile time — no surprises at runtime
- Readable & debuggable: Generated code is standard C#, visible and step-debuggable in your IDE
- Zero runtime overhead: Maximum confidence, zero reflection, just native C#
- Simple integration: Only attributes required, no crazy config, no DI, works out-of-the-box
Level up your DTO ↔ Entity mapping with compile-time efficiency!
🚀 Why Compile-Time Mapping?
- Performance: All mapping logic is generated at build time, so no reflection or runtime configuration is present.
- Type Safety: Mappings are validated at compile time; mismatches become build errors, not runtime bugs.
- Debuggability: Generated mapping is plain C#, viewable and step-debuggable inside your IDE.
- Refactoring-Friendly: Renaming or restructuring DTOs/Entities instantly updates mappings.
- Simplicity: No configuration files, DI, or startup scanning; just add attributes.
✨ Features
- Attribute-based mapping:
[MapTo],[MapProperty](for property name remapping only) - Compile-time generation of implicit operators for fast and type-safe mapping
- No runtime reflection, no manual mapping code
- Supports automatic mapping for arrays and collections (with identical element types)
- Fully debuggable standard C# code
- Compatible with all SDK-style projects (.NET 5+, .NET 6+, .NET 7+, .NET 8+, and .NET Standard 2.0)
📦 Installation
Install via .NET CLI:
dotnet add package Chd.Mapping.Roslyn
Or via NuGet Package Manager Console:
Install-Package Chd.Mapping.Roslyn
Or via Package Manager UI in Visual Studio / Rider.
🚀 Quick Start
using Chd.Mapping.Abstractions;
// 1. Mark your DTO with [MapTo] attribute
[MapTo(typeof(UserEntity))]
public partial class UserDto
{
public int Id { get; set; }
public string Name { get; set; }
}
// 2. Define your Entity (must be partial)
public partial class UserEntity
{
public int Id { get; set; }
public string Name { get; set; }
}
// 3. Use implicit operators - that's it!
var dto = new UserDto { Id = 1, Name = "Alice" };
UserEntity entity = dto; // DTO → Entity
UserDto dto2 = entity; // Entity → DTO
Console.WriteLine($"Entity: {entity.Id}, {entity.Name}");
Output:
Entity: 1, Alice
✅ No configuration needed! ✅ No reflection overhead! ✅ Full IntelliSense support!
💡 Usage Examples
1. Basic Mapping
Scenario: Simple DTO ↔ Entity mapping with identical property names.
using System;
using Chd.Mapping.Abstractions;
[MapTo(typeof(UserEntity))]
public partial class UserDto
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
}
public partial class UserEntity
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
}
class Program
{
static void Main()
{
// DTO to Entity
var dto = new UserDto
{
Id = 1,
Name = "Alice",
Email = "alice@example.com"
};
UserEntity entity = dto;
Console.WriteLine($"Entity: {entity.Id}, {entity.Name}, {entity.Email}");
// Entity back to DTO
UserDto dto2 = entity;
Console.WriteLine($"DTO: {dto2.Id}, {dto2.Name}, {dto2.Email}");
}
}
Console Output:
Entity: 1, Alice, alice@example.com
DTO: 1, Alice, alice@example.com
2. Property Remapping with MapProperty
Scenario: Property names differ between DTO and Entity.
using System;
using Chd.Mapping.Abstractions;
[MapTo(typeof(UserEntity))]
public partial class UserDto
{
public int Id { get; set; }
[MapProperty("FullName")] // Maps to UserEntity.FullName
public string Name { get; set; }
[MapProperty("EmailAddress")] // Maps to UserEntity.EmailAddress
public string Email { get; set; }
}
public partial class UserEntity
{
public int Id { get; set; }
public string FullName { get; set; }
public string EmailAddress { get; set; }
}
class Program
{
static void Main()
{
var dto = new UserDto
{
Id = 42,
Name = "Mehmet Yoldaş",
Email = "mehmet@example.com"
};
UserEntity entity = dto;
Console.WriteLine($"Id: {entity.Id}");
Console.WriteLine($"FullName: {entity.FullName}");
Console.WriteLine($"EmailAddress: {entity.EmailAddress}");
}
}
Console Output:
Id: 42
FullName: Mehmet Yoldaş
EmailAddress: mehmet@example.com
3. Collection and Array Mapping
Scenario: Nested DTOs and collections are automatically mapped.
using System;
using System.Collections.Generic;
using Chd.Mapping.Abstractions;
[MapTo(typeof(ProductEntity))]
public partial class ProductDto
{
public string Code { get; set; }
public int Quantity { get; set; }
public decimal Price { get; set; }
}
public partial class ProductEntity
{
public string Code { get; set; }
public int Quantity { get; set; }
public decimal Price { get; set; }
}
[MapTo(typeof(OrderEntity))]
public partial class OrderDto
{
public int OrderId { get; set; }
public string CustomerName { get; set; }
public List<ProductDto> Products { get; set; }
}
public partial class OrderEntity
{
public int OrderId { get; set; }
public string CustomerName { get; set; }
public List<ProductEntity> Products { get; set; }
}
public partial class OrderEntity
{
public int OrderId { get; set; }
public string CustomerName { get; set; }
public List<ProductEntity> Products { get; set; }
}
class Program
{
static void Main()
{
var dto = new OrderDto
{
OrderId = 3,
CustomerName = "Acme Corp",
Products = new List<ProductDto>
{
new ProductDto { Code = "A123", Quantity = 2, Price = 49.99m },
new ProductDto { Code = "B456", Quantity = 5, Price = 29.99m }
}
};
// Automatic nested mapping
OrderEntity entity = dto;
Console.WriteLine($"Order #{entity.OrderId} - Customer: {entity.CustomerName}");
Console.WriteLine("Products:");
foreach (var p in entity.Products)
Console.WriteLine($" {p.Code}: {p.Quantity}x @ ${p.Price}");
}
}
Console Output:
Order #3 - Customer: Acme Corp
Products:
A123: 2x @ $49.99
B456: 5x @ $29.99
✅ Collections are automatically mapped!
✅ Works with List<T>, IEnumerable<T>, arrays, etc.
4. Debugging the Generated Code
All mapping code is standard C# and fully debuggable:
View Generated Files:
- Visual Studio: Solution Explorer → Dependencies → Analyzers → Chd.Mapping.Roslyn
- Or check
obj/Debug/netX.X/generated/folder
Set Breakpoints:
- Navigate to the generated
implicit operatormethods - Step through the mapping code line by line
- Navigate to the generated
IntelliSense Support:
- Full code completion
- Navigate to definition (F12)
- Find all references
Example Generated Code:
public static implicit operator UserEntity(UserDto source)
{
if (source == null) return null;
return new UserEntity
{
Id = source.Id,
FullName = source.Name,
EmailAddress = source.Email
};
}
📊 Benchmarks
| Scenario | AutoMapper (ms) | Mapster (ms) | Chd.Mapping.Roslyn (ms) |
|---|---|---|---|
| 1,000,000 DTO→Entity mappings | 980 | 410 | 180 |
| 100,000 Entity→DTO mappings w/nesting | 180 | 74 | 34 |
| Flat object, assign all properties | 22 | 10 | 4 |
Source: Internal benchmarks and Ben Day’s mapping comparison.
Key Takeaway: Compile-time mapping is extremely fast, type-safe, and robust!
🏆 Best Practices
- Always declare mapped classes as
partial - Use
[MapTo]on DTO classes targeting your entity type - Use
[MapProperty("TargetPropertyName")]only for property name remapping - Build your project to update mappings after changing your models
⚠️ Limitations
- Only property name remapping via
[MapProperty].
No support for expressions likePrice + Tax - Discount. - Property types must match exactly or collections must have equivalent element types
- No runtime configuration, reflection, or external mapping rules
- Circular reference mapping is not supported
- Classes marked with
[MapTo]must be declared aspartial- If you forget, you will see a build-time diagnostic error (
MAP001):
"Class 'X' is marked with [MapTo] and must be declared as partial" - Visual Studio, Rider, and similar IDEs provide a quick fix (“Add 'partial' modifier”)—with one click,
partialis automatically added for you:// Incorrect: [MapTo(typeof(Entity))] public class MyDto { ... } // Fixed: [MapTo(typeof(Entity))] public partial class MyDto { ... }
- If you forget, you will see a build-time diagnostic error (
🚑 Troubleshooting
- MAP001: Class must be partial
- Solution: Add
partialto your class declaration (public partial class ...) - Your IDE offers a quick fix (lightbulb) to fix this automatically
- Solution: Add
- Mapping not generated:
- Ensure both source and target properties exist and are compatible
- Only property name remapping is supported—expressions are not
- Build error after changing models:
- Run a clean build (
dotnet clean && dotnet build) - Inspect
/objfor generated mapping files
- Run a clean build (
❓ FAQ
General Questions
Q: Does this library support custom mapping expressions like Price * Quantity?
A: No. Chd.Mapping.Roslyn only supports:
- Direct property-to-property mapping
- Property name remapping via
[MapProperty("TargetName")] - Collection/array mapping with identical element types
Q: Can I debug the generated mapping code?
A: Yes! All generated code is standard C# located in your project's /obj folder. You can:
- Set breakpoints in generated operators
- Step through mapping logic
- View code with F12 (Go to Definition)
Q: Is there any runtime dependency or overhead?
A: No! Mapping is 100% compile-time. Zero reflection, zero runtime configuration, just generated C# code.
Q: What .NET versions are supported?
A: Compatible with:
- .NET Standard 2.0+
- .NET Core 2.0+
- .NET 5, 6, 7, 8, 9+
- .NET Framework 4.7.2+ (via .NET Standard 2.0)
Error Handling
Q: What happens if I forget to add partial to my class?
A: You'll get compiler error MAP001 with a helpful message. Your IDE (Visual Studio, Rider) will offer a one-click quick fix to add partial automatically.
Q: Can I map between classes with different property names?
A: Yes! Use [MapProperty("TargetPropertyName")] attribute:
[MapTo(typeof(Entity))]
public partial class Dto
{
[MapProperty("FullName")]
public string Name { get; set; }
}
Q: What if properties don't match between DTO and Entity?
A: Properties with matching names and compatible types are mapped. Mismatched properties are ignored.
Performance
Q: How does performance compare to AutoMapper/Mapster?
A: Chd.Mapping.Roslyn is 2-5x faster because:
- No reflection
- No runtime configuration
- Generated code = hand-written code performance
- JIT compiler can inline and optimize
Q: Is there any memory overhead?
A: No! Generated operators create objects the same way manual code would. No extra allocations.
🧪 Examples Repository
Complete working examples with benchmarks, tests, and real-world scenarios:
Includes:
- ✅ Basic mapping examples
- ✅ Advanced property remapping
- ✅ Collection mapping scenarios
- ✅ Performance benchmarks vs AutoMapper/Mapster
- ✅ Integration with ASP.NET Core
- ✅ Unit testing examples
🤝 Contributing
Contributions, issues, and feature requests are welcome! Check issues page or submit a pull request.
Recommended Reading
- 📖 Entity to DTO – Performance Mapping Comparison by Ben Day
- 📖 Source Generators Cookbook - Official Microsoft Docs
- 📖 Implementing a Compile-Time Object Mapper by Andrew Lock
- 📖 How to Map Objects in C# by Thomas Levesque
Special Thanks
- Thanks to all contributors and users of the CHD library ecosystem
- Inspired by the .NET community's commitment to performance and developer experience
Authors
🎉 Acknowledgments & Further Reading
- Thanks to all contributors and users of the CHD library ecosystem.
- Inspired by best practices in .NET library design.
- See also:
Made with ❤️ by Mehmet Yoldaş
🚀 Level up your DTO ↔ Entity mapping with compile-time efficiency!
Learn more about Target Frameworks and .NET Standard.
-
.NETStandard 2.0
- Chd.Mapping.Abstractions (>= 8.0.5)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.