Идея для C# 14: интерцепторы могли бы сделать генерацию исходного кода System.Text.Json автоматической
Обсуждение в сообществе предложило использовать интерцепторы C# 14 для переписывания вызовов JsonSerializer, чтобы они автоматически использовали сгенерированный JsonSerializerContext, сохраняя AOT-совместимую генерацию исходного кода с более чистыми точками вызова.
Одной из наиболее интересных дискуссий о .NET за последние 24-48 часов стал простой вопрос: почему генерация исходного кода System.Text.Json всё ещё ощущается “ручной” в точке вызова?
Триггером стал тред от 7 февраля 2026 года, в котором предлагался подход, очень в духе C# 14: интерцепторы, переписывающие вызовы JsonSerializer.Serialize и JsonSerializer.Deserialize так, чтобы они автоматически использовали сгенерированный JsonSerializerContext.
Эргономический разрыв: контекст работает, но расползается по вашему коду
Если вы хотите безопасности обрезки и предсказуемой производительности в .NET 10, генерация исходного кода - сильный вариант. Трение в том, что вы в итоге протаскиваете контекст повсюду:
using System.Text.Json;
var foo = JsonSerializer.Deserialize<Foo>(json, FooJsonContext.Default.Foo);
var payload = JsonSerializer.Serialize(foo, FooJsonContext.Default.Foo);
Это явно и корректно, но шумно. Этот шум имеет тенденцию просачиваться в слои приложения, которым не должно быть дела до сериализационной обвязки.
Как могло бы выглядеть переписывание на основе интерцепторов
Идея в том, чтобы сохранить точки вызова чистыми:
var foo = JsonSerializer.Deserialize<Foo>(json);
А затем иметь интерцептор (на этапе компиляции), который переписывает это в вызов, основанный на контексте, который вы написали бы вручную:
var foo = JsonSerializer.Deserialize<Foo>(json, GlobalJsonContext.Default.Foo);
Если у вас несколько профилей опций, интерцептору нужно детерминированное сопоставление с правильным экземпляром контекста. Именно здесь начинается часть “это сложно”.
Ограничения, которые делают это возможным или невозможным (AOT - судья)
Чтобы это было больше, чем просто хорошая идея, оно должно выжить в средах, где генерация исходного кода имеет наибольшее значение:
- NativeAOT и обрезка: переписывание не должно случайно вновь вводить откаты, основанные на отражении.
- Идентичность опций: вам нужен стабильный способ выбрать контекст для заданного
JsonSerializerOptions. Изменяемые во время выполнения опции не подходят. - Частичная компиляция: интерцепторы должны вести себя согласованно между проектами, тестовыми сборками и инкрементальными сборками.
Если эти ограничения выполняются, вы получаете редкий выигрыш: сохранить AOT-совместимый конвейер, но убрать “обвязку контекста” из большей части вашего кода.
Практический вывод на сегодня: даже если интерцепторы не приземлятся точно в той форме, что обсуждалась, это сильный сигнал того, что разработчики .NET хотят лучшей эргономики вокруг генерации исходного кода. Я бы ожидал, что будущие инструменты, анализаторы или паттерны фреймворков будут двигаться в этом направлении.
Источники:
Comments
Sign in with GitHub to comment. Reactions and replies thread back to the comments repo.