BookinglyTech News
Software

Twinify 1.1.0 añade mapeo sin perfiles, atributos y generación para Native AOT

La librería de mapeo de objetos para .NET, con licencia MIT, elimina la necesidad de declarar CreateMap para DTOs idénticos e incorpora un generador de código que evita la reflexión en tiempo de ejecución.

3 min de lecturaDev.to0 vistas

Twinify, un mapeador de objetos para .NET con licencia MIT, ha publicado la versión 1.1.0. La librería funciona sobre .NET 8, 9 y 10 y en esta entrega añade mapeo sin perfiles declarados, atributos para renombrar o esconder miembros y un generador de código fuente que permite usarla en Native AOT. La API principal no se toca: se sigue inyectando IMapper y llamando a Map(origen).

Lo anterior, la 1.0.2, iba de rendimiento. Esta va de menos ceremonia, DTOs más seguros y compilación anticipada. Todo lo nuevo es aditivo, así que las aplicaciones que ya usaban perfiles mantienen el mismo comportamiento tras actualizar el paquete, disponible en NuGet junto a Twinify.DependencyInjection.

Menos CreateMap, mismos perfiles

Hasta ahora, aunque origen y destino tuvieran miembros con el mismo nombre, había que declarar un CreateMap. Ya no. Basta con registrar AddTwinify() y llamar al mapper: la librería copia los miembros homónimos, aplana rutas del tipo Address.City a AddressCity y recorre objetos anidados y colecciones. Sin inyección de dependencias es igual de simple, con new Mapper().

Los perfiles no desaparecen. Si se registra uno, solo mapean los pares declarados, como antes. Y si se quieren las dos cosas, hay una bandera: AllowMappingWithoutProfiles(). En ese caso CreateMap sigue ganando para su par concreto y el resto se automapea. Los tipos anidados dentro de un mapa explícito también se resuelven solos, sin necesidad de declarar el par de direcciones por separado.

Atributos y Native AOT

Los atributos sustituyen a las llamadas fluidas en los casos habituales. [IgnoreMap] excluye un miembro, pensado para cosas como un campo de contraseña en el DTO. [MapFrom("Address.City")] renombra o aplana sin perfil. [MapConstructor] elige constructor cuando el destino tiene más de uno. Se pueden desactivar con UseMappingAttributes(false).

El cambio de fondo es el soporte de Native AOT. Un mapa por reflexión no se puede calcular en tiempo de ejecución cuando el binario se compila por adelantado, así que el paquete ahora incluye Twinify.SourceGenerator. Marcando el par con [Twinify(typeof(User))] o a nivel de ensamblado con [TwinifyMap(typeof(User), typeof(UserDto))], el mapa se emite como código estático durante la compilación. Los miembros anidados que siguen la convención entran en el mapa generado, y los CreateMap sin personalizar también se pueden generar.

Hay una limitación que el autor reconoce sin adornos: las personalizaciones fluidas ForMember y ConvertUsing no se generan. En AOT toca usar [MapFrom] o [IgnoreMap], o dejar esos pares en JIT. Un par sin mapa generado lanza MappingNotFoundException en Native AOT, así que el fallo aparece en compilación y no en la primera petición.

La versión trae además mapeo de records (los parámetros del constructor se enlazan por nombre), actualización de una instancia existente con mapper.Map(origen, destinoExistente), validación de mapas al arrancar con ValidateMappings() y un mapper.Explain<Origen, Destino>() que muestra de dónde saca cada miembro su valor.

El interés para quien mantiene servicios en ASP.NET Core o workers es directo: si ya usa perfiles, actualizar el paquete no cambia nada; si arrastraba decenas de CreateMap para DTOs calcados, puede borrarlos. El detalle está en las notas de la versión, donde también se explica qué se queda fuera del generador.