Choosing the Right .NET Core Object Mapper: A Comparative Guide

Ramy Elnaghy
5 min readOct 12, 2023

--

Object mapping is a fundamental practice in software development, enabling us to convert one type of object to another in a programmatic way. This article aims to compare seven different mapping techniques used in .NET Core: Manual Mapper, Mapperly, Mapster, AutoMapper, TinyMapper, and Implicit Operator.

Comparison Criteria

The comparison will pivot around the following criteria:

  1. Ease of Use: The learning curve and how quickly a developer can get up and running.
  2. Flexibility: The ability to handle complex mapping scenarios.
  3. Performance: The time and computational resources consumed to perform the mapping.

Let’s get started

Create a .Net Core Console Application.

let’s go ahead and create two model classes named Product and ProductModelView.

Product Model
ProductModelView

Mapping Strategies and Libraries

Manual Mapper

  1. Ease of Use: Using manual mappers is often straightforward but can become increasingly complex with complicated objects. No external dependencies.
  2. Flexibility: Extremely flexible as developers have control over every aspect of the mapping.
  3. Performance: Usually the fastest since there is no additional computational overhead.

Let’s define the ManualMapper class.

ManualMapper

In the ManualMapper class, the Map function manually transforms a Product object into a ProductModelView object. It does this by individually transferring each property from the Product to its corresponding property in ProductModelView.

Mapperly

  1. Ease of Use: Moderate difficulty. Requires initial setup to define mapping rules, and hence, a slight learning curve.
  2. Flexibility: Highly customizable. Supports conditional mapping and custom conversion functions.
  3. Performance: Generally high, especially when using simple mappings. Performance can vary with the complexity of the custom logic.

To install the NuGet package.

dotnet add package Riok.Mapperly --version 3.2.0

Let’s define the MapperlyMapper class.

MapperlyMapper

[Mapper(EnumMappingStrategy = EnumMappingStrategy.ByName)]: This attribute indicates that this is a Mapperly mapping configuration. The EnumMappingStrategy.ByName specifies that any enum values will be mapped based on their names rather than their numeric values.

public static partial ProductModelView ProductToProductModelView(Product product);: Declares a static partial method named ProductToProductModelView. This method takes a Product object as an argument and returns a ProductModelView object. The actual mapping logic would be automatically generated by Mapperly based on this method signature and any applied configuration.

Mapster

  1. Ease of Use: Simple for most scenarios. Offers attribute-based mappings out of the box.
  2. Flexibility: Excellent. It supports a wide range of mappings, including nested and complex object types.
  3. Performance: Built for high performance, especially in simple-to-moderate mapping scenarios.

To install the NuGet package.

dotnet add package Mapster --version 7.4.1-pre01

Let’s define the MapsterMapper class.

MapsterMapper

return TypeAdapter.Adapt<ProductModelView>(product);: This line does the actual mapping. Mapster's TypeAdapter.Adapt<T> function is used to convert the given Product object into a ProductModelView object.

AutoMapper

  1. Ease of Use: Moderate. Powerful but requires initial setup and learning.
  2. Flexibility: Extremely flexible. Can handle complex object graphs, flattening, and other advanced scenarios.
  3. Performance: Varies. Typically slower than manual methods but acceptable in most scenarios.

To install the NuGet package.

dotnet add package AutoMapper --version 12.0.1

Let’s define the AutoMapper class.

AutoMapper
var mapperConfig = new MapperConfiguration(cfg =>
{
cfg.CreateMap<Product, ProductModelView>();
});

A new MapperConfiguration object is instantiated.

CreateMap<Product, ProductModelView>() defines a mapping from Product to ProductModelView. AutoMapper will try to map properties with the same name and compatible types automatically.

var mapper = mapperConfig.CreateMapper();

The CreateMapper() method creates a mapper object based on the earlier configuration. This object will handle the actual data transformation.

return mapper.Map<ProductModelView>(product);

The Map function takes the Product object (product) and returns a new ProductModelView object with the properties set based on the mapping configuration.

TinyMapper

  1. Ease of Use: Simple. Designed to be straightforward and easy to set up.
  2. Flexibility: Limited customization options compared to other libraries, but sufficient for simple mappings.
  3. Performance: High. Optimized for speed in straightforward mapping scenarios.

To install the NuGet package.

dotnet add package TinyMapper --version 3.0.3

Let’s define the TinyMapper class.

TinyMapper

TinyMapper.Bind<Product, ProductModelView>();: This line sets up the mapping relationship between the Product and ProductModelView classes. It tells TinyMapper how to convert an object of type Product to an object of type ProductModelView. This is generally done once to configure the mapping rules.

return TinyMapper.Map<ProductModelView>(product);: This line performs the actual mapping. It takes an object of type Product as input and returns a new object of type ProductModelView that has the same values for all the corresponding properties.

Implicit Operator

  1. Ease of Use: Fairly simple but requires explicit operator definition in code.
  2. Flexibility: Limited to what the developer manually codes into the operator functions.
  3. Performance: Generally high as it is almost equivalent to manual mapping.

Let’s define the ImplicitOperatorMapper class.

Implicit Operator
ImplicitOperatorMapper

Here, you’ll notice the simplest method for converting a Product object to its corresponding ProductModelView. This is made possible because we've set up an implicit operator inside the Product model.

Performance and Benchmarks

Let’s create a benchmark class and call it MappersBenchmark. Inside this class, we'll make a Product object and name it prod. To get prod up and running with some initial values, we'll add a void method named Setup and do all the assigning in there.

Next, we’ll extend the class by incorporating the mapping functions for the mappers. We’ll decorate it using the Benchmark attribute to each of these functions to enable the Benchmarking process.

Inside the Program class, let's fire up BenchmarkRunner to execute the MappersBenchmark.

Performance Test Results

From the benchmark scores, it’s clear that Manual mapping takes the lead in speed, followed by Mapperly. The implicit operator also puts up some pretty solid numbers. Considering the pros and cons we’ve discussed for each, along with these performance metrics, you’ve got all you need to pick the mapper that’s the best fit for your project.

Happy Coding!

--

--