Chd.Mapping.Roslyn
8.3.7
dotnet add package Chd.Mapping.Roslyn --version 8.3.7
NuGet\Install-Package Chd.Mapping.Roslyn -Version 8.3.7
<PackageReference Include="Chd.Mapping.Roslyn" Version="8.3.7" />
<PackageVersion Include="Chd.Mapping.Roslyn" Version="8.3.7" />
<PackageReference Include="Chd.Mapping.Roslyn" />
paket add Chd.Mapping.Roslyn --version 8.3.7
#r "nuget: Chd.Mapping.Roslyn, 8.3.7"
#:package Chd.Mapping.Roslyn@8.3.7
#addin nuget:?package=Chd.Mapping.Roslyn&version=8.3.7
#tool nuget:?package=Chd.Mapping.Roslyn&version=8.3.7
Chd.Mapping.Roslyn – High-Performance, Expression-Aware DTO Mapper
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 object mapper for .NET with expression-based mapping support—built on Roslyn source generators for maximum performance and type safety!
📑 Table of Contents
- About
- Why This Package?
- Features
- Installation
- Quick Start
- Usage Examples
- IDE Experience
- Performance
- Comparison with Other Mappers
- Best Practices
- Limitations
- Troubleshooting
- Viewing Generated Code
- FAQ
- Examples Repository
- Contributing
- Authors
- Acknowledgments
🧐 About
Chd.Mapping.Roslyn 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 this package
- 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.,
[MapProperty("Price + Tax - Discount")]) - No runtime logic. Just generated code: (e.g.,
NetTotal = entity.Price + entity.Tax - entity.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
- Live IntelliSense inside
[MapProperty("…")]— counterpart property names are suggested while you type - Roslyn analyzers for instant feedback in the editor:
MAP001— class decorated with[MapTo]is missing thepartialmodifier (ships with a one-click code fix)MAP002— unknown identifier inside[MapProperty("…")], reported on the attribute itself
- One-click code fix for
MAP002— “Replace ‘OldName’ with ‘NewName’ in [MapProperty] expressions” updates only the offending identifier inside the literal (single-quoted string segments and other identifiers are preserved) - Rename-aware refactoring — after
F2-renaming a property on the counterpart type, place the caret on the new name andCtrl+.offers “Rename ‘OldName’ to ‘NewName’ in [MapProperty] expressions” across the whole solution - Defensive generator — when an expression contains an unknown identifier, that single line is omitted from the generated operator instead of breaking the build inside
*.g.cs - Global-namespace classes are fully supported (no
namespace <global namespace>block is emitted)
📦 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.
Requirements:
- .NET Standard 2.0+
- .NET Core 3.1+
- .NET 5, 6, 7, 8, 9+
- C# 8.0 or higher
🚀 Quick Start
using Chd.Mapping.Abstractions;
namespace ChdRoslynMappingTest
{
// 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!
internal class Program
{
static void Main(string[] args)
{
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!
💡 Usage Examples
1. Basic Mapping
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
2. Advanced Property Mapping
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
Expression-Based Mapping
🔥 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:
- ✅ Mathematical operations:
+,-,*,/,% - ✅ Comparison:
==,!=,<,>,<=,>= - ✅ Logical:
&&,||,! - ✅ Ternary operator:
condition ? true : false - ✅ String concatenation:
+ - ✅ Property access:
Property.SubProperty - ✅ Method calls:
Property.ToString() - ✅ Parentheses for grouping:
(A + B) * C
Generated 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!
3. Nested and Collection Mapping
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!
4. Debugging and Maintainability
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 generated
implicit operatormethods - Step through mapping code line by line
- Inspect variable values
- Navigate to generated
IntelliSense Support:
- Full code completion
- Navigate to definition (F12)
- Find all references
- Refactoring 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:
- ✅ Readable and maintainable
- ✅ Optimized by the C# compiler
- ✅ No runtime overhead
- ✅ Type-safe at compile time
Tip — making generated files visible on disk: add the following to the consuming project so the generated
.g.csfiles are written next to your source and are clickable from Error List:<PropertyGroup> <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles> <CompilerGeneratedFilesOutputPath>Generated</CompilerGeneratedFilesOutputPath> </PropertyGroup> <ItemGroup> <Compile Remove="Generated\**" /> </ItemGroup>After the next build, generated mapping code lives under
Generated/Chd.Mapping.Roslyn/MappingGenerator/…and…/CollectionMappingGenerator/….
🛠 IDE Experience
In addition to the source generator, the package ships with a Roslyn CompletionProvider, two DiagnosticAnalyzers, two CodeFixProviders and one CodeRefactoringProvider, so most mapping mistakes become editor errors before you even build — and the cleanup after a rename is one click away.
IntelliSense inside [MapProperty("…")]
Place the caret between the quotes of [MapProperty("|")], press Ctrl+Space, and the IDE lists the public instance properties of the counterpart class (the one referenced by [MapTo(typeof(...))]). The same names are valid inside expressions such as Name + ' ' + Surname or IsActive ? 'Active' : 'Passive', because the generator rewrites those identifiers as entity.Name, entity.Surname, entity.IsActive etc., where entity is of the counterpart type.
Analyzer Diagnostics
| ID | Severity | What it catches |
|---|---|---|
MAP001 |
Error | A class decorated with [MapTo] is missing the partial modifier. Ships with a code fix. |
MAP002 |
Error | An identifier used inside a [MapProperty("…")] expression is not a public property of the counterpart type. The squiggle points at the exact word inside the attribute string. |
MAP002 example:
[MapTo(typeof(OrderEntity))]
public partial class OrderDto
{
// OrderEntity has no "Surnam" property.
[MapProperty("Name + ' ' + Surnam")] // ← red squiggle on Surnam
public string FullName { get; set; }
}
MAP002: 'Surnam' is not a public property of 'OrderEntity'. The expression in [MapProperty] must reference properties of the counterpart type.
Double-clicking the entry in Error List navigates straight to the typo — not to a *.g.cs file. Identifiers inside single-quoted segments (e.g. the Active / Passive in "IsActive ? 'Active' : 'Passive'") and C# reserved tokens (true, false, null, …) are not flagged.
When MAP002 triggers, the generator also defensively skips that single map line, so the build does not break inside generated files; you only see one clear error on the attribute. Fix the typo and the line reappears in the next build.
Code Fix: Add partial Modifier
MAP001 is paired with MapToMustBePartialCodeFixProvider. Place the caret on the squiggled class name, press Ctrl+. (Quick Actions) and choose Add 'partial' modifier — Roslyn rewrites the declaration in place:
// Before
[MapTo(typeof(Entity))]
public class MyDto { ... }
// After (one click)
[MapTo(typeof(Entity))]
public partial class MyDto { ... }
Code Fix: Replace Stale Identifier inside [MapProperty]
MAP002 is paired with MapPropertyExpressionCodeFixProvider. When an expression references a property that no longer exists on the counterpart type (typically because the property was renamed), place the caret on the squiggle and press Ctrl+.. The lightbulb lists every public property of the counterpart and prioritises names that already exist on the counterpart but not on the declaring DTO — the freshly renamed property is almost always at the top.
[MapTo(typeof(OrderEntity))]
public partial class OrderDto
{
public decimal Price { get; set; }
public decimal Tax { get; set; }
public decimal Discount { get; set; }
// OrderEntity.Price was renamed to OrderEntity.Pricex.
// MAP002 squiggles ONLY the bare word `Price` inside the literal.
[MapProperty("Price * (Tax + 100) / 100 - Discount")]
public decimal NetTotal { get; set; }
}
Picking “Replace ‘Price’ with ‘Pricex’ in [MapProperty] expressions” rewrites the literal to:
[MapProperty("Pricex * (Tax + 100) / 100 - Discount")]
Word-boundary matching guarantees that only the standalone identifier is replaced — Tax, Discount, parentheses, math operators and any single-quoted segments (e.g. 'Active' / 'Passive') are left untouched. The same fix is applied to every other [MapProperty] on the same DTO that references the stale name.
Refactoring: Propagate Property Rename into [MapProperty] Expressions
Visual Studio's built-in F2 rename only updates real C# symbol references, so [MapProperty("...")] strings stay stale after you rename a property on the counterpart type. MapPropertyRenameRefactoringProvider closes that gap as a refactoring on the property identifier itself.
Workflow:
- Open the counterpart type (e.g.
OrderEntity) andF2-renamePricetoPricex. C# symbol references update;[MapProperty]strings do not. - The caret is still sitting on
Pricex. PressCtrl+.. - The Quick Actions menu offers “Rename ‘Price’ to ‘Pricex’ in [MapProperty] expressions”.
- One click rewrites every DTO across the whole solution that declares
[MapTo(typeof(OrderEntity))], replacing only the standalonePriceidentifier inside each[MapProperty("…")]literal. A single Undo (Ctrl+Z) reverts all of those edits at once.
How the old name is inferred: the refactoring walks the solution for every class with [MapTo(typeof(<this counterpart>))], scans their [MapProperty] expressions for identifiers that no longer exist on the counterpart, and ranks the “stale” names by similarity to the new name. The most likely rename target (typically the one you just renamed from) appears first; additional stale identifiers — if any — get their own lightbulb entries.
Why a refactoring, not an automatic rewrite during F2: Roslyn's inline-rename pipeline (IInlineRenameService / IRenameRewriter) is internal to the C# language service and is not extensible from a NuGet-shipped analyzer. The refactoring is the supported, predictable substitute — same single keystroke (Ctrl+.) right after F2, no surprises if the rename was intentional (e.g. delete-then-add of a same-named property), and a clean undo group.
🚦 Performance
| 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, see /benchmarks.
Key Takeaway:
Chd.Mapping.Roslyn mapping is as fast as hand-written code, and dramatically faster than reflection-based mappers.
⚖ Comparison with Other Mappers
| Capability | AutoMapper | Mapster | Chd.Mapping.Roslyn |
|---|---|---|---|
| Mapping time | Runtime (reflection / IL emit) | Runtime + optional codegen | Compile time only |
| Configuration / profiles | Required | Optional | None — attributes only |
| Startup scanning | Yes | Yes (when reflection mode) | No |
| Debuggable mapping code | ❌ (IL or expression trees) | Partial | ✅ Plain C# you can step through |
| Expression-based derived properties | Via .ForMember(... => Expression) |
Via .Map(...) config |
✅ [MapProperty("Price + Tax")] |
| Nested objects | ✅ | ✅ | ✅ |
| Collections | ✅ | ✅ | ✅ |
| Compile-time validation | ❌ (runtime) | Partial (codegen mode) | ✅ C# compiler + MAP001 / MAP002 |
| IntelliSense in mapping config | ❌ | ❌ | ✅ CompletionProvider inside [MapProperty] |
| Analyzer for typos | ❌ | ❌ | ✅ MAP002 on the attribute |
Quick fix for missing partial |
n/a | n/a | ✅ MAP001 + Code Fix |
| Quick fix for stale identifier in mapping expression | ❌ | ❌ | ✅ MAP002 + Code Fix |
| Refactoring: propagate property rename into mapping strings | ❌ | ❌ | ✅ Ctrl+. on the renamed property |
| Reflection at runtime | Yes | Yes (default) | Never |
| Cold start cost | High | Medium | Zero |
| Trim / AOT friendly | ⚠ Partial | ⚠ Partial | ✅ Yes — no reflection |
| External runtime DLL | AutoMapper.dll |
Mapster.dll |
None — only Chd.Mapping.Abstractions (attributes) |
The differentiator of Chd.Mapping.Roslyn is not raw speed alone (any compile-time mapper is fast); it is the end-to-end IDE experience — completion, analyzers and code fixes all ship in the same package.
🏆 Best Practices and 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
- MAP002: '<name>' is not a public property of '<Counterpart>'
- Solution: fix the spelling, add the missing property to the counterpart type, or remove the
[MapProperty]if it is no longer needed. Identifiers inside single-quoted segments (e.g.'Active') and reserved tokens (true,false,null) are intentionally not flagged.
- Solution: fix the spelling, add the missing property to the counterpart type, or remove the
- Build error inside
*.g.cs: Should not happen anymore —MAP002is emitted instead of broken generated code, and the offending line is omitted from the operator. If you still see one, please file an issue with the failing snippet. - IntelliSense suggestions do not appear inside
[MapProperty("")]: Make sure your IDE uses Roslyn ≥ 4.8 (Visual Studio 2022 17.8+, Rider 2024.1+), and reload the consuming project (Solution Explorer → right-click → Unload / Reload) so the IDE picks up the analyzer DLL. - Squiggle remains after the issue is fixed: Roslyn caches diagnostics aggressively. Touch the file (add and remove a space) or Build → Clean + Rebuild. As a last resort, close the solution and clear the IDE component-model cache.
- Lightbulb still offers the old code fix after the package was updated: Visual Studio loads analyzer DLLs into the IDE process and does not unload them on rebuild. Close the solution (or restart VS) so the updated
Chd.Mapping.Roslyn.dllis picked up; otherwise the lightbulb keeps running the cached previous version. Ctrl+.on a renamed property doesn’t offer “Rename … in [MapProperty] expressions”: verify that (a) the property’s containing type is referenced via[MapTo(typeof(...))]from at least one class in the solution, and (b) those DTOs still contain[MapProperty("…")]strings holding the old name. The refactoring only appears when there is real work to do.- Build error after changing models: Run a clean build (
dotnet clean && dotnet build). Check generated sources in/obj(or in yourGenerated/folder ifEmitCompilerGeneratedFilesis enabled). - 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.
🧪 Examples Repository
This repository contains examples of how to use the Library.Mapping package in different scenarios, including DTO-Entity mapping, operator injection, and performance benchmarks.
👤 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.5)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.