Chd.Mapping.Roslyn.Advanced
8.0.3
See the version list below for details.
dotnet add package Chd.Mapping.Roslyn.Advanced --version 8.0.3
NuGet\Install-Package Chd.Mapping.Roslyn.Advanced -Version 8.0.3
<PackageReference Include="Chd.Mapping.Roslyn.Advanced" Version="8.0.3" />
<PackageVersion Include="Chd.Mapping.Roslyn.Advanced" Version="8.0.3" />
<PackageReference Include="Chd.Mapping.Roslyn.Advanced" />
paket add Chd.Mapping.Roslyn.Advanced --version 8.0.3
#r "nuget: Chd.Mapping.Roslyn.Advanced, 8.0.3"
#:package Chd.Mapping.Roslyn.Advanced@8.0.3
#addin nuget:?package=Chd.Mapping.Roslyn.Advanced&version=8.0.3
#tool nuget:?package=Chd.Mapping.Roslyn.Advanced&version=8.0.3
Chd.Mapping.Roslyn.Advanced – High-Performance, Expression-Aware Source Generator for .NET Mapping
📝 Table of Contents
- About
- Why Chd.Mapping.Roslyn.Advanced?
- Features
- Installation
- Usage
- Performance
- Best Practices & Tips
- Limitations
- Troubleshooting
- Viewing the Generated Mapping Code
- FAQ
- Contributing
- Authors
- Acknowledgments
🧐 About
Chd.Mapping.Roslyn.Advanced is a modern, compile-time object mapper for .NET, built with Roslyn source generators. It automatically creates fast, type-safe, and debuggable mapping code between DTOs and entities during your build process—eliminating runtime reflection, configuration headaches, and mapping errors typical of tools like AutoMapper or Mapster.
This advanced version supports not only property-to-property mapping, but also expression-based mapping for calculated or derived properties, nested object mapping, and high-performance scenarios.
🚀 Why Chd.Mapping.Roslyn.Advanced?
- Zero Reflection, Maximum Speed: All mapping logic is generated at build time. No runtime cost, no dynamic code, no hidden performance penalty.
- Type Safety: All mapping is verified at build—if your DTO or entity changes, mapping errors become compiler errors, not runtime bugs.
- Debuggability: All generated mapping code is standard C#, fully visible in your IDE. Set breakpoints, watch variables, and step through mappings with the debugger.
- Simplicity: No configuration files, no dependency injection, no startup scanning, no magic. Just add attributes, build, and use.
- Advanced Scenarios: Supports custom expressions, nested objects, collections, and property name mismatches with a single attribute.
✨ Features
- Attribute-based mapping:
[MapTo],[MapProperty](with expression support) - Compile-time generation of implicit mapping operators
- Expression-based property mapping (e.g.,
NetTotal = Price + Tax - Discount) - Nested and collection mapping support
- No runtime dependency, no reflection, no configuration files
- Full support for .NET 8+, .NET 9, and .NET Standard 2.0 SDK-style projects
📦 Installation
Install via .NET CLI:
dotnet add package Chd.Mapping.Roslyn.Advanced
Or via NuGet Package Manager Console:
Install-Package Chd.Mapping.Roslyn.Advanced
Compatible with all SDK-style projects – .NET Core 3.1+, .NET 5+, .NET 6+, .NET 7+.
🎈 Usage
1. Basic Mapping
Scenario: Map between DTO and Entity with matching property names—no configuration needed.
using Chd.Mapping.Abstractions;
using System;
[MapTo(typeof(UserEntity))]
public class UserDto
{
public int Id { get; set; }
public string Name { get; set; }
}
public partial class UserEntity
{
public int Id { get; set; }
public string Name { get; set; }
}
class Program
{
static void Main()
{
var dto = new UserDto { Id = 1, Name = "Alice" };
UserEntity entity = dto; // Implicit mapping
Console.WriteLine($"Id: {entity.Id}");
Console.WriteLine($"Name: {entity.Name}");
}
}
Console Output:
Id: 1
Name: Alice
2. Advanced Property Mapping
Scenario: Map between differently named properties, or apply custom logic and expressions.
using Chd.Mapping.Abstractions;
using System;
[MapTo(typeof(UserEntity))]
public class UserDto
{
public int Id { get; set; }
[MapProperty("FullName")] // Maps DTO.Name → Entity.FullName
public string Name { get; set; }
}
public partial class UserEntity
{
public int Id { get; set; }
public string FullName { get; set; }
}
class Program
{
static void Main()
{
var dto = new UserDto { Id = 42, Name = "Mehmet Yoldaş" };
UserEntity entity = dto; // Mapping with different property name
Console.WriteLine($"Id: {entity.Id}");
Console.WriteLine($"FullName: {entity.FullName}");
}
}
Console Output:
Id: 42
FullName: Mehmet Yoldaş
Expression-Based Mapping
using Chd.Mapping.Abstractions;
using System;
[MapTo(typeof(OrderEntity))]
public class OrderDto
{
public decimal Price { get; set; }
public decimal Tax { get; set; }
public decimal Discount { get; set; }
[MapProperty("Price + Tax - Discount")]
public decimal NetTotal { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
[MapProperty("Name + ' ' + Surname")]
public string FullName { get; set; }
public bool IsActive { get; set; }
[MapProperty("IsActive ? 'Active' : 'Passive'")]
public string StatusText { get; set; }
}
public partial class OrderEntity
{
public decimal Price { get; set; }
public decimal Tax { get; set; }
public decimal Discount { get; set; }
public decimal NetTotal { get; set; }
public string FullName { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public string StatusText { get; set; }
public bool IsActive { get; set; }
}
class Program
{
static void Main()
{
var dto = new OrderDto
{
Price = 200,
Tax = 36,
Discount = 16,
Name = "Ayşe",
Surname = "Kaya",
IsActive = false
};
OrderEntity entity = dto;
Console.WriteLine($"NetTotal: {entity.NetTotal}"); // 220
Console.WriteLine($"FullName: {entity.FullName}"); // Ayşe Kaya
Console.WriteLine($"StatusText: {entity.StatusText}"); // Passive
}
}
Console Output:
NetTotal: 220
FullName: Ayşe Kaya
StatusText: Passive
Tip:
You can use either single quotes (' ') or double quotes (" ") for string concatenation in expressions.
For readability, the recommended style is single quotes (' '), as in[MapProperty("Name + ' ' + Surname")].
3. Nested and Collection Mapping
Scenario: Map nested objects and collections automatically.
using Chd.Mapping.Abstractions;
using System;
using System.Collections.Generic;
[MapTo(typeof(ProductEntity))]
public class ProductDto
{
public string Code { get; set; }
public int Quantity { get; set; }
}
public partial class ProductEntity
{
public string Code { get; set; }
public int Quantity { get; set; }
}
[MapTo(typeof(OrderEntity))]
public class OrderDto
{
public int OrderId { get; set; }
public List<ProductDto> Products { get; set; }
}
public partial class OrderEntity
{
public int OrderId { get; set; }
public List<ProductEntity> Products { get; set; }
}
class Program
{
static void Main()
{
var dto = new OrderDto
{
OrderId = 3,
Products = new List<ProductDto>
{
new ProductDto { Code = "A123", Quantity = 2 },
new ProductDto { Code = "B456", Quantity = 5 }
}
};
OrderEntity entity = dto;
Console.WriteLine($"OrderId: {entity.OrderId}");
foreach (var p in entity.Products)
Console.WriteLine($"Product: {p.Code} - {p.Quantity}");
}
}
Console Output:
OrderId: 3
Product: A123 - 2
Product: B456 - 5
4. Debugging and Maintainability
- All generated mapping code is standard C#, located in
/objor/Generatedfolders. - You can set breakpoints, watch variables, and step through mappings with the debugger.
- Example generated code:
public static implicit operator UserEntity(UserDto dto) { if (dto == null) return null; return new UserEntity { Id = dto.Id, Name = dto.Name, // ... other properties }; }
🚦 Performance
| Scenario | AutoMapper (ms) | Mapster (ms) | Chd.Mapping.Roslyn.Advanced (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, see /benchmarks.
Key Takeaway:
Chd.Mapping.Roslyn.Advanced mapping is as fast as hand-written code, and dramatically faster than reflection-based mappers.
🏆 Best Practices & Tips
- Mark all mapped classes as
partial. - Use
[MapTo(typeof(TargetType))]on your DTOs. - Use
[MapProperty("...")]for calculated or custom-mapped properties. - Run a build to regenerate mapping code after model changes.
- No Fody, no config files, no runtime setup required.
⚠️ Limitations
[MapProperty]attribute only supports a single string parameter: use either the target property name or a full C# expression.- Expressions must be valid C# and use property names exactly as declared.
- Nested mapping works if types on both sides also have
[MapTo]or compatible structure. - Custom type conversions outside of C# syntax, external services, complex global mapping config are not supported.
- Circular object graph mapping is not supported.
- Classes marked with
[MapTo]must be declared aspartial.- If you forget to add
partial, you’ll 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 (lightbulb action) for this — “Add 'partial' modifier”.
- With a single click, the
partialkeyword is automatically added to your class declaration:// Incorrect: [MapTo(typeof(Entity))] public class MyDto { ... } // Fixed: [MapTo(typeof(Entity))] public partial class MyDto { ... }
- If you forget to add
🚑 Troubleshooting
- MAP001: Class must be partial
- Solution: Add
partialto your class declaration (e.g.,public partial class ...). - Your IDE (VS, Rider) typically offers a quick fix ("Add 'partial' modifier"/lightbulb) for this – just click to apply the fix!
- Solution: Add
- Build error after changing models: Run a clean build (
dotnet clean && dotnet build). Check generated sources in/obj. - Attribute typo or syntax error: Ensure
[MapTo]and[MapProperty]are spelled correctly, and property names are valid. - Expression compile errors: Expressions must be valid C#. If an error occurs, check the generated code and fix the expression.
🕵️♂️ Viewing the Generated Mapping Code
- Open
/obj/Debug/net*/*Mapping*.g.cs(or your IDE’s generated files node) to inspect all mapping operator code. - You can debug into the generated code just like any hand-written C#.
❓ FAQ
Q: Do I need to write any mapping code?
A: No. Just add attributes and build – all mapping code is generated for you.
Q: Can I debug the generated code?
A: Yes! All generated code is standard C# and fully debuggable.
Q: Is there any runtime dependency?
A: No. All mapping logic is generated at compile time.
Q: What if I change my DTO or Entity?
A: The generator will update mappings on the next build. Mapping errors become compiler errors.
🤝 Contributing
Contributions, issues and feature requests are welcome!
Check issues page or submit a pull request.
✍️ Authors
🎉 Acknowledgments
- Thanks to all contributors and users of the CHD library ecosystem.
- Inspired by best practices in .NET library design.
For issues, feature requests, or contributions, please visit the GitHub repository
Learn more about Target Frameworks and .NET Standard.
-
.NETStandard 2.0
- Chd.Mapping.Abstractions (>= 8.0.2)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.