1
0
This repository has been archived on 2025-10-14. You can view files and clone it, but cannot push or open issues or pull requests.
Files
MapperSourceGenSample/README.md
2025-07-21 13:48:02 -04:00

118 lines
4.0 KiB
Markdown

# Mapper Source Generator Example
This project demonstrates how you can use incremental source generators in C# to generate domain transfer objects (DTOs)
and mapping classes from a POCO.
> [!WARNING]
> This is a sample project and not intended for production use. It is meant to illustrate the concept of using source generators.
> Please look into using either [mapster's](https://github.com/MapsterMapper/Mapster) code generator or [mapperly](https://github.com/riok/mapperly) instead.
## Requirements
- .NET 8.0 SDK
## What's Included
- `MapperSourceGen`: The main project that contains the attributes for decorating classes and properties for the source generator.
- `MapperSourceGen.Sample`: A sample class library that demonstrates the use of the source generator.
- `MapperSourceGen.SourceGenerator`: The source generator that generates DTOs and mapping classes.
- `MapperSourceGen.SourceGenerator.Tests`: Unit tests for the source generator to ensure it works as expected (snapshot testing).
Feel free to inspect the `.csproj` files for the projects to see how they are set up and how the source generator is integrated.
> [!NOTE]
> The source files emitted by the source generator will be under `Dependencies -> .NET 8.0 -> Source Generators` in the `MapperSourceGen.Sample` project if using Rider.
## Purpose
As projects grow, the need for transferring data between layers (like from a database to a UI) becomes essential.
However, with that comes the additional complexity of maintaining DTOs and mapping classes. One of the ways this can be
solved is by using source generators to automate the creation of these classes.
Source generators provide the ability to generate code at compile time, which can help reduce boilerplate code and improve maintainability
and reduce the reliance on expensive reflection-based mapping.
## How It Works
The project **MapperSourceGen.SourceGenerator** contains a source generator that scans for classes decorated with the `GenerateMapperAttribute`.
When it finds such a class, it generates a DTO and a mapping class for it.
### Example
Let's say you have a class `Order` that you want to generate a DTO and mapping class for. You would decorate it with the `GenerateMapperAttribute` like this:
**Order.cs**
```csharp
[Mapper]
public sealed class Order
{
[MapAlias("EntityId")] // renames Id to EntityId in the DTO
public Guid Id { get; set; }
public Guid? CustomerId { get; set; }
[MapAlias("OrderId")] // renames IncrementId to OrderId in the DTO
public int IncrementId { get; set;}
public DateTimeOffset Created { get; set;}
public DateTimeOffset? Updated { get; set; }
[MapIgnore] // this property will not be included in the DTO or mapper
public string TransactionId { get; set; }
}
```
The source generator will then generate a DTO class `OrderDto` and a mapping class `OrderMapper` that looks like this:
**OrderMapper.g.cs**
```csharp
public sealed partial class OrderMapper
{
public static Order ToModel(OrderDto source)
{
ArgumentNullException.ThrowIfNull(source);
return new Order()
{
Id = source.EntityId,
CustomerId = source.CustomerId,
IncrementId = source.OrderId
Created = source.Created,
Updated = source.Updated
}
}
public static OrderDto ToDto(Order source)
{
ArgumentNullException.ThrowIfNull(source);
return new OrderDto()
{
EntityId = source.Id,
CustomerId = source.CustomerId,
OrderId = source.IncrementId,
Created = source.Created,
Updated = source.Updated
}
}
}
```
**OrderDto.g.cs**
```csharp
public sealed partial class OrderDto
{
public Guid? CustomerId { get; set; }
public Guid EntityId { get; set; }
public int OrderId { get; set; }
public DateTimeOffset Created { get; set; }
public DateTimeOffset? Updated { get; set; }
}
```