Одна из самых неприятных просадок производительности в C# начинается не с LINQ операторов, а с того, что коллекции начинают жить как
IEnumerable.Пример который встречается постоянно:
IEnumerable<Order> orders = GetOrders();
if (orders.Count() > 0)
{
// do something
}
Если внутри реально
List или массив, то количество элементов доступно быстро через свойство Count или Length, то есть без прохода по данным.Но
Count() как LINQ метод обязан работать для любого IEnumerable, поэтому в общем случае он перечисляет элементы, пока не посчитает все.Так проверка на пустоту внезапно становится полным обходом, и это особенно больно если orders это запрос с отложенным выполнением или поток данных.
А если хочется сохранить быстрый путь для коллекций, можно явно проверить интерфейс с Count:
if (orders is ICollection<Order> collection)
{
if (collection.Count > 0)
{
// fast path
}
}
else if (orders.Any())
{
// fallback
}
Если в профилировщике внезапно появился лишний проход по данным, стоит проверить где коллекция превратилась в
IEnumerable и где после этого зовется Count().📍 Навигация: Вакансии • Задачи • Собесы
#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
🥱11👍9❤1🤔1😢1
Roadmap для .NET-разработчика: от промптов к Semantic Kernel
ИИ-агенты становятся стандартом автоматизации. Для тех, кто работает в экосистеме
Ваш план развития:
— понимание основ агентной логики и
— проектирование систем памяти и доступа к данным;
— создание мультиагентных пайплайнов для рабочих задач;
— интеграция агентов в бизнес-процессы компании.
Курс «Разработка ИИ-агентов» — это интенсивный путь от теории до создания сложных производственных систем.
Начать погружение в ИИ
До 19 января купите курс и заберите два дополнительных в подарок (акция «3 в 1»).
ИИ-агенты становятся стандартом автоматизации. Для тех, кто работает в экосистеме
Microsoft, это шанс занять нишу архитектора автономных систем.Ваш план развития:
— понимание основ агентной логики и
Reasoning;— проектирование систем памяти и доступа к данным;
— создание мультиагентных пайплайнов для рабочих задач;
— интеграция агентов в бизнес-процессы компании.
Курс «Разработка ИИ-агентов» — это интенсивный путь от теории до создания сложных производственных систем.
Начать погружение в ИИ
До 19 января купите курс и заберите два дополнительных в подарок (акция «3 в 1»).
🥱12👏1🌚1
🌐 Браузер без всего лишнего
Наткнулись на проект, который помогает вырезать из Chrome, Edge и Firefox всё лишнее, что не относится к работе браузера.
Что сносит:
• AI-фичи (Copilot в Edge, AI-саммари в Chrome)
• Телеметрия и отчёты об использовании
• Спонсорский контент и реклама
• Интеграция сторонних продуктов
• Рекомендованные новости и виджеты
• Бесполезные UI-элементы
Вместо ручного копания в about:config или реестре Windows — готовые конфиги + скрипты установки.
➡️ Удалить мусор из браузера
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека шарписта
#async_news
Наткнулись на проект, который помогает вырезать из Chrome, Edge и Firefox всё лишнее, что не относится к работе браузера.
Что сносит:
• AI-фичи (Copilot в Edge, AI-саммари в Chrome)
• Телеметрия и отчёты об использовании
• Спонсорский контент и реклама
• Интеграция сторонних продуктов
• Рекомендованные новости и виджеты
• Бесполезные UI-элементы
Вместо ручного копания в about:config или реестре Windows — готовые конфиги + скрипты установки.
📍 Навигация: Вакансии • Задачи • Собесы
#async_news
Please open Telegram to view this post
VIEW IN TELEGRAM
❤🔥7👍2😢2😁1
Проблема LINQ в горячих местах обычно не в вычислениях, а в том, что вокруг каждого запроса появляются маленькие кусочки инфраструктуры.
Where и Select сами по себе ленивые, они не выполняются пока не началось перечисление. Но как только появляется ToArray, начинается реальная работа и выделяется новый массив под результатЕсли внутри цикла постоянно вызывается
ToArray, то постоянно создаются новые массивы.Если еще и лямбды захватывают переменные, добавляются лишние замыкания, и это тоже может стать частью мусора, который потом будет собирать GC.
Пример:
foreach (var batch in batches)
{
var validItems = batch
.Where(IsValid)
.Select(Transform)
.ToArray();
Process(validItems);
}
Ручной цикл выглядит скучнее, но дает контроль над буфером и позволяет переиспользовать память:
var buffer = new List<Result>(batch.Count);
foreach (var item in batch)
{
if (!IsValid(item))
continue;
buffer.Add(Transform(item));
}
Process(CollectionsMarshal.AsSpan(buffer));
buffer.Clear();
CollectionsMarshal.AsSpan дает доступ к внутреннему массиву List как Span, то есть можно передать данные дальше без копирования, но важно не менять List пока Span используется.📍 Навигация: Вакансии • Задачи • Собесы
#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
🥱7👍5👾5❤1
🏭 Новая база корпоративной культуры
В 2025 году индустрия провела эксперимент и пришла к циничному выводу: забота о сотрудниках экономически невыгодна. Теперь карьерный рост зависит не от крутого продукта, а от способности закрывать KPI и не сгореть раньше коллег.
Почему так произошло и кто в этом виноват — разбираемся в статье.
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека шарписта
В 2025 году индустрия провела эксперимент и пришла к циничному выводу: забота о сотрудниках экономически невыгодна. Теперь карьерный рост зависит не от крутого продукта, а от способности закрывать KPI и не сгореть раньше коллег.
Почему так произошло и кто в этом виноват — разбираемся в статье.
📍 Навигация: Вакансии • Задачи • Собесы
Please open Telegram to view this post
VIEW IN TELEGRAM
😢3👏1🤩1🥱1
В дефолтном микшере Windows 11 для настройки громкости отдельных приложений нужно сделать много действий:
1. В меню найти иконку громкости и кликнуть по ней
2. Кликнуть по ещё одной иконке в выпавшем меню
3. Пролистать вниз и настроить громкость.
Мод с Windhawk меняет это: наводим на иконку звука в таскбаре — прокручиваем колёсико мыши — сразу меняем громкость активного приложения.
📍 Навигация: Вакансии • Задачи • Собесы
#async_news
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4
SelectMany проектирует каждый элемент во вложенную последовательность и потом склеивает эти последовательности в одну общую.
И это отличный выбор для чистой проекции без сложной логики, когда нужно ровно развернуть коллекцию коллекций.
Но если в задаче появляется управление потоком или условия выхода:
var allItems = orders
.SelectMany(o => o.Items)
.Where(i => i.IsActive)
.ToList();
Цикл часто дает больше ясности и предсказуемости:
var allItems = new List<Item>();
foreach (var order in orders)
{
foreach (var item in order.Items)
{
if (!item.IsActive)
continue;
allItems.Add(item);
}
}
Плюс тут легко вставить
break, continue, счетчики, ограничения, и не гадать как они сложатся с отложенным выполнением.📍 Навигация: Вакансии • Задачи • Собесы
#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔9😁1🥱1
«Этот манёвр будет стоить нам 51 год...»
Для
В Proglib Academy поднимаются цены. Успейте забрать курс по старой стоимости:
— Разработка ИИ-агентов
— Математика для разработки AI-моделей
— ML для старта в Data Science
— Математика для Data Science
— Специалист по ИИ
— Алгоритмы и структуры данных
— Программирование на Python
— Основы IT для непрограммистов
— Архитектуры и шаблоны проектирования
Забрать по старой цене
⚠️ Повышение уже 19 января
Для
.NET разработчика архитектура и алгоритмы — это база. Если вы хотите проектировать сложные системы или внедрять ИИ в свои энтерпрайз-решения, сейчас лучший момент для старта.В Proglib Academy поднимаются цены. Успейте забрать курс по старой стоимости:
— Разработка ИИ-агентов
— Математика для разработки AI-моделей
— ML для старта в Data Science
— Математика для Data Science
— Специалист по ИИ
— Алгоритмы и структуры данных
— Программирование на Python
— Основы IT для непрограммистов
— Архитектуры и шаблоны проектирования
Забрать по старой цене
⚠️ Повышение уже 19 января
🥱4
Паттерн стратегия подходит, когда один и тот же сценарий можно выполнить несколькими способами, и выбор зависит от условий. Вместо большого
switch внутри сервиса разные варианты выносятся в отдельные классы с общим интерфейсом, а контекст просто делегирует работу выбранной реализации.Типовая схема такая. Есть интерфейс
Strategy, есть несколько конкретных стратегий, и есть контекст, который держит ссылку на стратегию и вызывает ее метод, не зная деталей реализации. Это снижает связность и позволяет добавлять новые варианты без переписывания старого кода.Мини пример на C#:
public interface IDiscountStrategy
{
decimal Apply(decimal total);
}
public sealed class RegularDiscount : IDiscountStrategy
{
public decimal Apply(decimal total) => total;
}
public sealed class VipDiscount : IDiscountStrategy
{
public decimal Apply(decimal total) => total * 0.9m;
}
public sealed class Checkout
{
private readonly IDiscountStrategy _discount;
public Checkout(IDiscountStrategy discount) => _discount = discount;
public decimal TotalWithDiscount(decimal total) => _discount.Apply(total);
}
Если стратегия выбирается по условиям, условие должно выбирать объект, а не ветку кода:
var checkout = serviceProvider.GetRequiredService<Checkout>();
var total = checkout.TotalWithDiscount(100m);
Выбор стратегии лучше делать на границе приложения, например в фабрике или при конфигурации через DI, потому что прямое создание зависимостей внутри сервиса жестко привязывает код к конкретной реализации.
📍 Навигация: Вакансии • Задачи • Собесы
#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
❤12
🔄 .NET: январские обновления
Microsoft выпустила очередную порцию сервисных обновлений для платформы .NET. Вышли новые версии для трёх поддерживаемых веток:
.NET 10.0.2 — самая свежая версия платформы
.NET 9.0.12 — актуальная STS-версия
.NET 8.0.23 — предыдущая LTS-версия
➡️ Блог разработчиков
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека шарписта
#async_news
Microsoft выпустила очередную порцию сервисных обновлений для платформы .NET. Вышли новые версии для трёх поддерживаемых веток:
.NET 10.0.2 — самая свежая версия платформы
.NET 9.0.12 — актуальная STS-версия
.NET 8.0.23 — предыдущая LTS-версия
📍 Навигация: Вакансии • Задачи • Собесы
#async_news
Please open Telegram to view this post
VIEW IN TELEGRAM
🌚2
🧑💻 Исключения — не для обычного управления потоком
Исключения во флоу — это не просто дорогие операции. Они дороги когнитивно: затуманивают логику программы и размывают границу между ошибкой и нормальным поведением.
Антипаттерн, который всё ещё встречается:
Отсутствие ключа в словаре — это не исключительная ситуация. Это ожидаемый сценарий. Использование exceptions в таких случаях передаёт неправильный смысл и усложняет отладку, когда происходят настоящие ошибки.
Правильный подход — явное ветвление:
Этот код читается понятно, работает быстрее и сохраняет исключения значимыми.
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека шарписта
#sharp_view
Исключения во флоу — это не просто дорогие операции. Они дороги когнитивно: затуманивают логику программы и размывают границу между ошибкой и нормальным поведением.
Антипаттерн, который всё ещё встречается:
{
var value = dictionary[key];
Process(value);
}
catch (KeyNotFoundException)
{
// ignore
}Отсутствие ключа в словаре — это не исключительная ситуация. Это ожидаемый сценарий. Использование exceptions в таких случаях передаёт неправильный смысл и усложняет отладку, когда происходят настоящие ошибки.
Правильный подход — явное ветвление:
if (dictionary.TryGetValue(key, out var value))
{
Process(value);
}
Этот код читается понятно, работает быстрее и сохраняет исключения значимыми.
📍 Навигация: Вакансии • Задачи • Собесы
#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
🥱9❤6👍5😁2
Прошла первая рабочая неделя 2026 года. Собираем яркие материалы и новости в один пост.
— Microsoft показали как делать виджеты
— Удаляем хлам из браузера
— Новая база корпоративной культуры
— Январские обновления .NET
— Скоро будет домен .meow
📍 Навигация: Вакансии • Задачи • Собесы
#async_news
Please open Telegram to view this post
VIEW IN TELEGRAM
❤2
Anonymous Poll
34%
Плохая привычка сортировать при поиске значения
20%
Виджеты для Android в .NET MAUI
43%
GroupBy в LINQ
15%
Добавляем картинку в PDF
13%
Браузер без лишнего
30%
Паттерн стратегия
public const Price = OldPrice; // до 20.01Мы меняем значение константы: завтра обучение станет дороже. Успейте пробросить заказ сегодня, чтобы зафиксировать текущую стоимость в своём стеке.
Инициализировать рост компетенций
🥱2👍1
🚀 Одна строка кода для ускорения EF Core
Когда EF Core загружает связанные сущности через
Пример:
При 100 постах, у каждого по 10 комментариев, в каждом по 10 реакций — вместо 11 100 записей получаем результирующий набор на 10 000 строк.
Добавьте
Query Splitting — это не хак и не костыль. Это правильный способ работы с EF Core в read-heavy сценариях.
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека шарписта
#il_люминатор
Когда EF Core загружает связанные сущности через
Include(), он генерирует один огромный SQL-запрос с множеством JOIN. Результат? Тысячи дублирующихся строк, гигабайты трафика и медленная работа.Пример:
var posts = await context.Posts
.Include(p => p.Comments)
.ThenInclude(c => c.Reactions)
.ToListAsync();
При 100 постах, у каждого по 10 комментариев, в каждом по 10 реакций — вместо 11 100 записей получаем результирующий набор на 10 000 строк.
Добавьте
.AsSplitQuery() — и EF Core разобьёт один большой запрос на несколько маленьких:var posts = await context.Posts
.AsSplitQuery() // ← магия здесь
.Include(p => p.Comments)
.ThenInclude(c => c.Reactions)
.ToListAsync();
Query Splitting — это не хак и не костыль. Это правильный способ работы с EF Core в read-heavy сценариях.
📍 Навигация: Вакансии • Задачи • Собесы
#il_люминатор
Please open Telegram to view this post
VIEW IN TELEGRAM
👍21❤1😁1
🛠 Parallel.For — когда циклы работают параллельно
Представьте: у вас есть массив из миллиона элементов, и каждый нужно обработать. Обычный цикл for будет делать это последовательно — один элемент за другим. А что если задействовать все ядра процессора?
Базовое использование:
Вот и всё. Task Parallel Library сам распределит работу по потокам, сам управляет ThreadPool, сам балансирует нагрузку.
Когда это имеет смысл:
+ Обработка изображений, видео
+ Математические вычисления
+ Парсинг больших объёмов данных
+ Криптографические операции
Не подходит:
- Обработка меньше 100 элементов
- Операции с базой данных или API
- Быстрые операции вроде i * 2
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека шарписта
#sharp_view
Представьте: у вас есть массив из миллиона элементов, и каждый нужно обработать. Обычный цикл for будет делать это последовательно — один элемент за другим. А что если задействовать все ядра процессора?
Базовое использование:
// Было
for (int i = 0; i < 1000; i++)
{
ProcessImage(images[i]);
}
// Стало
Parallel.For(0, 1000, i =>
{
ProcessImage(images[i]);
});
Вот и всё. Task Parallel Library сам распределит работу по потокам, сам управляет ThreadPool, сам балансирует нагрузку.
Когда это имеет смысл:
+ Обработка изображений, видео
+ Математические вычисления
+ Парсинг больших объёмов данных
+ Криптографические операции
Не подходит:
- Обработка меньше 100 элементов
- Операции с базой данных или API
- Быстрые операции вроде i * 2
📍 Навигация: Вакансии • Задачи • Собесы
#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
❤15🥱2
👍 JIT .NET 10 убирает абстракции почти бесплатно
В .NET 10 Microsoft сильно доработали JIT компилятор. Цель простая сделать так, чтобы привычный высокоуровневый С# код работал почти как вручную вылизанный низкоуровневый.
Главная идея обновления JIT убрать лишнюю цену за высокоуровневые конструкции. Раньше интерфейсы, делегаты, итераторы легко приносили дополнительные аллокации и лишнюю индирекцию, сейчас JIT старается пробиться сквозь них к конкретным типам и генерировать более плотный машинный код.
Ключевой механизм это улучшенный escape analysis. Если JIT может доказать, что объект живет только внутри метода не передается наружу и не сохраняется в поля, он размещает его на стеке.
Пример:
В старой версии платформы такой код почти гарантировал лишнюю аллокацию делегата и замыкания в куче.
По сути JIT делает за разработчика ту оптимизацию которую раньше приходилось реализовывать вручную через отказ от лямбд и делегатов на горячем пути.
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека шарписта
#il_люминатор
В .NET 10 Microsoft сильно доработали JIT компилятор. Цель простая сделать так, чтобы привычный высокоуровневый С# код работал почти как вручную вылизанный низкоуровневый.
Главная идея обновления JIT убрать лишнюю цену за высокоуровневые конструкции. Раньше интерфейсы, делегаты, итераторы легко приносили дополнительные аллокации и лишнюю индирекцию, сейчас JIT старается пробиться сквозь них к конкретным типам и генерировать более плотный машинный код.
Ключевой механизм это улучшенный escape analysis. Если JIT может доказать, что объект живет только внутри метода не передается наружу и не сохраняется в поля, он размещает его на стеке.
Пример:
[Benchmark]
[Arguments(42)]
public int SumWithOffset(int offset)
{
Func<int, int> addOffset = value => value + offset;
return ApplyTwice(addOffset, offset);
}
В старой версии платформы такой код почти гарантировал лишнюю аллокацию делегата и замыкания в куче.
По сути JIT делает за разработчика ту оптимизацию которую раньше приходилось реализовывать вручную через отказ от лямбд и делегатов на горячем пути.
📍 Навигация: Вакансии • Задачи • Собесы
#il_люминатор
Please open Telegram to view this post
VIEW IN TELEGRAM
👍29
Сделаем минимальный код для чтения таблиц для конвертации в JSON.
Подключите NuGet-пакеты
FreeSpire.XLS и Newtonsoft.Json. Первая читает .xlsx без зависимостей, вторая формирует JSON.Код начинается с загрузки файла в поток. Библиотека преобразует лист в DataSet, где строки становятся объектами. Первая строка служит заголовками полей.
Чтение и конвертация данных:
using Spire.Xls;
using Newtonsoft.Json;
Workbook wb = new Workbook();
wb.LoadFromFile("данные.xlsx");
DataTable таблица = wb.Worksheets.ExportDataTable();
JsonSerializerSettings опции = new JsonSerializerSettings
{
Formatting = Formatting.Indented,
NullValueHandling = NullValueHandling.Ignore
};
string результат = JsonConvert.SerializeObject(таблица, опции);
File.WriteAllText("выход.json", результат);
Игнорируйте null для компактности. Форматируйте даты единообразно. Тестируйте на реальных данных — библиотека FreeSpire.XLS ограничена объемом, но достаточна для большинства случаев.
📍 Навигация: Вакансии • Задачи • Собесы
#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🥱2
🧬 Мутационное тестирование
Вы пишете unit-тесты, coverage показывает 80-90%, но уверены ли вы, что эти тесты реально ловят баги? Мутационное тестирование помогает проверить качество самих тестов.
Суть подхода
Инструмент автоматически вносит небольшие изменения в ваш код: меняет операторы, условия, константы. Если тесты проходят с «поломанным» кодом — значит, они недостаточно строгие.
Stryker.NET в действии
Установка занимает пару минут через
• Какие мутации выжили
• Mutation Score — процент убитых мутантов
• Конкретные строки кода, где тесты слабые
Практический пример
Допустим, у вас метод проверяет возраст пользователя. Stryker меняет
Stryker умеет работать с xUnit, NUnit, MSTest. Настраивается через JSON-файл, где можно указать пороговые значения mutation score, исключить файлы из анализа, настроить уровни логирования.
Процесс требует времени — каждая мутация прогоняет весь набор тестов. Но результат того стоит: вы находите слепые зоны в тестовом покрытии, которые обычный coverage не показывает.
➡️ Репозиторий
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека шарписта
#il_люминатор
Вы пишете unit-тесты, coverage показывает 80-90%, но уверены ли вы, что эти тесты реально ловят баги? Мутационное тестирование помогает проверить качество самих тестов.
Суть подхода
Инструмент автоматически вносит небольшие изменения в ваш код: меняет операторы, условия, константы. Если тесты проходят с «поломанным» кодом — значит, они недостаточно строгие.
Stryker.NET в действии
Установка занимает пару минут через
dotnet tool. После запуска Stryker анализирует код, создаёт мутантов и прогоняет по ним тесты. В отчёте вы видите:• Какие мутации выжили
• Mutation Score — процент убитых мутантов
• Конкретные строки кода, где тесты слабые
Практический пример
Допустим, у вас метод проверяет возраст пользователя. Stryker меняет
age >= 18 на age > 18. Если тест с граничным значением 18 отсутствует — мутант выживает, и вы понимаете, где дописать проверку.Stryker умеет работать с xUnit, NUnit, MSTest. Настраивается через JSON-файл, где можно указать пороговые значения mutation score, исключить файлы из анализа, настроить уровни логирования.
Процесс требует времени — каждая мутация прогоняет весь набор тестов. Но результат того стоит: вы находите слепые зоны в тестовом покрытии, которые обычный coverage не показывает.
📍 Навигация: Вакансии • Задачи • Собесы
#il_люминатор
Please open Telegram to view this post
VIEW IN TELEGRAM
❤14🤔3