eQuantic Mapper
Object mapping utilities and extensions
Version: 2.0.0
Downloads: 19K+
Status: stable
Category: utilities
Installation
dotnet add package eQuantic.Mapper
Overview
eQuantic.Mapper est une bibliothèque de mappage d'objets haute performance pour .NET qui élimine la surcharge de reflection en générant du code de mappage au moment de la compilation à l'aide de générateurs de code source. Elle offre des fonctionnalités puissantes pour les mappages complexes de propriétés, les agrégations, le mappage conditionnel et les transformations bidirectionnelles avec d'excellentes caractéristiques de performance.
Contrairement aux mappeurs traditionnels qui dépendent de la reflection à l'exécution, eQuantic.Mapper utilise des analyseurs Roslyn pour générer du code de mappage optimisé pendant la compilation, résultant en zéro surcharge de reflection et des performances supérieures. La bibliothèque prend en charge des scénarios avancés incluant l'agrégation de propriétés, le mappage conditionnel basé sur des conditions d'exécution, les mappages sensibles au contexte et les mappages bidirectionnels.
La bibliothèque est conçue pour les applications d'entreprise où la performance, la sécurité des types et la maintenabilité sont critiques. Elle s'intègre parfaitement avec les conteneurs d'injection de dépendances et fournit de riches options de personnalisation via des attributs et des classes partielles, permettant aux développeurs de créer des scénarios de mappage sophistiqués tout en maintenant un code propre et lisible.
Quick Start
1. Installation et Configuration
Installez à la fois le package noyau du mappeur et le générateur de code source pour activer la génération de code au moment de la compilation.
// Installer via Package Manager Console
Install-Package eQuantic.Mapper
Install-Package eQuantic.Mapper.Generator
// Ou via .NET CLI
dotnet add package eQuantic.Mapper
dotnet add package eQuantic.Mapper.Generator
// Déclarations using de base
using eQuantic.Mapper;
using eQuantic.Mapper.Attributes;2. Définissez Vos Modèles
Créez vos modèles source et destination. Utilisez des attributs pour configurer des scénarios de mappage avancés comme l'agrégation de propriétés et le mappage conditionnel.
// Modèle source
public class UserSource
{
public string FirstName { get; set; } = string.Empty;
public string LastName { get; set; } = string.Empty;
public int Age { get; set; };
public decimal Salary { get; set; };
public decimal Bonus { get; set; };
public bool IsActive { get; set; };
}
// Modèle destination avec agrégation
public class UserDestination
{
// Agrégation de propriétés
[MapFrom(typeof(UserSource),
new[] { nameof(UserSource.FirstName), nameof(UserSource.LastName) },
MapperPropertyAggregation.ConcatenateWithSpace)]
public string FullName { get; set; } = string.Empty;
// Agrégation numérique
[MapFrom(typeof(UserSource),
new[] { nameof(UserSource.Salary), nameof(UserSource.Bonus) },
MapperPropertyAggregation.Sum)]
public decimal TotalIncome { get; set; };
// Mappage conditionnel
[MapFrom(typeof(UserSource), nameof(UserSource.Age))]
[MapWhen(nameof(UserSource.IsActive))]
public int? DisplayAge { get; set; };
// Propriétés mappées automatiquement (par nom)
public int Age { get; set; }
}3. Créez Votre Mappeur
Définissez une classe partielle avec l'attribut Mapper. Le générateur de code source créera l'implémentation automatiquement.
// Mappeur généré automatiquement
[Mapper(typeof(UserSource), typeof(UserDestination))]
public partial class UserMapper : IMapper
{
// Optionnel : Ajouter une logique personnalisée
partial void AfterConstructor()
{
OnBeforeMap += (sender, args) =>
{
// Logique de prétraitement
Console.WriteLine($"Mappage utilisateur : {args.Source.FirstName}");
};
OnAfterMap += (sender, args) =>
{
// Logique de post-traitement
if (args.Destination.Age < 18)
{
args.Destination.FullName = $"Mineur : {args.Destination.FullName}";
}
};
}
}4. Configurez l'Injection de Dépendances
Enregistrez tous les mappeurs dans votre conteneur DI en utilisant la méthode d'extension fournie.
var builder = WebApplication.CreateBuilder(args);
// Enregistrer tous les mappeurs automatiquement
builder.Services.AddMappers();
var app = builder.Build();
// Utiliser dans les contrôleurs ou services
app.MapGet("/users/{id}", async (int id, IMapperFactory mapperFactory) =>
{
var mapper = mapperFactory.GetMapper<UserSource, UserDestination>()!;
var user = await GetUserAsync(id); // Votre logique d'accès aux données
return mapper.Map(user);
});
app.Run();5. Utilisation des Fonctionnalités Avancées
Tirez parti des fonctionnalités avancées comme le mappage bidirectionnel, le mappage sensible au contexte et la logique conditionnelle.
// Mappage bidirectionnel
[Mapper(typeof(UserSource), typeof(UserDestination), MapperDirection.Bidirectional)]
public partial class BidirectionalUserMapper : IMapper { }
// Mappage sensible au contexte
public class MappingContext
{
public bool IncludeSensitiveData { get; set; }
public string UserRole { get; set; } = "User";
}
[Mapper(typeof(UserSource), typeof(UserDestination), typeof(MappingContext))]
public partial class ContextUserMapper : IMapper<UserSource, UserDestination, MappingContext>
{
partial void AfterConstructor()
{
OnAfterMap += (sender, args) =>
{
if (!Context?.IncludeSensitiveData == true)
{
args.Destination.Salary = 0;
}
};
}
}
// Utilisation
var contextMapper = mapperFactory.GetMapper<UserSource, UserDestination, MappingContext>()!;
contextMapper.Context = new MappingContext { IncludeSensitiveData = false, UserRole = "User" };
var result = contextMapper.Map(userSource);API Reference
MapperAttribute
Définit une classe de mappeur pour transformer entre deux types, avec support optionnel de contexte et de direction.
[Mapper(typeof(UserSource), typeof(UserDestination))]
public partial class UserMapper : IMapper
{
// Implémentation générée automatiquement
}
// Avec contexte
[Mapper(typeof(UserSource), typeof(UserDestination), typeof(MappingContext))]
public partial class ContextUserMapper : IMapper<UserSource, UserDestination, MappingContext> { }
// Bidirectionnel
[Mapper(typeof(UserSource), typeof(UserDestination), MapperDirection.Bidirectional)]
public partial class BiMapper : IMapper { }MapFromAttribute
Mappe une propriété destination depuis une ou plusieurs propriétés source avec agrégation optionnelle.
// Mappage simple
[MapFrom(typeof(UserSource), nameof(UserSource.FirstName))]
public string Name { get; set; }
// Agrégation de propriétés
[MapFrom(typeof(UserSource),
new[] { nameof(UserSource.FirstName), nameof(UserSource.LastName) },
MapperPropertyAggregation.ConcatenateWithSpace)]
public string FullName { get; set; }
// Agrégation numérique
[MapFrom(typeof(UserSource),
new[] { nameof(UserSource.Salary), nameof(UserSource.Bonus) },
MapperPropertyAggregation.Sum)]
public decimal TotalIncome { get; set; }MapWhenAttribute
Mappe conditionnellement une propriété basée sur une propriété booléenne ou une expression C#.
// Condition booléenne simple
[MapFrom(typeof(UserSource), nameof(UserSource.Email))]
[MapWhen(nameof(UserSource.IsEmailVisible))]
public string? PublicEmail { get; set; }
// Condition d'expression
[MapFrom(typeof(UserSource), nameof(UserSource.Age))]
[MapWhen("source.Age >= 18", true)]
public int? DisplayAge { get; set; }
// Condition sensible au contexte
[MapFrom(typeof(UserSource), nameof(UserSource.Salary))]
[MapWhen("Context?.IncludeSensitiveData == true", true)]
public decimal? Salary { get; set; }IMapper<TSource, TDestination>
Interface de mappeur de base pour transformer du type source vers le type destination.
public class UserMapper : IMapper<UserSource, UserDestination>
{
public UserDestination? Map(UserSource? source)
{
if (source == null) return null;
return new UserDestination
{
FirstName = source.FirstName,
LastName = source.LastName
};
}
public UserDestination? Map(UserSource? source, UserDestination? destination)
{
// Mapper vers une instance existante
}
}IMapper<TSource, TDestination, TContext>
Interface de mappeur sensible au contexte avec support pour le contexte de mappage.
public class ContextUserMapper : IMapper<UserSource, UserDestination, MappingContext>
{
public MappingContext? Context { get; set; }
public UserDestination? Map(UserSource? source)
{
if (source == null) return null;
var result = new UserDestination();
if (Context?.IncludeSensitiveData == true)
{
result.Salary = source.Salary;
}
return result;
}
}IMapperFactory
Interface factory pour créer et récupérer les instances de mappeur.
// Utilisation avec l'injection de dépendances
public class UserController : ControllerBase
{
private readonly IMapperFactory _mapperFactory;
public UserController(IMapperFactory mapperFactory)
{
_mapperFactory = mapperFactory;
}
[HttpGet("{id}")]
public async Task<UserDto> GetUser(int id)
{
var mapper = _mapperFactory.GetMapper<User, UserDto>()!;
var user = await _userService.GetByIdAsync(id);
return mapper.Map(user);
}
}MapperDirection
Spécifie la direction du mappage pour les mappeurs bidirectionnels.
// Direct seulement (par défaut)
[Mapper(typeof(UserSource), typeof(UserDestination))]
public partial class ForwardMapper : IMapper { }
// Inverse seulement
[Mapper(typeof(UserSource), typeof(UserDestination), MapperDirection.Reverse)]
public partial class ReverseMapper : IMapper { }
// Bidirectionnel
[Mapper(typeof(UserSource), typeof(UserDestination), MapperDirection.Bidirectional)]
public partial class BiMapper : IMapper { }MapperPropertyAggregation
Définit comment plusieurs propriétés source sont combinées en une seule propriété destination.
// Concaténation de chaîne
[MapFrom(typeof(PersonSource),
new[] { nameof(PersonSource.FirstName), nameof(PersonSource.LastName) },
MapperPropertyAggregation.ConcatenateWithSpace)]
public string FullName { get; set; }
// Opérations numériques
[MapFrom(typeof(PersonSource),
new[] { nameof(PersonSource.Salary), nameof(PersonSource.Bonus) },
MapperPropertyAggregation.Sum)]
public decimal TotalIncome { get; set; }
[MapFrom(typeof(PersonSource),
new[] { nameof(PersonSource.Score1), nameof(PersonSource.Score2) },
MapperPropertyAggregation.Average)]
public decimal AverageScore { get; set; }Key Features
Zéro Reflection avec Génération de Code Source
Utilise des analyseurs Roslyn pour générer du code de mappage hautement optimisé au moment de la compilation, éliminant ...
Système d'Agrégation de Propriétés
Combine plusieurs propriétés source en une seule propriété de destination en utilisant divers types d'agrégation incluan...
Mappage Conditionnel avec MapWhen
Mappe les propriétés seulement lorsque des conditions spécifiques sont remplies en utilisant l'attribut MapWhenAttribute...
Support de Mappage Bidirectionnel
Génère des mappeurs qui fonctionnent dans les deux directions (Direct, Inverse ou Bidirectionnel) avec une seule définit...
Mappage Sensible au Contexte
Support pour des objets de contexte qui influencent le comportement du mappage, permettant des scénarios comme le mappag...
Intégration avec l'Injection de Dépendances
Support intégré pour l'injection de dépendances avec IMapperFactory pour créer et gérer les instances de mappeur, l'enre...