Skip to content

Extremely fast and lightweight minimalistic object mapper generated on the fly

License

Notifications You must be signed in to change notification settings

DedAnton/NextGenMapper

Repository files navigation

License: MIT GitHub release (latest by date including pre-releases) donate

Extremely fast and lightweight minimalistic object mapper generated on the fly

NextGenMapperDemo.mov

Key features

  • Generation of mapping methods on the fly
  • Reflection and expression trees are not used
  • Performance like a hand-written mapper
  • Minimum memory allocation
  • Does not increase application startup time
  • No dependencies in the final assembly
  • No third party tools and IDE dependencies
  • Static analysis support
  • Code navigation support
  • Easy to debug
  • No attributes and fluid API

NextGenMapper is a tool that just solves a problem and tries not to create new ones

Usage

Add using NextGenMapper and call the Map extension method on the object you want to map

using NextGenMapper;

var source = new Source("Anton", 25);

var destination = source.Map<Destination>();

Console.WriteLine(destination);

record Source(string Name, int Age);
record Destination(string Name, int Age);

To customize the mapping of certain properties, call the MapWith method and pass the value of the overridden property as an argument

using NextGenMapper;

var source = new Source("Anton", "Ryabchikov", 25);

var destination = source.MapWith<Destination>(name: source.FirstName + ' ' + source.LastName);

Console.WriteLine(destination);

record Source(string FirstName, string LastName, int Age);
record Destination(string Name, int Age);

In order for NextGenMapper to use your mapping when mapping other objects, you need to create a partial class Mapper in the NextGenMapper namespace and add the Map method with your implementation to it

namespace NextGenMapper;

internal static partial class Mapper
{
    internal static Destination Map<To>(this Source source) 
        => source.MapWith<Destination>(name: source.FirstName + ' ' + source.LastName);
}

The following collection types are currently supported: List<T>, Array<T>, ICollection<T>, IEnumerable<T>, IList<T>, IReadOnlyCollection<T>, IReadOnlyList<T>, ImmutableArray<T>, ImmutableList<T>, IImmutableList<T>

var sourceCollection = new List<Source> { new("Anton", 25) };

var destination = sourceCollection.Map<List<Destination>>();

Enums can also be mapped

var source = Source.EnumValue;

var destination = source.Map<Destination>();

Projection for IQueryable supported

_dbContext.Users.Project<UserDestination>().ToList();

Note: Due to the use of new technology, some versions of Visual Studio can sometimes experience problems with syntax highlighting if IntelliCode says an error, but the solution was build without errors is to simply restart Visual Studio

Installation

Install from the package manager console:

PM> Install-Package NextGenMapper -prerelease

Or from the .NET CLI as:

dotnet add package NextGenMapper --prerelease

How it works?

NextGenMapper uses the new C# language feature - Source Code Generators. You can describe the work of the Source Code Generator in the following steps:

  1. Code compiles
  2. The source code generator analyzes the assembly
  3. Generates new code based on analysis
  4. Compiles the new code and adds it to the assembly

This is how the method that is called initially looks like:

internal static To Map<To>(this object source) => throw new InvalidOperationException($""Error when mapping {source.GetType()} to {typeof(To)}, mapping function was not found. Create custom mapping function."");

When we call it, the generator analyzes this call and generates a mapping function:

internal static Destination Map<To>(this Source source) 
    => new Destination(source.Name, source.Age);

The trick is that the method signatures are identical, but the generated method has more specific parameters and fits better, so it is called (this behavior is described in the specification)

Status

At the moment, all the main functionality has been added. But the work isn't over yet.

All tasks can be viewed on the project board

Thanks

Thanks JetBrains for support (Licenses for Open Source Development)

image