eQuantic Mapper
Object mapping utilities and extensions
Version: 2.0.0
Downloads: 21K+
Status: stable
Category: utilities
Installation
dotnet add package eQuantic.Mapper
Overview
eQuantic.Mapper es una biblioteca de mapeo de objetos de alto rendimiento para .NET que elimina la sobrecarga de reflection generando código de mapeo en tiempo de compilación usando generadores de código fuente. Proporciona características poderosas para mapeos complejos de propiedades, agregaciones, mapeo condicional y transformaciones bidireccionales con excelentes características de rendimiento.
A diferencia de los mapeadores tradicionales que dependen de reflection en tiempo de ejecución, eQuantic.Mapper usa analizadores Roslyn para generar código de mapeo optimizado durante la compilación, resultando en cero sobrecarga de reflection y rendimiento superior. La biblioteca soporta escenarios avanzados incluyendo agregación de propiedades, mapeo condicional basado en condiciones de tiempo de ejecución, mapeos sensibles al contexto y mapeos bidireccionales.
La biblioteca está diseñada para aplicaciones empresariales donde el rendimiento, la seguridad de tipos y la mantenibilidad son críticas. Se integra perfectamente con contenedores de inyección de dependencias y proporciona opciones ricas de personalización a través de atributos y clases parciales, permitiendo a los desarrolladores crear escenarios de mapeo sofisticados mientras mantienen código limpio y legible.
Quick Start
1. Instalación y Configuración
Instala tanto el paquete núcleo del mapeador como el generador de código fuente para habilitar la generación de código en tiempo de compilación.
// Instalar vía Package Manager Console
Install-Package eQuantic.Mapper
Install-Package eQuantic.Mapper.Generator
// O vía .NET CLI
dotnet add package eQuantic.Mapper
dotnet add package eQuantic.Mapper.Generator
// Declaraciones using básicas
using eQuantic.Mapper;
using eQuantic.Mapper.Attributes;2. Define Tus Modelos
Crea tus modelos fuente y destino. Usa atributos para configurar escenarios de mapeo avanzados como agregación de propiedades y mapeo condicional.
// Modelo fuente
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; };
}
// Modelo destino con agregación
public class UserDestination
{
// Agregación de propiedades
[MapFrom(typeof(UserSource),
new[] { nameof(UserSource.FirstName), nameof(UserSource.LastName) },
MapperPropertyAggregation.ConcatenateWithSpace)]
public string FullName { get; set; } = string.Empty;
// Agregación numérica
[MapFrom(typeof(UserSource),
new[] { nameof(UserSource.Salary), nameof(UserSource.Bonus) },
MapperPropertyAggregation.Sum)]
public decimal TotalIncome { get; set; };
// Mapeo condicional
[MapFrom(typeof(UserSource), nameof(UserSource.Age))]
[MapWhen(nameof(UserSource.IsActive))]
public int? DisplayAge { get; set; };
// Propiedades mapeadas automáticamente (por nombre)
public int Age { get; set; }
}3. Crea Tu Mapeador
Define una clase parcial con el atributo Mapper. El generador de código fuente creará la implementación automáticamente.
// Mapeador generado automáticamente
[Mapper(typeof(UserSource), typeof(UserDestination))]
public partial class UserMapper : IMapper
{
// Opcional: Agregar lógica personalizada
partial void AfterConstructor()
{
OnBeforeMap += (sender, args) =>
{
// Lógica de preprocesamiento
Console.WriteLine($"Mapeando usuario: {args.Source.FirstName}");
};
OnAfterMap += (sender, args) =>
{
// Lógica de postprocesamiento
if (args.Destination.Age < 18)
{
args.Destination.FullName = $"Menor: {args.Destination.FullName}";
}
};
}
}4. Configura la Inyección de Dependencias
Registra todos los mapeadores en tu contenedor DI usando el método de extensión proporcionado.
var builder = WebApplication.CreateBuilder(args);
// Registrar todos los mapeadores automáticamente
builder.Services.AddMappers();
var app = builder.Build();
// Usar en controllers o servicios
app.MapGet("/users/{id}", async (int id, IMapperFactory mapperFactory) =>
{
var mapper = mapperFactory.GetMapper<UserSource, UserDestination>()!;
var user = await GetUserAsync(id); // Tu lógica de acceso a datos
return mapper.Map(user);
});
app.Run();5. Uso de Características Avanzadas
Aprovecha características avanzadas como mapeo bidireccional, mapeo sensible al contexto y lógica condicional.
// Mapeo bidireccional
[Mapper(typeof(UserSource), typeof(UserDestination), MapperDirection.Bidirectional)]
public partial class BidirectionalUserMapper : IMapper { }
// Mapeo sensible al contexto
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;
}
};
}
}
// Uso
var contextMapper = mapperFactory.GetMapper<UserSource, UserDestination, MappingContext>()!;
contextMapper.Context = new MappingContext { IncludeSensitiveData = false, UserRole = "User" };
var result = contextMapper.Map(userSource);API Reference
MapperAttribute
Define una clase mapeador para transformar entre dos tipos, con soporte opcional de contexto y dirección.
[Mapper(typeof(UserSource), typeof(UserDestination))]
public partial class UserMapper : IMapper
{
// Implementación generada automáticamente
}
// Con contexto
[Mapper(typeof(UserSource), typeof(UserDestination), typeof(MappingContext))]
public partial class ContextUserMapper : IMapper<UserSource, UserDestination, MappingContext> { }
// Bidireccional
[Mapper(typeof(UserSource), typeof(UserDestination), MapperDirection.Bidirectional)]
public partial class BiMapper : IMapper { }MapFromAttribute
Mapea una propiedad destino desde una o más propiedades fuente con agregación opcional.
// Mapeo simple
[MapFrom(typeof(UserSource), nameof(UserSource.FirstName))]
public string Name { get; set; }
// Agregación de propiedades
[MapFrom(typeof(UserSource),
new[] { nameof(UserSource.FirstName), nameof(UserSource.LastName) },
MapperPropertyAggregation.ConcatenateWithSpace)]
public string FullName { get; set; }
// Agregación numérica
[MapFrom(typeof(UserSource),
new[] { nameof(UserSource.Salary), nameof(UserSource.Bonus) },
MapperPropertyAggregation.Sum)]
public decimal TotalIncome { get; set; }MapWhenAttribute
Mapea condicionalmente una propiedad basada en una propiedad booleana o expresión C#.
// Condición booleana simple
[MapFrom(typeof(UserSource), nameof(UserSource.Email))]
[MapWhen(nameof(UserSource.IsEmailVisible))]
public string? PublicEmail { get; set; }
// Condición de expresión
[MapFrom(typeof(UserSource), nameof(UserSource.Age))]
[MapWhen("source.Age >= 18", true)]
public int? DisplayAge { get; set; }
// Condición sensible al contexto
[MapFrom(typeof(UserSource), nameof(UserSource.Salary))]
[MapWhen("Context?.IncludeSensitiveData == true", true)]
public decimal? Salary { get; set; }IMapper<TSource, TDestination>
Interfaz básica de mapeador para transformar del tipo fuente al tipo destino.
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)
{
// Mapear a instancia existente
}
}IMapper<TSource, TDestination, TContext>
Interfaz de mapeador sensible al contexto con soporte para contexto de mapeo.
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
Interfaz factory para crear y recuperar instancias de mapeador.
// Uso con inyección de dependencias
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
Especifica la dirección del mapeo para mapeadores bidireccionales.
// Solo directo (por defecto)
[Mapper(typeof(UserSource), typeof(UserDestination))]
public partial class ForwardMapper : IMapper { }
// Solo reverso
[Mapper(typeof(UserSource), typeof(UserDestination), MapperDirection.Reverse)]
public partial class ReverseMapper : IMapper { }
// Bidireccional
[Mapper(typeof(UserSource), typeof(UserDestination), MapperDirection.Bidirectional)]
public partial class BiMapper : IMapper { }MapperPropertyAggregation
Define cómo múltiples propiedades fuente se combinan en una sola propiedad destino.
// Concatenación de string
[MapFrom(typeof(PersonSource),
new[] { nameof(PersonSource.FirstName), nameof(PersonSource.LastName) },
MapperPropertyAggregation.ConcatenateWithSpace)]
public string FullName { get; set; }
// Operaciones numéricas
[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
Cero Reflection con Generación de Código Fuente
Usa analizadores Roslyn para generar código de mapeo altamente optimizado en tiempo de compilación, eliminando completam...
Sistema de Agregación de Propiedades
Combina múltiples propiedades fuente en una sola propiedad destino usando varios tipos de agregación incluyendo concaten...
Mapeo Condicional con MapWhen
Mapea propiedades solo cuando se cumplen condiciones específicas usando el atributo MapWhenAttribute. Soporta condicione...
Soporte de Mapeo Bidireccional
Genera mapeadores que funcionan en ambas direcciones (Directo, Reverso o Bidireccional) con una sola definición de clase...
Mapeo Sensible al Contexto
Soporte para objetos de contexto que influyen en el comportamiento del mapeo, habilitando escenarios como mapeo de campo...
Integración con Inyección de Dependencias
Soporte integrado para inyección de dependencias con IMapperFactory para crear y gestionar instancias de mapeador, regis...