Chd (Cleverly Handle Difficulty) packages are easy to use. Automatically maps DTO and Entity classes without any configuration. Now supports advanced mapping scenarios, custom value converters, nested object mapping, and improved performance for large projects.
License
—
Deps
1
Install Size
—
Vulns
✓ 0
Published
Feb 28, 2026
$ dotnet add package Chd.Mapping.Roslyn.AdvancedChd (Cleverly Handle Difficulty) library helps you cleverly handle difficulty, write code quickly, and keep your application stable.
Chd.Mapping.Roslyn.Advanced is a blazing-fast, compile-time object mapper for .NET with expression-based mapping support—built on Roslyn source generators for maximum performance and type safety!
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.
[MapTo], [MapProperty] (with expression support)[MapProperty(Price + Tax - Discount))NetTotal = Price + Tax - Discount;)Install via .NET CLI:
dotnet add package Chd.Mapping.Roslyn.Advanced
Or via NuGet Package Manager Console:
Install-Package Chd.Mapping.Roslyn.Advanced
Or via Package Manager UI in Visual Studio / Rider.
Requirements:
using Chd.Mapping.Abstractions;
// 1. Mark your DTO with [MapTo] and expression mapping
[MapTo(typeof(OrderEntity))]
public partial class OrderDto
{
public decimal Price { get; set; }
public decimal Tax { get; set; }
public decimal Discount { get; set; }
// Expression-based calculated property!
[MapProperty("Price * (Tax + 100) / 100 - Discount")]
public decimal NetTotal { get; set; }
}
// 2. Define your Entity (must be partial)
public partial class OrderEntity
{
public decimal Price { get; set; }
public decimal Tax { get; set; }
public decimal Discount { get; set; }
public decimal NetTotal { get; set; }
}
// 3. Use implicit operators - that's it!
var dto = new OrderDto { Price = 100, Tax = 18, Discount = 2 };
OrderEntity entity = dto; // DTO → Entity with calculation!
Console.WriteLine($"NetTotal: {entity.NetTotal}"); // Output: 116
Output:
NetTotal: 116
✅ Expression-based mapping! ✅ No reflection overhead! ✅ Full IntelliSense support! ✅ Compile-time validation!
Scenario: Simple DTO ↔ Entity mapping with identical property names.
using Chd.Mapping.Abstractions;
using System;
[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 = "Mehmet",
Email = "mehmet@example.com"
};
UserEntity entity = dto; // Implicit mapping
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, Mehmet, mehmet@example.com
DTO: 1, Mehmet, mehmet@example.com
Scenario: Map properties with different names.
using Chd.Mapping.Abstractions;
using System;
[MapTo(typeof(UserEntity))]
public partial class UserDto
{
public int Id { get; set; }
[MapProperty("FullName")] // Maps DTO.Name → Entity.FullName
public string Name { get; set; }
[MapProperty("EmailAddress")] // Maps DTO.Email → Entity.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
🔥 The Power of Advanced Mapping: Calculate derived properties with C# expressions!
using Chd.Mapping.Abstractions;
using System;
[MapTo(typeof(OrderEntity))]
public partial class OrderDto
{
public decimal Price { get; set; }
public decimal Tax { get; set; }
public decimal Discount { get; set; }
// Mathematical expression
[MapProperty("Price * (Tax + 100) / 100 - Discount")]
public decimal NetTotal { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
// String concatenation with single quotes
[MapProperty("Name + ' ' + Surname")]
public string FullName { get; set; }
public bool IsActive { get; set; }
// Ternary operator
[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 Name { get; set; }
public string Surname { get; set; }
public string FullName { get; set; }
public bool IsActive { get; set; }
public string StatusText { get; set; }
}
class Program
{
static void Main()
{
var dto = new OrderDto
{
Price = 100,
Tax = 18,
Discount = 2,
Name = "Mehmet",
Surname = "Yoldaş",
IsActive = true
};
OrderEntity entity = dto; // Expression-based mapping!
Console.WriteLine($"NetTotal: {entity.NetTotal}"); // 116
Console.WriteLine($"FullName: {entity.FullName}"); // Mehmet Yoldaş
Console.WriteLine($"StatusText: {entity.StatusText}"); // Active
// Reverse mapping works too!
OrderDto dto2 = entity;
Console.WriteLine($"DTO NetTotal: {dto2.NetTotal}"); // 116
}
}
Console Output:
NetTotal: 116
FullName: Mehmet Yoldaş
StatusText: Active
DTO NetTotal: 116
💡 Pro Tip:
You can use either single quotes (' ') or double quotes (" ") for string literals in expressions.
Recommended style: Single quotes ([MapProperty("Name + ' ' + Surname")]) for better readability.
Supported Expression Types:
+, -, *, /, %==, !=, <, >, <=, >=&&, ||, !condition ? true : false+Property.SubPropertyProperty.ToString()(A + B) * CGenerated Code Example:
The generator creates highly optimized code like this:
// <auto-generated />
public partial class OrderEntity
{
public static implicit operator OrderDto(OrderEntity entity)
{
if(entity == null) return null;
return new OrderDto
{
Price = entity.Price,
Tax = entity.Tax,
Discount = entity.Discount,
NetTotal = entity.Price * (entity.Tax + 100) / 100 - entity.Discount,
Name = entity.Name,
Surname = entity.Surname,
FullName = entity.Name + " " + entity.Surname,
IsActive = entity.IsActive,
StatusText = entity.IsActive ? "Active" : "Passive"
};
}
}
✅ Zero reflection - just pure, optimized C# code!
✅ Fully debuggable - set breakpoints and step through!
✅ Type-safe - compile-time validation!
Scenario: Automatically map nested objects and collections.
using Chd.Mapping.Abstractions;
using System;
using System.Collections.Generic;
[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; }
}
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 collection mapping!
OrderEntity entity = dto;
Console.WriteLine($"Order #{entity.OrderId} - {entity.CustomerName}");
Console.WriteLine("Products:");
foreach (var p in entity.Products)
Console.WriteLine($" {p.Code}: {p.Quantity}x @ ${p.Price}");
}
}
Console Output:
Order #3 - Acme Corp
Products:
A123: 2x @ $49.99
B456: 5x @ $29.99
✅ Nested objects mapped automatically!
✅ Collections supported: List<T>, IEnumerable<T>, arrays, etc.
✅ Deep nesting works recursively!
All mapping code is standard C# and fully debuggable:
View Generated Files:
obj/Debug/netX.X/generated/ folderSet Breakpoints:
implicit operator methodsIntelliSense Support:
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
};
}
Generated Code is:
public string StatusText { get; set; }
public bool IsActive { get; set; }
}
class Program { static void Main() { OrderDto dto = new OrderDto() { Price = 100, Tax = 18, Discount = 2, Name = "Mehmet", Surname = "Yoldaş", IsActive = true }; OrderEntity entity = dto; dto = entity; Console.WriteLine($"NetTotal: {dto.NetTotal}"); // 116 Console.WriteLine($"FullName: {dto.FullName}"); // Mehmet Yoldaş Console.WriteLine($"StatusText: {dto.StatusText}"); // Active } }
**Console Output:**
NetTotal: 116 FullName: Mehmet Yoldaş StatusText: Active
> **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")]`.
---
**Generated Code Example:**
When building the above example, the generator creates code similar to this:
```csharp
// <auto-generated />
namespace Mapping.Test
{
public partial class OrderEntity
{
public static implicit operator global::Mapping.Test.OrderDto(OrderEntity entity)
{
if(entity == null) return null;
return new OrderDto {
Price = entity.Price,
Tax = entity.Tax,
Discount = entity.Discount,
NetTotal = entity.Price *(entity.Tax+100)/100 - entity.Discount,
Name = entity.Name,
Surname = entity.Surname,
FullName = entity.Name + " " + entity.Surname,
IsActive = entity.IsActive,
StatusText = entity.IsActive ? "Active" : "Passive"
};
}
}
}
Therefore, you can debug and step through the generated mapping logic as needed. Runtime performance is equivalent to hand-written code. There is no reflection or dynamic code involved.None of the mapping logic is executed at runtime; everything is pre-compiled. Runtime errors due to mapping issues are eliminated.
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
/obj or /Generated folders.public static implicit operator UserEntity(UserDto dto)
{
if (dto == null) return null;
return new UserEntity
{
Id = dto.Id,
Name = dto.Name,
// ... other properties
};
}
| 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.
partial.[MapTo(typeof(TargetType))] on your DTOs.[MapProperty("...")] for calculated or custom-mapped properties.[MapProperty] attribute only supports a single string parameter: use either the target property name or a full C# expression.[MapTo] or compatible structure.[MapTo] must be declared as partial.
partial, you’ll see a build-time diagnostic error (MAP001):partial keyword is automatically added to your class declaration:
// Incorrect:
[MapTo(typeof(Entity))]
public class MyDto { ... }
// Fixed:
[MapTo(typeof(Entity))]
public partial class MyDto { ... }
partial to your class declaration (e.g., public partial class ...).dotnet clean && dotnet build). Check generated sources in /obj.[MapTo] and [MapProperty] are spelled correctly, and property names are valid./obj/Debug/net*/*Mapping*.g.cs (or your IDE’s generated files node) to inspect all mapping operator code.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.
Contributions, issues and feature requests are welcome!
Check issues page or submit a pull request.
This repository contains examples of how to use the Library.Mapping package in different scenarios, including DTO-Entity mapping, operator injection, and performance benchmarks.
For issues, feature requests, or contributions, please visit the GitHub repository