Разработчик предложил официальную формальную семантику C# на Lean 4 — то есть основу, которая позволит строить машинно проверяемые доказательства для C#.
ИИ-агенты становятся очень хороши в написании кода — и очень хороши в том, чтобы его ломать.
В эпоху агентов для критически важного ПО фразы «тесты прошли» будет уже недостаточно. Нам нужно уметь доказывать свойства кода, который мы выпускаем.
И это уже становится практичным.
У Rust уже есть Aeneas → Lean. Microsoft Research использует его для формальной верификации SymCrypt. У Java и C тоже уже есть основа в формальной верификации.
C# не должен остаться позади.
ИИ может написать код.
ИИ может построить доказательство.
А детерминированное ядро проверки доказательств проверит, действительно ли это доказательство корректно.
Это совсем другая модель доверия по сравнению с
ИИ пишет код → ИИ проверяет код → надеемся, что оба оказались правы.
Предложение: https://github.com/dotnet/csharplang/discussions/10314
👉 @KodBlog
ИИ-агенты становятся очень хороши в написании кода — и очень хороши в том, чтобы его ломать.
В эпоху агентов для критически важного ПО фразы «тесты прошли» будет уже недостаточно. Нам нужно уметь доказывать свойства кода, который мы выпускаем.
И это уже становится практичным.
У Rust уже есть Aeneas → Lean. Microsoft Research использует его для формальной верификации SymCrypt. У Java и C тоже уже есть основа в формальной верификации.
C# не должен остаться позади.
ИИ может написать код.
ИИ может построить доказательство.
А детерминированное ядро проверки доказательств проверит, действительно ли это доказательство корректно.
Это совсем другая модель доверия по сравнению с
ИИ пишет код → ИИ проверяет код → надеемся, что оба оказались правы.
Предложение: https://github.com/dotnet/csharplang/discussions/10314
Please open Telegram to view this post
VIEW IN TELEGRAM
GitHub
Proposal: An official Lean formal semantics for C# · dotnet/csharplang · Discussion #10314
This is not a proposal for new C# syntax or language constructs. I would like C# to have an officially maintained Lean 4 formal semantics, developed incrementally alongside the language specificati...
👍2🍾1
Андерс Хейлсберг — создатель TypeScript и C#. На подкасте его спросили о том, как переписывание компилятора на Go позволило ускорить TypeScript примерно в 10 раз, и о том, как ИИ уже влияет на разработку ПО.
В выпуске
• Как переписывание компилятора дало ускорение в 10 раз
• Почему выбрали Go, а не Rust
• Почему для миграции не использовали LLM
• Как ИИ повлияет на разработку ПО в будущем
https://www.youtube.com/watch?v=cywK3XYYJ2o
👉 @KodBlog
В выпуске
• Как переписывание компилятора дало ускорение в 10 раз
• Почему выбрали Go, а не Rust
• Почему для миграции не использовали LLM
• Как ИИ повлияет на разработку ПО в будущем
https://www.youtube.com/watch?v=cywK3XYYJ2o
Please open Telegram to view this post
VIEW IN TELEGRAM
YouTube
Creator of TypeScript: 10x Faster Typescript, Why AI Won't Replace SWEs | Anders Hejlsberg
Anders Hejlsberg is the creator of TypeScript and C#, and I asked him about how the TypeScript compiler got 10x faster through a rewrite in Go and his thoughts on how AI has impacted software engineering.
• My ergonomic keyboard project I mentioned, you…
• My ergonomic keyboard project I mentioned, you…
🍾3
C# 14 позволяет объединить проверку на
Раньше нужно было писать так:
Теперь оператор
Поведение то же самое. Если
Ещё несколько нюансов:
— работает и с
— не работает с
— поддерживаются и
👉 @KodBlog
null и присваивание в одну строку.Раньше нужно было писать так:
if (customer is not null)
{
customer.Order = GetCurrentOrder();
}
Теперь оператор
?. можно использовать слева от присваивания:customer?.Order = GetCurrentOrder();
Поведение то же самое. Если
customer равен null, GetCurrentOrder() даже не вызовется.Ещё несколько нюансов:
— работает и с
+=, -= и другими составными присваиваниями— не работает с
++ и --— поддерживаются и
?., и ?[] слева от присваиванияPlease open Telegram to view this post
VIEW IN TELEGRAM
👍17🍾2
C# 14 позволяет массивам,
Массив
✔️ Преобразования работают между
✔️ Типы
✔️ Компилятору стало проще выводить обобщённые типы, когда массивы и
👉 @KodBlog
Span<T> и ReadOnlySpan<T> автоматически преобразовываться друг в друга.Span<T> и ReadOnlySpan<T> уже повсеместно используются в среде выполнения ради производительности без ущерба для безопасности. В C# 14 компилятор получил полноценную поддержку преобразований между ними и T[]:void PrintFirst(ReadOnlySpan<int> values)
{
Console.WriteLine(values[0]);
}
int[] numbers = [10, 20, 30];
PrintFirst(numbers);
Массив
int напрямую передаётся в параметр ReadOnlySpan<int> — никаких явных вызовов преобразования.✔️ Преобразования работают между
ReadOnlySpan<T>, Span<T> и T[]✔️ Типы
Span теперь могут выступать получателями методов расширения✔️ Компилятору стало проще выводить обобщённые типы, когда массивы и
Span используются вместеPlease open Telegram to view this post
VIEW IN TELEGRAM
👍7❤1🍾1
Эти заметки — структурированное руководство по собеседованиям по проектированию систем.
Внутри разбираются как базовые подходы к System Design, так и конкретные архитектуры: веб-краулеры, системы уведомлений, платёжные платформы и другие типичные задачи с собеседований.
https://github.com/liquidslr/system-design-notes
👉 @KodBlog
Внутри разбираются как базовые подходы к System Design, так и конкретные архитектуры: веб-краулеры, системы уведомлений, платёжные платформы и другие типичные задачи с собеседований.
https://github.com/liquidslr/system-design-notes
Please open Telegram to view this post
VIEW IN TELEGRAM
GitHub
GitHub - liquidslr/system-design-notes: Notes of the book System Desgin Interview - An Insider's Guide
Notes of the book System Desgin Interview - An Insider's Guide - liquidslr/system-design-notes
🥰3🍾1
C# 14 позволяет хранить сигнатуру конструктора и его реализацию в двух разных файлах.
Частичные члены уже позволяли разделять методы между сгенерированным и написанным вручную кодом. В C# 14 такой же подход с объявлением и реализацией теперь распространяется на конструкторы и события.
Объявляющая часть, которая, скорее всего, находится в сгенерированном коде, содержит только сигнатуру:
А реализующая часть в вашем собственном файле содержит тело конструктора:
✔️ Должно быть ровно одно объявление и ровно одна реализация — ни больше ни меньше
✔️ Только реализующая часть может содержать инициализатор
✔️ Тот же принцип теперь работает и для событий — в реализующей части должны быть оба метода доступа
👉 @KodBlog
Частичные члены уже позволяли разделять методы между сгенерированным и написанным вручную кодом. В C# 14 такой же подход с объявлением и реализацией теперь распространяется на конструкторы и события.
Объявляющая часть, которая, скорее всего, находится в сгенерированном коде, содержит только сигнатуру:
public partial class Order
{
public partial Order(string id);
}
А реализующая часть в вашем собственном файле содержит тело конструктора:
public partial class Order
{
public partial Order(string id)
{
Id = id;
}
public string Id { get; }
}
✔️ Должно быть ровно одно объявление и ровно одна реализация — ни больше ни меньше
✔️ Только реализующая часть может содержать инициализатор
: this() или : base()✔️ Тот же принцип теперь работает и для событий — в реализующей части должны быть оба метода доступа
add и removePlease open Telegram to view this post
VIEW IN TELEGRAM
🍾2
Как добавить проверки работоспособности в .NET?
Следующий шаг — подключить сами проверки.
Существует множество библиотек с готовыми проверками для популярных баз данных, брокеров сообщений и других сервисов.
Если нужен полный разбор, вот хорошая статья:
https://milanjovanovic.tech/blog/health-checks-in-asp-net-core
👉 @KodBlog
AddHealthChecks — добавляет необходимые сервисы.MapHealthChecks — создаёт конечную точку для проверки состояния приложения.Следующий шаг — подключить сами проверки.
Существует множество библиотек с готовыми проверками для популярных баз данных, брокеров сообщений и других сервисов.
Если нужен полный разбор, вот хорошая статья:
https://milanjovanovic.tech/blog/health-checks-in-asp-net-core
Please open Telegram to view this post
VIEW IN TELEGRAM
❤1🍾1
Какие практики обработки ошибок в API на .NET считаются лучшими?
Я бы начал с главного — ошибки API должны возвращаться в едином формате.
Нужна понятная и стабильная структура ответа, логирование и мониторинг, нормальные сообщения об ошибках, документация по типовым ошибкам и никакой утечки чувствительных данных.
Было бы удобно, если бы для всего этого существовал стандарт.
Он есть.
Называется Problem Details.
👉 @KodBlog
Я бы начал с главного — ошибки API должны возвращаться в едином формате.
Нужна понятная и стабильная структура ответа, логирование и мониторинг, нормальные сообщения об ошибках, документация по типовым ошибкам и никакой утечки чувствительных данных.
Было бы удобно, если бы для всего этого существовал стандарт.
Он есть.
Называется Problem Details.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤7👍1🍾1
В EF Core 10 есть 7 перехватчиков, но в большинстве проектов подключают ровно один.
Перехватчик — это просто точка, в которой EF Core вызывает ваш код в определённый момент. Например, при сохранении данных, выполнении запроса или открытии соединения.
Вот для чего на самом деле нужен каждый из них.
1. ISaveChangesInterceptor
Самый известный. Срабатывает вокруг SaveChanges. Именно здесь обычно реализуют поля аудита вроде CreatedOn и UpdatedOn, мягкое удаление и шаблон Outbox.
2. IDbCommandInterceptor
Видит настоящий SQL-запрос до его выполнения. Можно журналировать медленные запросы, добавлять подсказки для СУБД или изменять команду перед отправкой в базу данных.
3. IDbConnectionInterceptor
Срабатывает, когда EF открывает соединение. Можно подменять строку подключения для разных арендаторов или получать новый токен доступа к базе данных. Для многопользовательских приложений с изоляцией арендаторов этот перехватчик сильно недооценён.
4. IDbTransactionInterceptor
Перехватывает подтверждение и откат транзакции. Полезен, когда нужно добавить собственное журналирование или дополнительную логику вокруг самой транзакции.
5. IMaterializationInterceptor
Срабатывает, когда EF превращает строку из базы данных в объект сущности. Можно задать свойство, которое не связано со столбцом таблицы, или передать сущности какой-либо сервис прямо во время её создания.
6. IQueryExpressionInterceptor
Переписывает запрос ещё до того, как EF преобразует его в SQL. Например, можно автоматически добавлять сортировку по умолчанию или фильтр ко всем выполняемым запросам.
7. IIdentityResolutionInterceptor
Определяет, что делать, если две отслеживаемые сущности имеют один и тот же первичный ключ. Вместо того чтобы EF выбросил исключение, можно самостоятельно объединить эти экземпляры.
Последние три появились довольно незаметно в нескольких недавних версиях EF Core, и большинство разработчиков дальше учебных примеров с ними так и не заходят.
Если вы когда-либо подключали только первый, то в уже используемой вами версии EF Core есть ещё шесть перехватчиков, которые просто остаются без дела.
👉 @KodBlog
Перехватчик — это просто точка, в которой EF Core вызывает ваш код в определённый момент. Например, при сохранении данных, выполнении запроса или открытии соединения.
Вот для чего на самом деле нужен каждый из них.
1. ISaveChangesInterceptor
Самый известный. Срабатывает вокруг SaveChanges. Именно здесь обычно реализуют поля аудита вроде CreatedOn и UpdatedOn, мягкое удаление и шаблон Outbox.
2. IDbCommandInterceptor
Видит настоящий SQL-запрос до его выполнения. Можно журналировать медленные запросы, добавлять подсказки для СУБД или изменять команду перед отправкой в базу данных.
3. IDbConnectionInterceptor
Срабатывает, когда EF открывает соединение. Можно подменять строку подключения для разных арендаторов или получать новый токен доступа к базе данных. Для многопользовательских приложений с изоляцией арендаторов этот перехватчик сильно недооценён.
4. IDbTransactionInterceptor
Перехватывает подтверждение и откат транзакции. Полезен, когда нужно добавить собственное журналирование или дополнительную логику вокруг самой транзакции.
5. IMaterializationInterceptor
Срабатывает, когда EF превращает строку из базы данных в объект сущности. Можно задать свойство, которое не связано со столбцом таблицы, или передать сущности какой-либо сервис прямо во время её создания.
6. IQueryExpressionInterceptor
Переписывает запрос ещё до того, как EF преобразует его в SQL. Например, можно автоматически добавлять сортировку по умолчанию или фильтр ко всем выполняемым запросам.
7. IIdentityResolutionInterceptor
Определяет, что делать, если две отслеживаемые сущности имеют один и тот же первичный ключ. Вместо того чтобы EF выбросил исключение, можно самостоятельно объединить эти экземпляры.
Последние три появились довольно незаметно в нескольких недавних версиях EF Core, и большинство разработчиков дальше учебных примеров с ними так и не заходят.
Если вы когда-либо подключали только первый, то в уже используемой вами версии EF Core есть ещё шесть перехватчиков, которые просто остаются без дела.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤12🍾1
В C# 14 параметры лямбда-выражений с
Раньше, если нужно было добавить
Теперь достаточно указать сам модификатор, а типы компилятор выведет автоматически
То же самое работает со
Исключение —
Небольшое изменение, но именно из таких вещей C# постепенно убирает лишний шум из кода.
👉 @KodBlog
ref, out и in стали заметно короче.Раньше, если нужно было добавить
out, приходилось явно указывать тип каждого параметраTryParse<int> parse2 = (string text, out int result) =>
Int32.TryParse(text, out result);
Теперь достаточно указать сам модификатор, а типы компилятор выведет автоматически
TryParse<int> parse1 = (text, out result) =>
Int32.TryParse(text, out result);
То же самое работает со
scoped, ref, in, out и ref readonly.Исключение —
params. С ним список параметров по-прежнему нужно типизировать явно.Небольшое изменение, но именно из таких вещей C# постепенно убирает лишний шум из кода.
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔5⚡4👍1🍾1
Шаблон Full Stack FastAPI теперь отдаёт фронтенд на React и TanStack прямо через FastAPI.
В итоге одно приложение, один деплой и один домен.
Без отдельного фронтенд-сервера, лишней настройки CORS и постоянной отладки проблем между двумя частями приложения.
https://github.com/fastapi/full-stack-fastapi-template
👉 @KodBlog
В итоге одно приложение, один деплой и один домен.
Без отдельного фронтенд-сервера, лишней настройки CORS и постоянной отладки проблем между двумя частями приложения.
https://github.com/fastapi/full-stack-fastapi-template
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4🍾1
Пришло время что-то собрать.
В этом GitHub-репозитории собрана огромная коллекция практических руководств, где обучение идёт через создание реальных проектов.
Если застряли на вопросе «что вообще сделать?», начинать можно отсюда.
https://github.com/practical-tutorials/project-based-learning
👉 @KodBlog
В этом GitHub-репозитории собрана огромная коллекция практических руководств, где обучение идёт через создание реальных проектов.
Если застряли на вопросе «что вообще сделать?», начинать можно отсюда.
https://github.com/practical-tutorials/project-based-learning
Please open Telegram to view this post
VIEW IN TELEGRAM
GitHub
GitHub - practical-tutorials/project-based-learning: Curated list of project-based tutorials
Curated list of project-based tutorials. Contribute to practical-tutorials/project-based-learning development by creating an account on GitHub.
🍾4❤1
IAsyncActionFilter недооценён, хотя это очень мощный инструмент.В ASP.NET Core фильтры позволяют запускать свою логику до или после определённых этапов обработки запроса, не трогая сами контроллеры.
Две главные причины их использовать
1. Повторное использование — одну и ту же логику можно применять сразу к нескольким контроллерам или действиям.
2. Расширяемость — бизнес-правила можно полностью вынести из методов контроллера.
IActionFilter выполняется до и после метода действия и хорошо подходит для лёгких синхронных проверок.IAsyncActionFilter нужен, когда внутри проверки приходится ждать асинхронную операцию — например, запрос к базе данных или другому сервису.Вместо двух отдельных методов до и после здесь используется один
OnActionExecutionAsync, который оборачивает вызов next().Если вызвать
next(), выполнение продолжится дальше. Если не вызывать его и задать context.Result, запрос можно остановить прямо в фильтре.internal sealed class EmailVerifiedFilter(
IUser currentUser,
IUserService userService) : IAsyncActionFilter
{
public async Task OnActionExecutionAsync(
ActionExecutingContext context,
ActionExecutionDelegate next)
{
Guid? userId = currentUser.Id;
if (userId != null &&
!await userService.IsEmailVerifiedAsync(userId))
{
context.Result = new ForbidResult();
return;
}
await next();
}
}
Регистрация
builder.Services.AddScoped<EmailVerifiedFilter>();
Использование
[HttpGet("dashboard")]
[ServiceFilter(typeof(EmailVerifiedFilter))]
public IActionResult GetUserDashboard()
{
...
}Хорошо подходит для проверки подтверждения почты или подписки, выполнения бизнес-правил перед запуском действия, условной блокировки запросов и любой общей логики, которую иначе пришлось бы копировать в десяток контроллеров.
Но если нужна обычная проверка роли или политики без обращения к базе данных, чаще лучше использовать
IAsyncAuthorizationFilter. Он выполняется ещё до привязки модели, поэтому отклонённый запрос не тратит ресурсы на ненужную работу.Один фильтр — куча сценариев.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🍾1
SignalR позволяет добавлять функции реального времени в приложения на .NET.
И всё начинается с SignalR Hub.
Hub — это центральный компонент приложения, который управляет подключёнными клиентами и отправкой сообщений. Чтобы получать и отправлять сообщения, клиенты должны подключиться к Hub.
SignalR — одна из лучших библиотек в экосистеме .NET.
👉 @KodBlog
И всё начинается с SignalR Hub.
Hub — это центральный компонент приложения, который управляет подключёнными клиентами и отправкой сообщений. Чтобы получать и отправлять сообщения, клиенты должны подключиться к Hub.
SignalR — одна из лучших библиотек в экосистеме .NET.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13🥰3🍾1
Эндпоинт работает медленно. В логах написано, что запрос занял 800 мс. И что дальше?
Одних логов недостаточно, чтобы понять, куда ушло время. Это был обработчик? Запрос к базе данных? Внешний вызов? В итоге приходится гадать или добавлять Stopwatch, снова разворачивать приложение и проверять ещё раз.
Именно поэтому в моём шаблоне полная картина доступна сразу.
Приложение отправляет логи, трассировки и метрики через OTLP. Один контейнер grafana/otel-lgtm принимает всё это. Loki хранит логи, Tempo — трассировки, Prometheus — метрики. Поверх всего работает Grafana на localhost:3000.
Запускаете docker compose up, вызываете эндпоинт и можете увидеть конкретный запрос в виде временной шкалы. Каждый запрос EF Core отображается отдельной полосой. После этого можно сразу перейти к логам именно этого запроса.
Самое важное — такую же схему можно использовать и в продакшене, хотя я рекомендую запускать эти сервисы в отдельных контейнерах.
👉 @KodBlog
Одних логов недостаточно, чтобы понять, куда ушло время. Это был обработчик? Запрос к базе данных? Внешний вызов? В итоге приходится гадать или добавлять Stopwatch, снова разворачивать приложение и проверять ещё раз.
Именно поэтому в моём шаблоне полная картина доступна сразу.
Приложение отправляет логи, трассировки и метрики через OTLP. Один контейнер grafana/otel-lgtm принимает всё это. Loki хранит логи, Tempo — трассировки, Prometheus — метрики. Поверх всего работает Grafana на localhost:3000.
Запускаете docker compose up, вызываете эндпоинт и можете увидеть конкретный запрос в виде временной шкалы. Каждый запрос EF Core отображается отдельной полосой. После этого можно сразу перейти к логам именно этого запроса.
Самое важное — такую же схему можно использовать и в продакшене, хотя я рекомендую запускать эти сервисы в отдельных контейнерах.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤3🍾1
Если «результатов нет», лучше возвращать пустую коллекцию, а не null.
Если метод возвращает коллекцию, вызывающему коду почти всегда проще работать с пустой коллекцией.
Вместо:
Лучше:
Тогда вызывающий код может просто сделать так:
Никакой проверки на null перед циклом не требуется.
Одно небольшое изменение дает сразу несколько плюсов:
✔️ Чище вызывающий код
✔️ Меньше лишних проверок
✔️ Ниже риск NullReferenceException
✔️ Более понятный контракт API
В современном C# конструкция
Именно такие небольшие решения в проектировании API определяют, будет ли с ним приятно работать или разработчикам постоянно придется гадать, что метод вернет в очередной раз.
👉 @KodBlog
Если метод возвращает коллекцию, вызывающему коду почти всегда проще работать с пустой коллекцией.
Вместо:
return null;
Лучше:
return [];
Тогда вызывающий код может просто сделать так:
foreach (var user in users)
{
// ...
}
Никакой проверки на null перед циклом не требуется.
Одно небольшое изменение дает сразу несколько плюсов:
✔️ Чище вызывающий код
✔️ Меньше лишних проверок
✔️ Ниже риск NullReferenceException
✔️ Более понятный контракт API
В современном C# конструкция
[] сразу показывает намерение.Именно такие небольшие решения в проектировании API определяют, будет ли с ним приятно работать или разработчикам постоянно придется гадать, что метод вернет в очередной раз.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8❤2🍾1
10 навыков для .NET, которые стоит использовать в следующей разработке с ИИ.
Навык — это файл с инструкциями, который агент загружает только тогда, когда задача действительно этого требует.
1.
Проверяет код примерно на 50 типичных проблем с производительностью: async, память, строки, коллекции, LINQ, регулярные выражения, сериализация и ввод-вывод.
2.
Берёт медленный запрос и оптимизирует его так, чтобы генерировалось меньше SQL и было меньше обращений к базе данных.
3.
Проверяет то, что только что сделал агент, и ищет его «срезанные углы»: отключённые тесты, подавленные предупреждения, пустые блоки
4.
Отвечает на вопрос: «Смогли бы мои тесты поймать эту ошибку?»
5.
Интеграционные тесты с реальными базами данных, очередями и кешами, которые поднимаются в Docker, вместо моков.
6.
Интеграционные тесты с удобствами .NET Aspire: фикстуры, распределённое приложение и автоматическое обнаружение конечных точек.
7.
Читает binlog MSBuild и объясняет, почему сборка упала, когда консоль не сообщает ничего полезного.
8.
Переводит решение на Central Package Management и выравнивает версии NuGet-пакетов во всех проектах.
9.
Обновляет
10.
Декомпилирует сборку, чтобы понять, как внутри работает API фреймворка или NuGet-пакет.
Мне особенно понравился №3. Сам факт того, что существует отдельный навык для проверки «срезанных углов» агента, многое говорит о текущем состоянии разработки с ИИ.
В Claude Code они устанавливаются так:
👉 @KodBlog
Навык — это файл с инструкциями, который агент загружает только тогда, когда задача действительно этого требует.
1.
analyzing-dotnet-performanceПроверяет код примерно на 50 типичных проблем с производительностью: async, память, строки, коллекции, LINQ, регулярные выражения, сериализация и ввод-вывод.
2.
optimizing-ef-core-queriesБерёт медленный запрос и оптимизирует его так, чтобы генерировалось меньше SQL и было меньше обращений к базе данных.
3.
slopwatchПроверяет то, что только что сделал агент, и ищет его «срезанные углы»: отключённые тесты, подавленные предупреждения, пустые блоки
catch. В общем, всё, что помогает сборке пройти, не решая саму проблему.4.
test-gap-analysisОтвечает на вопрос: «Смогли бы мои тесты поймать эту ошибку?»
5.
testcontainersИнтеграционные тесты с реальными базами данных, очередями и кешами, которые поднимаются в Docker, вместо моков.
6.
aspire-integration-testingИнтеграционные тесты с удобствами .NET Aspire: фикстуры, распределённое приложение и автоматическое обнаружение конечных точек.
7.
binlog-failure-analysisЧитает binlog MSBuild и объясняет, почему сборка упала, когда консоль не сообщает ничего полезного.
8.
convert-to-cpmПереводит решение на Central Package Management и выравнивает версии NuGet-пакетов во всех проектах.
9.
migrate-dotnet9-to-dotnet10Обновляет
TargetFramework и исправляет несовместимые изменения в .NET 10, C# 14, ASP.NET Core 10 и EF Core 10.10.
ilspy-decompileДекомпилирует сборку, чтобы понять, как внутри работает API фреймворка или NuGet-пакет.
Мне особенно понравился №3. Сам факт того, что существует отдельный навык для проверки «срезанных углов» агента, многое говорит о текущем состоянии разработки с ИИ.
В Claude Code они устанавливаются так:
/plugin marketplace add dotnet/skills
/plugin marketplace add Aaronontheweb/dotnet-skills
Please open Telegram to view this post
VIEW IN TELEGRAM
🍾2🤩1
Пора перестать использовать
И вот почему.
Я часто разбираю .NET-проекты, и эта проблема встречается почти везде.
А потом в понедельник утром начинают падать тесты, и никто не понимает почему.
Что на самом деле ломает
→ Поведение меняется между окружениями
→ Бизнес-логика начинает зависеть от часов сервера
→ Тесты проходят у тебя и падают в другом часовом поясе
→ Нельзя просто перемотать время на «следующий месяц» или «два года назад»
→ Любая логика, зависящая от времени, становится неудобной для тестирования
Как протестировать скидку, которая заканчивается в полночь?
А последний день бесплатного периода?
Или подписку, которая должна продлиться через год?
Нормально протестировать всё это можно только тогда, когда приложение получает время из источника, которым ты можешь управлять.
Решение простое — относиться ко времени как к обычной зависимости и внедрять его.
В современном .NET есть два хороших варианта.
1. Встроенный
2. Собственный интерфейс
Для новых проектов я бы использовал
Он уже входит в платформу, умеет работать с таймерами и часовыми поясами, а вместе с
Подключение через DI занимает одну строку:
После этого внедряешь его как обычный сервис и используешь
В проде поведение остаётся тем же.
А в тестах ты наконец полностью контролируешь время.
👉 @KodBlog
DateTime.Now в коде.И вот почему.
Я часто разбираю .NET-проекты, и эта проблема встречается почти везде.
DateTime.Now раскидан по сущностям домена, бизнес-логике, валидаторам и сервисам. На ревью кода на это обычно никто не обращает внимания. Выглядит как совершенно безобидный вызов.А потом в понедельник утром начинают падать тесты, и никто не понимает почему.
Что на самом деле ломает
DateTime.Now→ Поведение меняется между окружениями
→ Бизнес-логика начинает зависеть от часов сервера
→ Тесты проходят у тебя и падают в другом часовом поясе
→ Нельзя просто перемотать время на «следующий месяц» или «два года назад»
→ Любая логика, зависящая от времени, становится неудобной для тестирования
Как протестировать скидку, которая заканчивается в полночь?
А последний день бесплатного периода?
Или подписку, которая должна продлиться через год?
Нормально протестировать всё это можно только тогда, когда приложение получает время из источника, которым ты можешь управлять.
Решение простое — относиться ко времени как к обычной зависимости и внедрять его.
В современном .NET есть два хороших варианта.
1. Встроенный
TimeProvider в .NET 8 и новее2. Собственный интерфейс
IDateTimeProvider, который работает с любой версией .NETДля новых проектов я бы использовал
TimeProvider.Он уже входит в платформу, умеет работать с таймерами и часовыми поясами, а вместе с
FakeTimeProvider позволяет в тестах перемещать время куда угодно.Подключение через DI занимает одну строку:
builder.Services.AddSingleton(TimeProvider.System);
После этого внедряешь его как обычный сервис и используешь
GetUtcNow() там, где раньше был DateTime.UtcNow.В проде поведение остаётся тем же.
А в тестах ты наконец полностью контролируешь время.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍17🍾1👀1
Самый простой способ отправлять HTTP-запросы в .NET — использовать
Но есть интересная альтернатива.
Проблема
Для этого есть отличная библиотека Refit.
Это автоматически генерируемый и типобезопасный клиент для REST API в .NET.
Под капотом Refit всё равно использует
По сути, ты описываешь API через интерфейс, а Refit сам берёт на себя большую часть рутинной работы.
👉 @KodBlog
HttpClient.Но есть интересная альтернатива.
Проблема
HttpClient в том, что при неправильном использовании можно столкнуться с исчерпанием портов и проблемами с DNS. Плюс сериализацию и десериализацию приходится настраивать вручную.Для этого есть отличная библиотека Refit.
Это автоматически генерируемый и типобезопасный клиент для REST API в .NET.
Под капотом Refit всё равно использует
HttpClient для отправки запросов, но добавляет поверх него более удобный для разработчика слой.По сути, ты описываешь API через интерфейс, а Refit сам берёт на себя большую часть рутинной работы.
Please open Telegram to view this post
VIEW IN TELEGRAM
🤨3👍2🍾1😈1
Три главных встроенных обобщённых делегата в C# — Func, Action и Predicate.
Делегаты можно воспринимать как ссылки на функции. Они используются для передачи поведения, обратных вызовов и взаимодействия между разными частями программы.
В C# есть три основных встроенных обобщённых делегата.
1️⃣ Func
Принимает значения и возвращает результат.
Например:
Func<int, string>
Здесь на вход передаётся int, а возвращается string.
2️⃣ Action
Принимает значения, но ничего не возвращает.
Например:
Action<string>
Такой делегат получает строку и выполняет какое-то действие без возвращаемого значения.
3️⃣ Predicate
Принимает значение и всегда возвращает bool.
Например:
Predicate<Student>
Он получает объект Student и проверяет некоторое условие, возвращая true или false.
Эти делегаты очень широко используются внутри .NET и позволяют не создавать собственный тип делегата каждый раз.
Простой пример.
Создаём класс Student с несколькими свойствами, затем список студентов и добавляем в него данные.
После этого можно увидеть, как разные методы работают с разными типами делегатов.
Select принимает Func.
ForEach принимает Action.
FindAll принимает Predicate.
По сути, Func используется, когда нужен результат, Action — когда нужно просто выполнить действие, а Predicate — когда нужно проверить условие и получить true или false.
👉 @KodBlog
Делегаты можно воспринимать как ссылки на функции. Они используются для передачи поведения, обратных вызовов и взаимодействия между разными частями программы.
В C# есть три основных встроенных обобщённых делегата.
1️⃣ Func
Принимает значения и возвращает результат.
Например:
Func<int, string>
Здесь на вход передаётся int, а возвращается string.
2️⃣ Action
Принимает значения, но ничего не возвращает.
Например:
Action<string>
Такой делегат получает строку и выполняет какое-то действие без возвращаемого значения.
3️⃣ Predicate
Принимает значение и всегда возвращает bool.
Например:
Predicate<Student>
Он получает объект Student и проверяет некоторое условие, возвращая true или false.
Эти делегаты очень широко используются внутри .NET и позволяют не создавать собственный тип делегата каждый раз.
Простой пример.
Создаём класс Student с несколькими свойствами, затем список студентов и добавляем в него данные.
После этого можно увидеть, как разные методы работают с разными типами делегатов.
Select принимает Func.
ForEach принимает Action.
FindAll принимает Predicate.
По сути, Func используется, когда нужен результат, Action — когда нужно просто выполнить действие, а Predicate — когда нужно проверить условие и получить true или false.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2❤1🍾1