TGViewer
Библиотека шарписта | C#, F#, .NET, ASP.NET Библиотека шарписта | C#, F#, .NET, ASP.NET @csharpproglib · 21.7K subscribers
Post #6973 3.1K
😊 Маппинг объектов без рефлексии и без оверхеда

Маппинг между моделями это одна из самых скучных вещей в C#-разработке. AutoMapper решает проблему, но тянет рефлексию в рантайме. FreakyKit.Forge генерирует весь маппинг-код на этапе компиляции через Roslyn source generators.

Вы объявляете partial-метод, библиотека генерирует его реализацию при сборке. Никакой рефлексии, никаких зависимостей в рантайме.

Установка:
<ItemGroup>
<PackageReference Include="FreakyKit.Forge.Generator" Version="1.0.0" />
<PackageReference Include="FreakyKit.Forge.Analyzers" Version="1.0.0" />
</ItemGroup>


Как это работает

Помечаем статический класс атрибутом [Forge] и объявляем метод без тела:
using FreakyKit.Forge;

public class Person { public string Name { get; set; } public int Age { get; set; } }
public class PersonDto { public string Name { get; set; } public int Age { get; set; } }

[Forge]
public static partial class PersonForges
{
public static partial PersonDto ToDto(Person source);
}


При компиляции Forge генерирует реализацию:
public static partial PersonDto ToDto(Person source)
{
var __result = new PersonDto();
__result.Name = source.Name;
__result.Age = source.Age;
return __result;
}


Вызов выглядит так:
var dto = PersonForges.ToDto(person);


Возможности

Базовый сценарий это маппинг по совпадению имён. Но библиотека умеет больше.

Переименование полей через [ForgeMap]:
public class Source { [ForgeMap("Name")] public string FirstName { get; set; } }
public class Dest { public string Name { get; set; } }


Вложенные объекты с AllowNestedForging:
[Forge]
public static partial class PersonForges
{
public static partial AddressDto ToAddressDto(Address source);

[ForgeMethod(AllowNestedForging = true)]
public static partial PersonDto ToDto(Person source);
}
// Генерирует: __result.Home = ToAddressDto(source.Home);


Коллекции обрабатываются автоматически — List<T>, T[], ImmutableArray<T> и другие. Если типы элементов отличаются, достаточно включить AllowNestedForging.

Обновление существующего объекта вместо создания нового — метод с двумя параметрами и void:
public static partial void Update(Person source, PersonDto existing);
// Генерирует: existing.Name = source.Name; existing.Age = source.Age;


Строгий режим для отлова расхождений при рефакторинге:
[ForgeMethod(StrictMapping = true)]
public static partial PersonDto ToDto(Person source);
// Если добавить поле в Source или Dest — компилятор выдаст ошибку, не предупреждение


Тип-конвертеры для несовместимых типов:
[ForgeConverter]
public static string ConvertDateTime(DateTime value) => value.ToString("yyyy-MM-dd");
// Forge сам найдёт подходящий конвертер и применит его при маппинге


Диагностика

Пакет FreakyKit.Forge.Analyzers добавляет 35 диагностических правил. Ошибки в объявлениях маппингов вы увидите прямо в редакторе при сборке, а не в рантайме.

➡️ Репозиторий

📍 Навигация: ВакансииЗадачиСобесы

🐸 Библиотека шарписта

#sharp_view
  • ❤ 13
  • 🤔 9
More from @csharpproglib
  1. Sep 23, 2026⚙️ yield return не бесплатный Итераторы выглядят просто, но работают иначе: IEnumerable<in…
  2. Sep 22, 2026💡 Replace, Regex или StringBuilder? Для замены текста в C# есть несколько инструментов. И…
  3. Sep 21, 2026⚙️ Настоящие атомарные операции Если Volatile решает проблему видимости, то Interlocked ре…
  4. Sep 20, 2026💪 Разминка перед трудовыми буднями Что произойдёт? ❤️ — список станет [1, 3] 🔥 — Invalid…
  5. Sep 19, 2026🧩 Middleware в ASP.NET Core: 3 ловушки Middleware — звено HTTP pipeline: app.Use(async (c…
  6. Sep 18, 2026📍 Навигация: Вакансии • Задачи • Собесы 🐸Библиотека шарписта #garbage_collector
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →