23284
Все самое полезное для C#-разработчика в одном канале. По рекламе: @proglib_adv Учиться у нас: https://proglib.io/w/b60af5a4 Для обратной связи: @proglibrary_feeedback_bot РКН: https://gosuslugi.ru/snet/67a5c81cdc130259d5b7fead
🎮 Портфолио, в которое хочется играть
Наткнулись на резюме разраба, которое явно не пройдёт роботизированную проверку, потому что робот ничего не поймёт.
Резюме сделано в виде 3D игры, где нужно кататься на машинке по точкам интереса: проекты, места работы, соц. сети. У обычного HR'а на такое точно не хватит времени.
Челлендж от админа — попробуйте выбить страйк в левой части карты. Скидывайте скрины в комменты 👇
➡️ Выбить страйк
🐸Библиотека шарписта
#GoTalk
🧑💻 Готовые LINQ-скрипты
Шарписты, которые активно пользуются LINQPad редко хранят полезные скрипты.
Нашли личный набор рабочих скриптов для LINQPad, который автор вынес в общий GitHub репозиторий.
В репозитории лежат .linq скрипты которые помогают решать рутину в .NET проектах через LINQPad вместо отдельных утилит. Это могут быть быстрые запросы к БД, небольшие проверки, конвертеры данных и прочие «разовые» задачи которые регулярно повторяются.
➡️ Репозиторий
🔹 Специалист по ИИ
🔹 Получить консультацию менеджера
🔹 Сайт Академии 🔹 Сайт Proglib
🐸Библиотека шарписта
#sharp_view
🧑🎓 Как вуз влияет на карьеру
В экосистеме шарпа традиционно много продуктовых компаний банков и корпораций. Для них формальное образование по прежнему важнее чем в типичном веб фрилансе.
Но и здесь со временем решающим фактором становятся не корочки а опыт и стек.
➡️ Сколько стоит джун с дипломом и без
🔹 AI-агенты для DS-специалистов
🔹 Получить консультацию менеджера
🔹 Сайт Академии 🔹 Сайт Proglib
🐸Библиотека шарписта
Летим зимовать ✈️
Когда холодает, айтишники пакуют чемоданы, а мы разыгрываем ваучер на 50 000 рублей в Островке.
Поехать к морю или остаться среди снежных пейзажей — выбирайте сами!
Чтобы участвовать, нужно оставить любую реакцию под этим постом и подписаться на каналы ниже:
😎 Типичный программист
🐸 Библиотека программиста
🟢 Ostrovok! Tech
Теперь осталось нажать на кнопку участия под этим постом и вы в игре!
Итоги подведём 12 декабря. Победителя выберем с помощью бота. Подробнее с правилами можно ознакомиться здесь.
Всем удачи!
Участников: 111
Призовых мест: 1
Дата розыгрыша: 19:00, 12.12.2025 MSK (3 дня)
⭐️ Золотой стандарт для рефакторинга
Golden Master — это простой приём для безопасного рефакторинга, когда страшно ломать легаси и непонятно, как правильно должно «по идее» работать.
Идея такая: берём старую реализацию, гоняем через неё достаточно входных данных и сериализуем результат — это и есть золотой стандарт.
Потом пишем тест, который запускает старую и новую версию и сравнивает их вывод. Если совпадает — поведение не изменилось, можно смело продолжать рефакторить; если нет — либо нашли баг, либо сознательно меняем старый код.
В C# это можно сделать вообще минималистично:
// serialize output before change, compare after change
var before = JsonSerializer.Serialize(await RunOld());
var after = JsonSerializer.Serialize(await RunNew());
Assert.Equal(before, after);
👨💻 База про менеджмент в разработке
Закон Брукса — это принцип управления разработкой ПО, который говорит: если проект уже опаздывает, добавление людей чаще всего только ещё больше задерживает его.
Закон сформулировал Фредерик Брукс в книге «Мифический человеко‑месяц».
Новичков нужно онбордить: рассказывать контекст, архитектуру, правила команды. Опытные ребята вместо того чтобы закрывать задачи, превращаются в живую документацию и менторов.
Параллельно растут коммуникации: больше созвонов, больше согласований, больше мест, где можно неправильно понять требования. В какой‑то момент команда тратит больше времени на разговоры и объяснения, чем на фактическую разработку.
Практический вывод простой: «давайте накинем ещё разработчиков» — плохой универсальный ответ на проблему сроков. Гораздо полезнее заранее резать систему на независимые модули, упрощать архитектуру, улучшать документацию и процессы.
А если проект уже горит, то честный пересмотр объёма, приоритизация и выкидывание лишнего часто работают лучше, чем срочный найм.
🔹 Основы IT для непрограммистов
🔹 Получить консультацию менеджера
🔹 Сайт Академии 🔹 Сайт Proglib
🐸Библиотека шарписта
#il_люминатор
👀 Бритни, лазеры и полупроводники
Наткнулись на старый веб-артефакт — сайт, где Бритни Спирс читает курс по полупроводниковым лазерам и оптоэлектронике. Внутри не мем на один экран, а вполне учебные разборы p–n переходов, лазерных диодов и VCSEL, просто завернутые в эстетику фан-сайта двухтысячных.
Если хочется отвлечься от документации по фреймворкам и заодно освежить базу по полупроводниковым лазерам, эта старая страница сделает день чуть веселее.
➡️ Почитать курс от Бритни
🔹 Практический интенсив «Архитектуры и шаблоны проектирования»
🔹 Получить консультацию менеджера
🔹 Сайт Академии 🔹 Сайт Proglib
🐸Библиотека шарписта
Как правильно реализовать освобождение ресурсов в IAsyncDisposable?
Короткий ответ: Реализуйте шаблон с охраной от повторного вызова: DisposeAsync() вызывает приватный DisposeAsyncCore() и синхронный Dispose(false), закрывает IAsyncDisposable ресурсы через await using, остальные — в Dispose. Используйте AsyncLazy/флаг disposed, прокидывайте CancellationToken только там, где это безопасно, и учитывайте, что await using всегда вызывает именно DisposeAsync().
🔹 Курс «Программирование на языке Python»
🔹 Получить консультацию менеджера
🔹 Сайт Академии 🔹 Сайт Proglib
Библиотека собеса по С#
✏️ Задача без подвоха
Дан массив длиной 2n в виде [x1,x2,xn,y1,y2,yn] нужно вернуть массив [x1,y1,x2,y2,xn,yn], то есть перемешать.
Идея решения
Логически делим массив на две половины по n элементов и в одном цикле по индексу i собираем ответ в новый массив result.
На каждой итерации кладем сначала элемент из первой половины nums[i] потом из второй nums[i+n].
Так мы проходим вход один раз время O(n), где n это половина массива.
Решение:
public class Solution
{
public int[] Shuffle(int[] nums, int n)
{
int[] result = new int[2 * n];
int index = 0;
for (int i = 0; i < n; i++)
{
result[index++] = nums[i];
result[index] = nums[i + n];
index++;
}
return result;
}
}
n минус один вторая от n до 2n минус один, а индекс в result просто сдвигается на два шага за итерацию.
🧑💻 Честность в айти — это грех
В айти часто говорят, что честность — это слабость. Многие накручивают опыт, преувеличивают достижения и скрывают ошибки, чтобы выглядеть лучше в резюме.
Но без честности не бывает доверия и настоящего развития. Признание своих ошибок и реальных навыков помогает учиться и двигаться вперед, а не строить пирамиду из лжи.
💬 Как думаете лучше приврать или сказать как есть? Где ложь во благо, а где во вред? Делитесь в комментах своими размышлениями 👇
🔹 Практический интенсив «Архитектуры и шаблоны проектирования»
🔹 Получить консультацию менеджера
🔹 Сайт Академии 🔹 Сайт Proglib
🐸Библиотека шарписта
#entry_point
🔑 Управление HttpClient по ключам
С .NET 9 можно управлять зависимостями по ключам. Буквально регистрировать и получать, к примеру, конфиги для HttpClient.
Как это работает
• AddAsKeyed() — новый метод расширения для регистрации именованных HttpClient как Keyed Service в DI. Имя клиента становится ключом, по которому можно получать конкретный экземпляр.
• Внедрение осуществляется с помощью атрибута [FromKeyedServices("key")] или через Func<string, HttpClient> для динамического выбора клиента по ключу.
• В отличие от старых подходов с именованными или типизированными клиентами, внедрение зависимостей по ключам позволяет упростить код и уменьшить лишние вызовы фабрики IHttpClientFactory.
Пример регистрации и использования:
var builder = WebApplication.CreateBuilder(args);
// Регистрация HttpClient с ключом "github"
builder.Services.AddHttpClient("github", c =>
{
c.BaseAddress = new Uri("https://api.github.com/");
c.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json");
c.DefaultRequestHeaders.Add("User-Agent", "dotnet");
})
.AddAsKeyed();
var app = builder.Build();
// Внедрение HttpClient по ключу "github"
app.MapGet("/", ([FromKeyedServices("github")] HttpClient httpClient) =>
{
return httpClient.GetFromJsonAsync<Repo>("/repos/dotnet/runtime");
});
app.Run();
record Repo(string Name, string Url);
IHttpClientFactory.ConfigureHttpClientDefaults.AddAsKeyed() регистрирует HttpClient с областью видимости Scoped, но можно настроить и другой жизненный цикл.
👨💻 Поддержка and! в task-вычислениях F# 10
В F# 10 библиотека FSharp.Core получила улучшение — поддержку оператора and! в вычислительном выражении task.
Раньше, чтобы ждать несколько задач параллельно, нужно было либо ждать их последовательно:
task {
let! a = fetchA()
let! b = fetchB()
return combineAB a b
}Task.WhenAll для ожидания сразу всех:task {
let ta = fetchA()
let tb = fetchB()
let! results = Task.WhenAll([| ta; tb |])
return combineAB ta.Result tb.Result
}task {
let! a = fetchA()
and! b = fetchB()
return combineAB a b
}
Math for .NET Developers
Использовать ML.NET или Accord.net — это полдела. Чтобы кастомизировать модели и понимать, почему сеть не сходится, нужно лезть под капот. Там живут матрицы, производные и векторы.
Завтра стартуем курс «Математика для разработки AI-моделей».
🛠 Темы: Линал, матан, теорвер.
💸 Цена: 28 200 ₽ (новогодний прайс).
⏱ Дедлайн: Старт завтра.
Интегрируйте знания в свой стек:
🔗 Ссылка на курс
Debug your math: @proglib_academy_webinar_bot
🛠 Строгая проверка назначения атрибутов в F# 10
В F# 10 компилятор стал жёстко проверять, что атрибуты применяются только к тем конструкциям, для которых они предназначены. Это касается функций, значений, объединений, конструкторов, структур, классов и других элементов.
Раньше F# позволял неявно применять атрибуты к неподходящим целям без предупреждений. Из-за этого возникали баги, например:
• Тестовые атрибуты не работали, если функция не имела (), и тесты не запускались
• Атрибуты-анализаторы иногда игнорировались, приводя к сбоям в CI без очевидной причины.
Пример такого кода, который никак не работал:
[<Fact>]
let ``this is not a function`` = // никак не запускался тест
Assert.True(false)
[<Fact>]
//^^^^ предупреждение FS0842: атрибут нельзя применять к свойству, полю и т.п.
let ``works correctly`` =
Assert.True(true)
🌲 Подборка вакансий для шарпистов
C#/.NET Developer на удалёнку
C#/.NET Developer с ЗП от 2 500 до 5 000$
C# / .NET Разработчик, middle, middle+ — от 190 000 до 290 000 ₽
🔸 AI-агенты для DS-специалистов
🔸 Получить консультацию менеджера
🔸 Сайт Академии 🔸 Сайт Proglib
➡️ Еще больше топовых вакансий — в нашем канале C# Jobs
🐸 Библиотека шарписта
🔄 Первое сервисное обновление .NET 10
Вышло сервисное обновление для десятой версии платформы, в котором правят баги и стабильность без новых фич.
Обновление помечено как non security: оно не закрывает уязвимости, а дорабатывает поведение рантайма, BCL и SDK после выхода 10.0.0.
➡️ Release notes
🐸Библиотека шарписта
#async_news
⚙️ Останавливаем некрасивый код
Использовать dotnet format в CI удобно как «стоп кран» по стилю кода. В пайплайн достаточно добавить один шаг:
- name: Format
run: dotnet tool restore && dotnet format --verify-no-changes
.editorconfig и проверяет что код им соответствует. Ключ --verify-no-changes сообщает утилите работать в режиме проверки без правок файлов и выйти с ненулевым кодом если что то нужно переформатировать.
🐸Библиотека шарписта
#garbage_collector
📩 Быстрый антиспам
Для .NET есть готовый клиент Cloudmersive Spam Detection API который умеет проверять текстовые поля. Вместо того чтобы вручную обучать модель для спама можно отдать эту задачу готовому облачному сервису.
Для работы с API нужно поставить NuGet пакет Cloudmersive.APIClient.NET.Spam.
После установки достаточно прописать ключ API и создать экземпляр клиента:
using Cloudmersive.APIClient.NET.Spam.Client;
using Cloudmersive.APIClient.NET.Spam.Api;
using Cloudmersive.APIClient.NET.Spam.Model;
public class SpamChecker
{
private readonly SpamDetectionApi _api;
public SpamChecker(string apiKey)
{
// глобальная конфигурация
Configuration.Default.AddApiKey("Apikey", apiKey);
_api = new SpamDetectionApi();
}
}
public async Task<bool> IsSpamAsync(string text)
{
var request = new SpamDetectionAdvancedRequest
{
InputString = text,
Model = "Advanced",
// политика что считаем допустимым
AllowUnsolicitedSales = false,
AllowPromotionalContent = false,
AllowPhishing = false
};
SpamDetectionAdvancedResponse resp =
await _api.SpamDetectionAdvancedAsync(request);
// если сервис считает текст спамом реагируем
return resp.ContainsSpam ||
resp.ContainsUnsolicitedSales ||
resp.ContainsPhishingAttempt;
}
⚡️ 100 RPS на всё приложение
Rate limit — это простой способ защитить API от всплесков нагрузки, случайных «шторма» с клиента и банального DDoS по честным endpoint’ам.
В примере ниже на всё приложение вешается глобальный лимитер:
builder.Services.AddRateLimiter(o =>
{
o.GlobalLimiter = PartitionedRateLimiter.Create<HttpContext, string>(ctx =>
RateLimitPartition.GetFixedWindowLimiter("global", _ =>
new FixedWindowRateLimiterOptions
{
PermitLimit = 100,
Window = TimeSpan.FromSeconds(1)
}));
});
app.UseRateLimiter();
⚙️ Как повысить надёжность конфигурации
В современных приложениях важно не только загрузить настройки из конфигурации, но и убедиться, что они корректны. В .NET для этого есть удобный паттерн — Typed Options с встроенной валидацией.
Пример регистрации опций с проверкой данных:
builder.Services.AddOptions<AppOptions>()
.BindConfiguration("App")
.ValidateDataAnnotations() // Валидация по атрибутам из System.ComponentModel.DataAnnotations
.Validate(o => Uri.IsWellFormedUriString(o.ApiBaseUrl, UriKind.Absolute),
"ApiBaseUrl must be absolute") // Дополнительная кастомная проверка
.ValidateOnStart(); // Проверка при старте приложения
ValidateOnStart() заставляет приложение валидировать настройки сразу при запуске, а не при первом использовании.
📰 Декабрьский дайджест
Админ ждёт снега и собирает новости недели в кучу.
— Microsoft объясняет сложности управления горячими клавишами в Visual Studio 2026
Microsoft подчёркивает, что изменение горячих клавиш в Visual Studio 2026 — сложная задача из-за поддержки нескольких комбинаций для одной команды, профилей разработчиков и последовательных шорткатов.
— Бывший разработчик Microsoft потоптал Windows 11
Дейв Пламмер считает, что сейчас Windows 11 страдает от багов в обновлениях, вроде исчезновения иконки пароля на экране блокировки и дублирования процессов в Диспетчере задач.
— Microsoft предостерегает админов от устаревших .NET рантаймов
В официальном блоге Microsoft рекомендует срочно проверить наличие устаревших рантаймов и перейти на поддерживаемые версии.
— Баг в интерфейсе Windows 11 24H2 и 25H2
🔹 Программирование на языке Python
🔹 Получить консультацию менеджера
🔹 Сайт Академии 🔹 Сайт Proglib
🐸Библиотека шарписта
#async_news
🐸Библиотека шарписта
#garbage_collector
C# мощный, но математика универсальна
ML.NET развивается, но фундамент Data Science остаётся неизменным. Чтобы эффективно работать с данными (даже в .NET-среде), нужно понимать линейную алгебру и статистику.
Мы добавили живые вебинары в наш курс по математике для AI.
Программа ближайших лекций:
— Vectors & Matrices: операции, ранги, СЛАУ;
— Linear Regression: реализация МНК, интерпретация весов;
— SVD: матричные разложения и рекомендательные системы.
Практика на Python (NumPy), но алгоритмическая суть переносится на любой язык.
Регистрация закрывается 9 декабря:
https://clc.to/LojFzw
🔄 Отмена запросов в EF
В реальных приложениях бывают ситуации, когда нужно прервать долгую операцию с базой данных, если она больше не актуальна или пользователь отменил действие.
Долгие запросы или операции сохранения могут повиснуть или перерасходовать системные ресурсы, если не предусмотрена возможность прерывания.
В Entity Framework для управления отменой используется CancellationToken. Его можно передавать в асинхронные методы, например:
await db.SaveChangesAsync(ct);
❗️ Microsoft признала масштабный баг в интерфейсе Windows 11 24H2 и 25H2
У части пользователей Windows 11 после установки последних обновлений в версиях 24H2 и 25H2 начали ломаться ключевые элементы интерфейса.
Проблема затрагивает базовые функции оболочки и выглядит как обычный «заглючивший» рабочий стол, но на деле связана с ошибками в самих системных компонентах.
Временное решение — установка актуальных патчей, использование опубликованных обходных скриптов или откат проблемных обновлений, если интерфейс стал нестабильным после апдейта.
➡️ Источник
🔹 Математика для разработки AI-моделей
🔹 Получить консультацию менеджера
🔹 Сайт Академии 🔹 Сайт Proglib
🐸Библиотека шарписта
#async_news
⚙️ Используйте AsNoTracking() для запросов только на чтение
Если нужно получить данные из базы без их изменения, лучше использовать AsNoTracking():
var posts = await db.Posts.AsNoTracking()
.Where(p => p.Published)
.ToListAsync(ct);
AsNoTracking() говорит Entity Framework не отслеживать изменения для полученных объектов.
🛠 .NET MAUI и работа с возрастом
С началом 2026 года в США вступают в силу новые требования по верификации возраста пользователей для мобильных и десктопных приложений.
Да, это затрагивает несколько штатов в США, но стоит держать руку на пульсе.
.NET MAUI предоставляет удобный способ решения этой задачи с помощью единого интерфейса IAgeSignalService и трёх платформо-специфичных реализаций:
• Для Android используется Google Play Age Signals API, который возвращает пять статусов в зависимости от ситуации: от подтверждённого возраста до ожидания одобрения опекуна.
• На iOS применяется Apple Declared Age Range API, работающий на устройствах с iOS 26 и выше, отображающий возрастной диапазон и информацию о том, кто его подтвердил — сам пользователь или опекун.
• Windows предлагает Windows Age Consent API с упрощённой классификацией пользователей на три категории: ребёнок, несовершеннолетний и взрослый.
Главное преимущество — единая точка интеграции и адаптация под каждый API за счёт условной компиляции и инъекции зависимостей. Достаточно подключить сервис в MauiProgram, чтобы обеспечить проверку возраста на нужной платформе.
➡️ Блог Microsoft
🔹 AI-агенты для DS-специалистов
🔹 Получить консультацию менеджера
🔹 Сайт Академии 🔹 Сайт Proglib
🐸Библиотека шарписта
#sharp_view
🧑💻 Проекция колонок вместо сущностей в запросах
Когда работаете с базой данных, лучше получить только нужные поля, а не всю сущность. Это ускорит запросы и снизит объём передаваемых данных.
Пример проекции колонок с использованием LINQ:
var dto = await db.Users
.Where(u => u.Id == id)
.Select(u => new UserDto(u.Id, u.Name))
.SingleOrDefaultAsync(ct);
🔍 Устаревший синтаксис в F# 10
Раньше F# позволял опускать ключевое слово seq при создании последовательностей, что выглядело так:
{ 1..10 } |> List.ofSeq // неявная последовательностьseq { 1..10 } |> List.ofSeq