Este projeto tem por finalidade apresentar os resultados de um benchmark detalhado entre dois métodos de mapeamento de objetos no .NET 8: o uso de operators nativos da linguagem (manual mapping) e a biblioteca Mapster. A análise leva em consideração desempenho, legibilidade, manutenção, curva de aprendizado, complexidade e extensibilidade.
- .NET 8
- Mapster
- BenchmarkDotNet
- Bogus
BenchmarkTests: Contém os benchmarks principais, comoObjectMappingBenchmark.cs,ObjectMappingListBenchmark.cseOrderMappingBenchmark.cs. Cada arquivo mede cenários diferentes de mapeamento entre entidades e DTOs.Config: Contém a classeBenchmarkConfig.cs, responsável pela configuração do BenchmarkDotNet (ex: colunas, ordenação, warmups, etc).Dtos: Contém os modelos de transferência de dados (Data Transfer Objects), comoUserDto,OrderDto,CustomerDto, entre outros.Entities: Contém os modelos de domínio utilizados como origem dos mapeamentos, incluindoUser,Order,Address, etc.Mapping: Contém o arquivoMapsterConfig.cs, onde é feita a configuração global dos mapeamentos personalizados do Mapster.Program.cs: Ponto de entrada do projeto. Inicializa os benchmarks com base na configuração desejada.BenchmarkDotNet.Artifacts/results: Pasta gerada automaticamente com os resultados dos benchmarks executados.
- .NET 8 SDK instalado
- Terminal, PowerShell ou Bash
Execute o projeto no modo Release (requisito do BenchmarkDotNet):
dotnet run -c ReleaseUse o parâmetro --filter para rodar apenas um benchmark:
dotnet run -c Release --filter *OrderMappingBenchmark*dotnet run -c Release --listAo final da execução, o BenchmarkDotNet gera uma tabela contendo:
- Method: Nome do benchmark
- Mean: Tempo médio
- Error / StdDev: Erro padrão e desvio padrão
- Allocated: Quantidade de memória alocada
- Ops/sec: Operações por segundo
Os arquivos de resultado também ficam salvos em BenchmarkDotNet.Artifacts/results.
- Mapster é mais rápido tanto para mapeamento de entidades quanto DTOs, mesmo em estruturas complexas.
- Operators têm desempenho consistente, mas não tão otimizado quanto os geradores de código do Mapster.
- Operator exige código duplicado e detalhado, tornando-se custoso conforme o modelo cresce.
- Mapster reduz boilerplate com configurações globais e expressivas.
- Operators: trivial para qualquer desenvolvedor C#.
- Mapster: requer compreensão da API, configuração estática/dinâmica e uso de source generators.
- Operator é mais explícito e claro.
- Mapster favorece concisão, mas pode ocultar lógica de transformação.
- Operator: fácil de isolar, sem dependências externas.
- Mapster: requer testes de configurações, especialmente quando definidas por perfil.
- Mapster permite reutilizar configurações, suporta projeções LINQ, uso com EF Core e outros cenários.
- Operator pode ficar verboso e duplicado em várias camadas.
- Melhor performance para grandes volumes.
- Redução significativa de boilerplate.
- Suporte a source generators.
- Configurações reutilizáveis e flexíveis.
- Integração com
IServiceCollectionpara DI.
- Aumento da curva de aprendizado, especialmente para configurações mais complexas.
- Possível ocultamento de lógica, dificultando debugging.
- Dependência de uma biblioteca externa (risco de abandono, bugs, incompatibilidades futuras).
Com base no benchmark e na análise qualitativa:
Recomenda-se a adoção do Mapster para projetos com alto volume de transformação de objetos, grande complexidade de modelos, ou necessidade de manutenção a longo prazo.
Para projetos pequenos ou que demandam extrema clareza no código, o uso de operators pode ser mantido.
Roberto Camara
Software Architect & Senior Software Engineer
.NET, C#, Kafka, RabbitMQ, Azure Service Bus, Docker, Cloud, Microservices