C# (C Sharp) programming
По всем вопросам- @notxxx1 Реестр РКН: https://clck.ru/3Fk3kb #VRHSZ
Show more📈 Analytical overview of Telegram channel C# (C Sharp) programming
Channel C# (C Sharp) programming (@csharp_ci) in the Russian language segment is an active participant. Currently, the community unites 18 319 subscribers, ranking 7 281 in the Technologies & Applications category and 36 747 in the Russia region.
📊 Audience metrics and dynamics
Since its creation on невідомо, the project has demonstrated rapid growth, gathering an audience of 18 319 subscribers.
According to the latest data from 23 June, 2026, the channel demonstrates stable activity. Although there has been a change in the number of participants by 27 over the last 30 days and by 4 over the last 24 hours, overall reach remains high.
- Verification status: Not verified
- Engagement rate (ER): The average audience engagement rate is 17.49%. Within the first 24 hours after publication, content typically collects 7.97% reactions from the total number of subscribers.
- Post reach: On average, each post receives 3 204 views. Within the first day, a publication typically gains 1 460 views.
- Reactions and interaction: The audience actively supports content: the average number of reactions per post is 0.
- Thematic interests: Content is focused on key topics such as .net, api, логика, архитектура, string.
📝 Description and content policy
The author describes the resource as a platform for expressing subjective opinions:
“По всем вопросам- @notxxx1
Реестр РКН: https://clck.ru/3Fk3kb
#VRHSZ”
Thanks to the high frequency of updates (latest data received on 24 June, 2026), the channel maintains relevance and a high level of publication reach. Analytics show that the audience actively interacts with content, making it an important point of influence in the Technologies & Applications category.
Data loading in progress...
| Date | Subscriber Growth | Mentions | Channels | |
| 24 June | +1 | |||
| 23 June | +11 | |||
| 22 June | +10 | |||
| 21 June | +4 | |||
| 20 June | +3 | |||
| 19 June | +4 | |||
| 18 June | +11 | |||
| 17 June | +5 | |||
| 16 June | +3 | |||
| 15 June | +5 | |||
| 14 June | +4 | |||
| 13 June | +8 | |||
| 12 June | +6 | |||
| 11 June | +8 | |||
| 10 June | +10 | |||
| 09 June | 0 | |||
| 08 June | 0 | |||
| 07 June | +2 | |||
| 06 June | +3 | |||
| 05 June | +12 | |||
| 04 June | +10 | |||
| 03 June | +8 | |||
| 02 June | +4 | |||
| 01 June | +4 |
docker-compose.yml, опишите сервисы в AppHost. Aspire Docker publisher сможет сгенерировать Compose-артефакты из этой модели.
Но важно понимать границу: Aspire не деплоит приложение за вас.
Он не заменяет CI/CD, не управляет секретами и не переносит контейнеры на сервер. Вам всё равно нужно собрать image, задать реальные env-переменные, скопировать файлы и запустить Docker Compose.
Зато это хороший баланс: меньше ручной YAML-рутины, но без магии, которая скрывает реальную схему деплоя.| 2 | 🖥 На Stepik обновили курс «C# с нуля до профи»
Представьте: через четыре месяца вы открываете чужой .NET-проект и читаете его как книгу.
IServiceCollection не вызывает ступора. async Task<IActionResult> пишется на автомате. Вы точно знаете, почему EF Core сгенерировал именно такой SQL - и как переписать запрос, чтобы он летал.
Это не фантазия. Это результат после 16 модулей, в которых каждая концепция объясняется через код и закрепляется практикой.
ООП, SOLID, LINQ, async/await, DI, EF Core, ASP.NET Core, Docker, Kubernetes - всё, что казалось магией, станет рабочим инструментом.
А бонусом - портфолио проектов: от CLI-утилит и REST API до собственного SaaS с multi-tenancy, JWT и деплоем в Kubernetes под TLS.
Скидка - 58% доступна 48 часов: https://stepik.org/a/282984/ | 1 466 |
| 3 | Тест прошёл. А PostgreSQL вообще в курсе?
Интеграционные тесты часто выглядят надёжно ровно до того момента, пока приложение не встречается с настоящей базой.
На локалке всё зелёное. В CI всё зелёное. Моки довольны. In-memory база тоже не против. А потом в проде внезапно выясняется, что реальный PostgreSQL иначе обрабатывает запрос, constraint не даёт сохранить данные, транзакция ведёт себя не так, как ожидалось, а Redis показывает проблему, которую тесты вообще не могли поймать.
Именно поэтому Testcontainers в .NET так хорошо заходят для интеграционных тестов. Вместо имитации базы вы поднимаете настоящий PostgreSQL, Redis или другой сервис в Docker-контейнере, прогоняете приложение против реальной зависимости и удаляете контейнер после тестов.
Это даёт намного больше уверенности, чем тесты против подмены. При этом не нужен общий тестовый сервер, который кто-то сломал, не почистил или настроил иначе.
В хорошей схеме контейнеры запускаются через fixture, приложение получает connection string динамически, версии образов фиксируются, а настройка прячется за небольшими helper-классами. Сам тест при этом остаётся читаемым: он проверяет бизнес-сценарий, а не превращается в простыню из настройки базы и очистки состояния.
Есть важный нюанс. Общие fixtures ускоряют тесты, но требуют дисциплины со shared state. Когда изоляция важнее скорости, лучше использовать отдельные fixtures и не ловить фантомные падения из-за данных, оставшихся от соседнего теста.
Мне нравится этот подход именно за баланс. Вы тестируете не идеальную игрушечную модель приложения, а поведение, максимально близкое к реальному окружению. Но без боли ручной инфраструктуры.
Поэтому в следующий раз, когда интеграционный тест прошёл против in-memory базы, стоит задать неприятный вопрос: а настоящая база с ним согласится? | 1 774 |
| 4 | Кеширование в ASP.NET Core: от IMemoryCache до Redis
Приложение работает быстро — пока растёт нагрузка на базу, увеличивается время ответа API, а масштабирование инфраструктуры не начинает обходиться слишком дорого.
Кеширование помогает снизить количество запросов к хранилищам, ускорить работу сервисов и эффективнее использовать ресурсы. Но результат зависит от того, какие данные попадают в кеш, где он хранится и как устроена инвалидация.
На открытом вебинаре разберём:
— какие данные стоит кешировать, а какие — нет;
— как выбрать стратегию инвалидации;
— как работают HTTP Cache, UseResponseCaching и IMemoryCache в ASP.NET Core;
— когда нужен распределённый кеш через IDistributedCache;
— как использовать Redis и чем он отличается от Memcached.
Открытый урок пройдёт 25 июня в 20:00 МСК в преддверии старта курса «C# ASP.NET Core разработчик».
Подробности и регистрация: https://otus.pw/wSp1/?erid=2W5zFJU5ydB
Реклама. ООО "ОТУС ОНЛАЙН-ОБРАЗОВАНИЕ". ИНН 9705100963. | 1 429 |
| 5 | Аллокации, которых нет в коде: охота на скрытый боксинг в .NET 10
Самая дорогая аллокация в вашем сервисе та, которой нет в исходниках. Вы написали struct ради zero-allocation, прошли code review, а в проде Gen0-коллекции все равно идут косяком. Потому что между вашим кодом и машинным кодом стоит компилятор, и он молча упаковывает ваш value-тип в кучу там, где вы этого не просили — а на код-ревью этого не видно.
TL;DR. Боксинг (boxing) в .NET - это не только object o = 42. Он прячется в вызовах интерфейсных методов на struct, в дефолтном ValueType.Equals, в params object[]-аргументах, в foreach по интерфейсу и в замыканиях. При этом часть “классических” примеров боксинга из старых гайдов на современном рантайме уже не аллоцирует — JIT научился их вырезать, и слепо копировать советы десятилетней давности вредно. Ниже — карта мест, где боксинг живёт и сейчас, отдельный разбор того, что рантайм уже оптимизировал, реальный мини-кейс, воспроизводимый бенчмарк на BenchmarkDotNet с MemoryDiagnoser, способ ловить упаковку через DOTNET_JitDisasm и dotnet-gcdump, и паттерны лечения без потери читаемости.
О версиях и числах. Всё прверялось на .NET 10 (текущий LTS) и C# 13/14-уровне компилятора, Release, без отладчика, BenchmarkDotNet с MemoryDiagnoser. На .NET 8/9 поведение в основном такое же, но отдельные оптимизации JIT отличаются между мажорными версиями — поэтому главный принцип статьи: не верьте на слово (в том числе мне), гоняйте MemoryDiagnoser на своей версии рантайма. Числа в таблицах ниже - иллюстративные, порядок величины, а не точные замеры с вашего железа.
Пролог: “у нас же всё на struct, откуда Gen0?”
Сервис на горячем пути считает метрики: миллионы маленьких readonly struct-значений в секунду, никакого new, никаких классов в hot path. По задумке — ноль аллокаций. На дашборде — стабильный поток Gen0-коллекций раз в несколько секунд под нагрузкой.
Профайлер показывает аллокации, но стек ведёт в метод, где в коде нет ни одного new. Там цикл по интерфейсу, пара вызовов .Equals(), передача значения в params-метод лога. Глазами — чисто. В машинном коде — box-инструкции на каждой итерации.
Это и есть скрытый боксинг: компилятор C# и JIT упаковывают ваш struct в объект на куче, потому что в конкретной точке кода value-тип нужно представить как ссылочный. Симптом — Gen0-коллекции “из ниоткуда”, и его не видно ни в code review, ни в дампе, пока не посмотришь на IL или дизасм.
Если тема близка - я регулярно разбираю такие штуки по C# и .NET (внутренности рантайма, перформанс, неочевидные грабли с замерами и дизасмом) в своём Telegram-канале: t.me/csharp_ci. Заходите, если интересно копаться глубже.
Что такое боксинг и почему он стоит дорого
Боксинг — это упаковка value-типа (struct, enum, примитив) в объект на управляемой куче. Рантайму нужно выделить заголовок объекта, скопировать туда значение и вернуть ссылку. Анбоксинг - обратная операция с проверкой типа.
Цена не в самой инструкции, а в последствиях: каждая упаковка - это аллокация в Gen0. Много мелких аллокаций на горячем пути означают частые Gen0-коллекции, паузы (пусть и короткие), вытеснение полезных данных из кэша и общий рост CPU на ровном месте. На сервисе с SLA по p99 это бьёт по хвосту латентности так же, как и любая другая лишняя аллокация.
В IL боксинг виден явно - инструкция box. Именно её мы и будем искать.
Читать дальше: https://habr.com/ru/articles/1049236/ | 1 765 |
| 6 | ⚡️ Геймдеверы, обновляемся: Unreal Engine 5.8 уже вышел
Epic Games выпустила Unreal Engine 5.8.
Ссылка:
https://www.unrealengine.com/news/unreal-engine-5-8-is-now-available
Главное обновление для всех, кто следит за AI в геймдеве: в движок добавили поддержку MCP.
Теперь Claude, Gemini и другие AI-агенты могут напрямую подключаться к Unreal Engine, видеть структуру проекта и выполнять задачи внутри редактора. Не просто советовать в чате, а реально работать с сценой.
На демо агент создаёт целый городской квартал прямо в Unreal Editor. Это уже не «ИИ поможет написать промпт», а шаг к агентам, которые собирают уровни, прототипируют локации, правят ассеты и ускоряют production pipeline.
Похоже, поток AI-контента в играх только начинается.
Скачать:
https://www.unrealengine.com/download | 3 334 |
| 7 | Fenwick Tree на C#: всё держится на одном битовом трюке
Fenwick Tree, или Binary Indexed Tree, считает prefix sums за O(log n).
Главная операция:
i & -i
Она находит младший установленный бит числа.
Именно это значение говорит структуре, на сколько нужно прыгнуть по индексам.
Пример:
i = 12 // 1100
i & -i = 4 // 0100
Реализация на C#:
public sealed class FenwickTree
{
private readonly int[] _tree;
public FenwickTree(int size)
{
_tree = new int[size + 1];
}
public void Update(int index, int delta)
{
while (index < _tree.Length)
{
_tree[index] += delta;
index += index & -index;
}
}
public int Query(int index)
{
var sum = 0;
while (index > 0)
{
sum += _tree[index];
index -= index & -index;
}
return sum;
}
}
Как это работает:
* Update идёт вверх по структуре и обновляет все узлы, которые отвечают за индекс
* Query идёт вниз и собирает блоки, из которых состоит prefix sum
* index & -index каждый раз выбирает размер текущего блока
Главный нюанс: Fenwick Tree обычно использует 1-based indexing.
То есть первый элемент имеет индекс 1, а не 0.
Пример использования:
var tree = new FenwickTree(5);
tree.Update(1, 10);
tree.Update(2, 20);
tree.Update(3, 30);
Console.WriteLine(tree.Query(3)); // 60
Красота Fenwick Tree в том, что дерево не хранится явно.
Нет узлов.
Нет ссылок.
Нет рекурсии.
Только массив и один битовый трюк.
Дерево спрятано прямо внутри двоичного представления индексов. | 2 409 |
| 8 | C# вопрос с собеседований: скомпилируется ли этот код?
На первый взгляд строка выглядит криво:
order._items.AddRange(items);
Поле _items объявлено как private.
Значит ли это, что доступ к нему разрешён только через this._items?
Нет.
Код скомпилируется.
В C# модификатор private ограничивает доступ типом, а не конкретным экземпляром объекта.
То есть любой код внутри класса Order может обращаться к private-полям любого другого экземпляра Order.
Пример:
public class Order
{
private readonly List<OrderItem> _items = new();
public void CopyItemsFrom(Order other)
{
_items.AddRange(other._items);
}
}
Здесь other._items тоже валиден, потому что мы всё ещё находимся внутри типа Order.
Это часто путают на собеседованиях:
private означает не «доступно только этому объекту», а «доступно только коду внутри этого класса».
В примере это используется в static factory method:
var order = new Order { ... };
order._items.AddRange(items);
return order;
Метод Create находится внутри Order, поэтому он имеет полный доступ к private-состоянию создаваемого экземпляра.
Более интересный вопрос тут даже не в компиляции, а в дизайне.
Такой подход часто встречается в DDD:
* private constructor
* static factory method
* закрытая коллекция _items
* наружу отдаётся IReadOnlyList<OrderItem>
* изменение состояния контролируется внутри агрегата
Но есть нюанс.
_items.AsReadOnly() каждый раз создаёт новый wrapper. Обычно лучше кэшировать read-only view или возвращать IReadOnlyCollection<T>, если индексатор не нужен.
Ещё важнее: фабрика должна не просто копировать items, а проверять инварианты:
if (items is null || items.Count == 0)
throw new DomainException("Order must contain at least one item.");
Иначе получается не DDD entity, а просто объект с красивой фабрикой.
Да, код компилируется.
Потому что private в C# работает на уровне типа, а не экземпляра.
А хороший senior-вопрос здесь такой:
скомпилируется ли код - это база.
А вот защищает ли этот Order свои инварианты - уже архитектура. | 2 379 |
| 9 | Приходи на C# Speed Dating — 2 часа на полезные знакомства
23 июня пройдет вечер коротких онлайн-знакомств для C#-разработчиков.
Как все пройдет
Участники будут рандомно делиться по парам и общаться в Zoom. Будет 6 раундов по 10 минут.
Зачем приходить
— обсудишь темы, которые вызывают споры: AI, карьера, архитектурные паттерны и метрики.
— заберешь идеи и практики, которые работают у других, и поделишься своим опытом.
— найдешь полезные контакты и познакомишься с C#-коммьюнити.
Вечер организуют ребята из Mindbox, но они будут «без оружия»: никакого хантинга и рассказов про вакансии, пока ты сам не спросишь.
📅 23 июня
⏰ 19:00–21:00 по мск
📍 Zoom (пришлем ссылку после регистрации)
👉 Зарегистрироваться | 2 179 |
| 10 | OptimizerDuck - open-source утилита, после которой CCleaner уже не нужен
OptimizerDuck собирает в одном приложении 30+ твиков системы: от отключения телеметрии, Copilot, Cortana и рекламного ID до тонкой настройки автозагрузки, служб, питания и задержек ввода.
Укаждой настройки есть рейтинг риска. То есть вы заранее видите, что безопасно применить, а где лучше подумать, вместо классического сценария «нажал всё подряд и потом откатываешь систему».
Что умеет:
* отключать телеметрию Windows, Cortana, Copilot и рекламный ID
* управлять автозагрузкой приложений
* настраивать службы хоста под объём RAM
* включать кастомный план питания для высокой производительности
* снижать задержку клавиатуры для игр
* применять GPU-твики, которые обычно правят вручную через реестр
Все изменения обратимы. Не понравилось, можно откатить назад. можно откатить назад.
https://github.com/itsfatduck/optimizerDuck | 2 272 |
| 11 | Program.cs — это не просто точка входа. За несколькими строками кода в ASP.NET Core скрывается полноценная инфраструктура запуска приложений, управления жизненным циклом и фоновых процессов.
На открытом уроке разберём, как на самом деле устроен ASP.NET Core и почему понимание Generic Host меняет подход к разработке .NET-приложений. Поговорим о жизненном цикле приложения, фоновых задачах через IHostedService и различиях между веб-приложениями и консольными сервисами.
Это особенно полезно разработчикам, которые уже работают с ASP.NET Core, но хотят глубже понимать архитектуру платформы, увереннее проектировать сервисы и принимать технические решения осознанно, а не
по шаблону.
Открытый урок пройдёт 18 июня в 20:00 МСК в преддверии старта курса «C# ASP.NET Core разработчик».
Подробности и регистрация: https://otus.pw/SMEy/
Реклама. ООО "ОТУС ОНЛАЙН-ОБРАЗОВАНИЕ". ИНН 9705100963. | 1 616 |
| 12 | ⚡️ Переписывать legacy-систему редко значит «переписать код». Обычно самая дорогая часть начинается там, где старый и новый мир должны какое-то время жить одновременно.
Типичная проблема - синхронизация данных между старой БД и новой моделью. На бумаге кажется, что можно взять CDC, подключить Debezium, прокинуть события и жить спокойно. На практике это работает только пока у вас почти прямое соответствие: таблица → событие → таблица.
В реальном legacy всё еще хуже.
Одна запись в старой системе может собираться из нескольких агрегатов в новой. Поля могут иметь другой смысл. Часть данных нормализована, часть размазана по справочникам, часть хранится как «магические» статусы. А ещё при переносе нужно не просто скопировать байты, а применить бизнес-правила: пересчитать состояние, отфильтровать мусор, восстановить инварианты, иногда даже специально повторить старый баг, потому что на нём завязан внешний процесс.
Нормальное решение может выглядеть так:
* события из новой системы публикуются через outbox, а не напрямую из хендлера
* синхронизатор читает сообщения из RabbitMQ или другого брокера
* трансформации делаются явно, через application service или отдельный mapping layer
* операции проектируются идемпотентными, потому что повторная доставка будет всегда
* для каждой внешней записи хранится mapping старого и нового идентификатора
* ошибки не теряются, а уходят в retry/DLQ с понятной диагностикой
* консистентность проверяется отдельными reconciliation jobs, а не верой в «оно доедет»
Такой синхронизатор выглядит как временный костыль, но по сложности быстро становится полноценной подсистемой. У него появляются свои контракты, версии сообщений, миграции, алерты, метрики, ручные repair-команды и отдельные сценарии восстановления после падений.
Если всё сделано хорошо, этот компонент потом удалят. Он нужен только на период миграции. Но если сделать его плохо, миграция не закончится никогда. | 2 733 |
| 13 | 🖥 Задача
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
var actions = new List<Func<Task>>();
for (int i = 0; i < 3; i++)
{
actions.Add(async () =>
{
await Task.Yield();
Console.Write(i + " ");
});
}
foreach (var action in actions)
{
await action();
}
Что выведет код?
Варианты:
0 1 2
3 3 3
0 0 0
1 2 3
Правильный ответ:
3 3 3
Разбор коротко:
i в for не копируется в каждую лямбду. Все три лямбды захватывают одну и ту же переменную i. Когда цикл закончился, i == 3. Поэтому каждая отложенная async-функция печатает уже финальное значение.
Чтобы получить 0 1 2, нужно создать локальную копию внутри цикла:
```
for (int i = 0; i < 3; i++)
{
int copy = i;
actions.Add(async () =>
{
await Task.Yield();
Console.Write(copy + " ");
});
}
``` | 2 742 |
| 14 | 🐳 «Используй Testcontainers вместо in-memory» - это только половина правды
Все уже выучили: EF Core InMemory provider - не интеграционный тест.
Он не ловит:
- баги в LINQ-трансляции
- ограничения БД
- коллации
- реальные типы колонок
- поведение конкретного SQL-провайдера
Окей, заменили на реальный PostgreSQL через Testcontainers. Победа? Не совсем.
Вот что начинается дальше.
1. Вы получили «медленное враньё» вместо «быстрого»
Поднимать контейнер на каждый тест-класс - быстрый способ превратить CI из 30 секунд в 8 минут.
Нормальный вариант:
- один контейнер на всю тестовую сессию
- изоляция данных между тестами через Respawn
- без пересоздания базы и контейнера каждый раз
Respawn чистит таблицы с учётом графа foreign keys за миллисекунды.
2. Транзакционный откат ≠ реальный сценарий
Трюк «обернули тест в транзакцию и откатили» красиво выглядит, но ломается, когда в коде есть:
- свои транзакции
- несколько SaveChanges
- фоновые операции
- поведение, завязанное на commit
В итоге тестируется сценарий, которого в проде нет.
3. Самая коварная ловушка - общий DbContext
Если тест и код используют один экземпляр DbContext, EF может вернуть данные из change tracker, а не из базы.
Тест зелёный, но он врёт: реальный SQL-запрос мог вообще не выполниться.
Между Act и Assert стоит чистить трекер:
Db.ChangeTracker.Clear();
4. Бонус, который теряют 90% команд - тест миграций
Реальная БД позволяет прогнать EF-миграции на чистой схеме.
Если миграция падает или схема разъехалась с моделью, вы узнаёте об этом в CI, а не в проде в пятницу вечером.
Пример базового подхода:
public class IntegrationTestBase : IAsyncLifetime
{
private static readonly PostgreSqlContainer _db =
new PostgreSqlBuilder()
.WithImage("postgres:16-alpine")
.Build();
private Respawner _respawner = null!;
protected AppDbContext Db = null!;
public async Task InitializeAsync()
{
await _db.StartAsync();
var options = new DbContextOptionsBuilder<AppDbContext>()
.UseNpgsql(_db.GetConnectionString())
.Options;
Db = new AppDbContext(options);
// Реальные миграции - заодно проверяем, что они накатываются
await Db.Database.MigrateAsync();
await using var conn = new NpgsqlConnection(_db.GetConnectionString());
await conn.OpenAsync();
_respawner = await Respawner.CreateAsync(conn, new RespawnerOptions
{
DbAdapter = DbAdapter.Postgres,
SchemasToInclude = ["public"]
});
}
// Сброс данных перед каждым тестом - без пересоздания контейнера
protected async Task ResetAsync()
{
await using var conn = new NpgsqlConnection(_db.GetConnectionString());
await conn.OpenAsync();
await _respawner.ResetAsync(conn);
// Иначе тест может читать из кеша, а не из БД
Db.ChangeTracker.Clear();
}
public Task DisposeAsync() => Task.CompletedTask;
}
Testcontainers - это не галочка «best practice», а смена философии.
Без нормальной изоляции данных вы просто пересели с быстрого вранья на медленное.
А как вы изолируете состояние БД между интеграционными тестами - Respawn, транзакции или пересоздание контейнера?
#dotnet #csharp #testing #efcore | 2 746 |
| 15 | Алгоритму почти 70 лет, а он до сих пор живёт в ядре Linux.
В 1957 году Wilkes, Wheeler и Gill описали быстрый способ считать количество установленных битов в числе. Не циклом по одному биту, а через маски и арифметику сразу над группами битов.
Идея простая:
- сначала считаем биты парами
- потом группами по 4
- потом по байтам
- в конце умножение собирает сумму в старший байт
Если в процессоре нет инструкции POPCNT, Linux использует похожий подход в __sw_hweight64.
Красивый пример того, как старый битовый трюк пережил десятилетия и всё ещё работает в современном системном коде. | 3 642 |
| 16 | #ПятничныйКвиз #ДляСамыхМаленьких | 4 428 |
| 17 | ✔️ Одна строчка .Result роняет ваш ASP.NET Core при CPU 8 %: разбор hill-climbing в .NET 9
TL;DR. Один foo.GetAsync().Result внутри middleware превращает ASP.NET Core, державший 50k RPS на p99 = 40 мс, в сервис на 12k RPS с p99 = 4 с при CPU 8 %. Виноват не блокирующий вызов сам по себе.
Виноват hill-climbing: фидбэк-луп в ThreadPool, внутри которого живёт дискретное преобразование Фурье.
Разбираемся по исходникам CoreCLR, как это работает, воспроизводим эффект на ~80 строках кода и показываем, почему SetMinThreads это не лечение, а анестезия.
https://habr.com/ru/articles/1040804/ | 4 593 |
| 18 | 🖥 C# задачка с подвохом
Что выведет код?
using System;
using System.Collections.Generic;
var list = new List<Func<int>>();
for (int i = 0; i < 3; i++)
{
int x = i;
list.Add(() => x);
x = 100;
}
foreach (var f in list)
{
Console.Write(f() + " ");
}
A) 0 1 2
😎 100 100 100
C) 3 3 3
D) 0 100 100
Правильный ответ: 😎 100 100 100
Почему так:
Внутри каждой итерации создаётся новая локальная переменная x, и именно её захватывает лямбда. Кажется, что ответы должны быть 0 1 2, потому что x получает значение i.
Но после добавления лямбды переменная x всё ещё та же самая захваченная переменная. Потом мы меняем её на 100.
В итоге каждая лямбда хранит свою отдельную x, но каждая из этих x была изменена на 100. | 4 354 |
| 19 | 🖥 Сервисы крутятся. Прод вроде живой. Но когда тимлид спрашивает: «почему здесь лучше ValueTask, а не Task?» или «как GC поведёт себя под нагрузкой?» - ты начинаешь плыть.
И дело не в том, что ты плохо пишешь код. Просто большинство курсов заканчиваются ровно там, где начинается настоящий .NET.
Этот курс про то, что обычно остаётся под капотом:
- CLR
- JIT
- GC
- Span
- async state machine
- Source Generators
- lock-free подходы
- OpenTelemetry
- дампы в проде
На практике разбираем, как .NET реально работает внутри: что происходит с кодом после компиляции, как память живёт под нагрузкой, почему async иногда помогает, а иногда ломает производительность, как читать проблемы по дампам и метрикам, а не гадать по логам.
Если хочешь дойти до уровня, где система для тебя не чёрный ящик, а инструмент, который ты понимаешь до IL, - велкам.
Сейчас на stepik доступна скидка 55%: https://stepik.org/a/288694 | 3 410 |
| 20 | No text... | 3 892 |
Available now! Telegram Research 2025 — the year's key insights 
