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.
2025-07-21 13:48:02 -04:00
2025-07-21 13:48:02 -04:00
2025-07-21 13:48:02 -04:00
2025-07-21 13:48:02 -04:00
2025-07-21 13:48:02 -04:00
2025-07-21 13:48:02 -04:00
2025-07-21 13:48:02 -04:00
2025-07-21 13:48:02 -04:00
2025-07-21 13:48:02 -04:00
2025-07-21 13:48:02 -04:00

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 code generator or 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

[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

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

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; }
}
Description
No description provided
Readme 69 KiB
Languages
C# 100%