es
Feedback
C# 1001 notes

C# 1001 notes

Ir al canal en Telegram

Регулярные короткие заметки по C# и .NET. Просто о сложном для каждого. admin - @haarrp

Mostrar más
6 662
Suscriptores
-524 horas
+87 días
+3330 días
Atraer Suscriptores
oct '26
octubre '26
+11
en 0 canales
septiembre '26
+107
en 9 canales
Get PRO
agosto '26
+132
en 37 canales
Get PRO
julio '26
+102
en 41 canales
Get PRO
junio '26
+73
en 0 canales
Get PRO
mayo '26
+67
en 0 canales
Get PRO
abril '26
+66
en 0 canales
Get PRO
marzo '26
+57
en 0 canales
Get PRO
febrero '26
+138
en 0 canales
Get PRO
enero '26
+91
en 1 canales
Get PRO
diciembre '25
+85
en 0 canales
Get PRO
noviembre '25
+132
en 3 canales
Get PRO
octubre '25
+87
en 1 canales
Get PRO
septiembre '25
+101
en 4 canales
Get PRO
agosto '25
+81
en 0 canales
Get PRO
julio '25
+80
en 0 canales
Get PRO
junio '25
+83
en 0 canales
Get PRO
mayo '25
+60
en 0 canales
Get PRO
abril '25
+80
en 0 canales
Get PRO
marzo '25
+107
en 0 canales
Get PRO
febrero '25
+105
en 0 canales
Get PRO
enero '25
+169
en 0 canales
Get PRO
diciembre '24
+202
en 1 canales
Get PRO
noviembre '24
+203
en 2 canales
Get PRO
octubre '24
+364
en 1 canales
Get PRO
septiembre '24
+241
en 0 canales
Get PRO
agosto '24
+262
en 1 canales
Get PRO
julio '24
+168
en 0 canales
Get PRO
junio '24
+398
en 2 canales
Get PRO
mayo '24
+379
en 35 canales
Get PRO
abril '24
+304
en 43 canales
Get PRO
marzo '24
+314
en 20 canales
Get PRO
febrero '24
+281
en 1 canales
Get PRO
enero '24
+572
en 45 canales
Get PRO
diciembre '23
+941
en 48 canales
Get PRO
noviembre '23
+655
en 2 canales
Get PRO
octubre '23
+61
en 0 canales
Get PRO
septiembre '23
+80
en 0 canales
Get PRO
agosto '23
+507
en 0 canales
Get PRO
julio '23
+487
en 0 canales
Get PRO
junio '23
+88
en 0 canales
Get PRO
mayo '23
+569
en 0 canales
Get PRO
abril '23
+21
en 0 canales
Get PRO
marzo '23
+28
en 0 canales
Get PRO
febrero '23
+23
en 0 canales
Get PRO
enero '23
+28
en 0 canales
Get PRO
diciembre '22
+32
en 0 canales
Get PRO
noviembre '22
+31
en 0 canales
Get PRO
octubre '22
+40
en 0 canales
Get PRO
septiembre '22
+28
en 0 canales
Get PRO
agosto '22
+43
en 0 canales
Get PRO
julio '22
+321
en 0 canales
Get PRO
junio '22
+41
en 0 canales
Get PRO
mayo '22
+37
en 0 canales
Get PRO
abril '22
+180
en 0 canales
Get PRO
marzo '220
en 0 canales
Get PRO
febrero '220
en 0 canales
Get PRO
enero '220
en 0 canales
Get PRO
diciembre '210
en 0 canales
Get PRO
noviembre '210
en 0 canales
Get PRO
octubre '210
en 0 canales
Get PRO
septiembre '210
en 0 canales
Get PRO
agosto '210
en 0 canales
Get PRO
julio '210
en 0 canales
Get PRO
junio '210
en 0 canales
Get PRO
mayo '210
en 0 canales
Get PRO
abril '21
+1
en 0 canales
Get PRO
marzo '21
+45
en 0 canales
Get PRO
febrero '21
+54
en 0 canales
Get PRO
enero '21
+42
en 0 canales
Get PRO
diciembre '20
+1 304
en 0 canales
Fecha
Crecimiento de Suscriptores
Menciones
Canales
06 octubre+1
05 octubre+1
04 octubre+1
03 octubre+1
02 octubre+4
01 octubre+3
Publicaciones del Canal
Задачка по C# 14: сколько раз вызовется Next()?

int calls = 0;
int Next() => ++calls;

Box? a = null;
Box b = new();

a?.Value = Next();
b?.Value = Next();
a?.Value += Next();
b?.Value += Next();

Console.WriteLine($"{calls} {b.Value}");

class Box
{
    public int Value
    {
        get;
        set => field = value * 10;
    }
}
Варианты:
A) 4 120
😎 2 120
C) 2 30
D) Код не скомпилируется
Ответ: B) 2 120 Здесь сразу две фичи C# 14. Первая: null-conditional assignment. Теперь ?. можно ставить слева от присваивания, в том числе составного. Главный подвох в том, что если объект слева равен null, правая часть вообще не вычисляется. Поэтому для a функция Next() ни разу не вызывается, и счётчик доходит только до 2, хотя вызовов в коде четыре. Вторая: ключевое слово `field`. Геттер остаётся автоматическим, а сеттер умножает значение на 10, обращаясь к скрытому полю без ручного объявления. Считаем по шагам: ``` b?.Value = Next() → Next() = 1, сохраняем 1 * 10 = 10 b?.Value += Next() → читаем 10, Next() = 2, 10 + 2 = 12, сохраняем 120 ``` Бонусный подвох: b?.Value++ уже не скомпилируется. Составное присваивание с ?. разрешено, а инкремент и декремент нет.

2
🦈 Открытое собеседование на Middle C# | 6 октября, 19:00 МСК Приглашаем на открытое собеседование: Senior C# разработчик про
🦈 Открытое собеседование на Middle C# | 6 октября, 19:00 МСК Приглашаем на открытое собеседование: Senior C# разработчик проведёт его в прямом эфире. Можно посмотреть, как всё устроено изнутри, и понять, насколько ты готов к такому интервью. Как это будет: 📂 Собеседует Александр Моргунов — Senior C# разработчик, 7+ лет в европейских высоконагруженных сервисах. Отвечает разработчик-доброволец; 📂 Всё как на настоящем собесе: Александр задаёт те вопросы и задачи, которые даёт кандидатам на своих интервью. Заранее их никто не знает; 📂 После каждого ответа Александр даст обратную связь: что прозвучало сильно, а что стоило раскрыть иначе. Так станет понятнее, на что обращают внимание на собесе; 📂 В конце можно задать любой вопрос. Это бесплатно. Эфир проходит в рамках менторской программы от ШОРТКАТ для C# разработчиков, которые хотят повысить свой грейд, ЗП и прокачать скиллы. Переходи в нашего бота, чтобы получить ссылку на эфир -> @shortcut_csharp_bot Реклама. О рекламодателе.
670
3
«Ядро Windows NT во многом превосходит Linux», считает исследовательница Google и бывший реверс-инженер Microsoft Лори Кирк.+1
«Ядро Windows NT во многом превосходит Linux», считает исследовательница Google и бывший реверс-инженер Microsoft Лори Кирк. Её аргумент касается устройства системы: в NT ресурсы представлены объектами с правами доступа. В Linux контроль строится из нескольких механизмов, включая права файлов, ACL, capabilities и SELinux. По мнению Кирк, из-за этого труднее ответить на вопрос: что именно разрешено ИИ-агенту, которому дали доступ к системе? Кирк считает, что ядро, спроектированное с нуля в 2026 году, скорее напоминало бы NT, чем Linux. Ей возражают: отдельные механизмы дают Linux гибкость, которая помогла ему стать основой серверов и контейнеров. Это спор об архитектуре и управлении доступом, а не доказательство, что одна ОС безопаснее другой. Источник: https://www.windowslatest.com/2026/09/26/google-researcher-explains-why-windows-nt-puts-linux-to-shame-and-imagines-an-alternate-history-where-it-won/
1 273
4
Ваш .NET API работает локально. Готов ли он к продакшену? Чек-лист из 8 проверок перед релизом. Он посвящён решениям, которые позже влияют на поиск ошибок, поддержку API и внесение изменений. Удобно пройтись по нему перед выкладкой, даже если все эндпоинты уже отвечают как надо. [Читать статью](https://mwaseemzakir.substack.com/p/before-your-net-api-goes-to-production) #aspnetcore #dotnet
1 827
5
🧩 C# Channels: сообщение попало в очередь. Почему обработчик его не получил? Два воркера читают один ограниченный канал. Один из них отменяет ожидание. Продюсер успешно записывает сообщение — без исключений. using System.Threading.Channels; var queue = Channel.CreateBounded<int>( new BoundedChannelOptions(1) { FullMode = BoundedChannelFullMode.Wait }); using var cts = new CancellationTokenSource(); var firstRead = queue.Reader.ReadAsync().AsTask(); var firstWorker = Task.Run(async () => { try { var item = await firstRead.WaitAsync(cts.Token); Console.WriteLine($"A: {item}"); } catch (OperationCanceledException) { Console.WriteLine("A: canceled"); } }); // Дожидаемся, чтобы первый воркер обработал отмену. cts.Cancel(); await firstWorker; var secondWorker = Task.Run(async () => { await foreach (var item in queue.Reader.ReadAllAsync()) Console.WriteLine($"B: {item}"); }); await queue.Writer.WriteAsync(42); queue.Writer.TryComplete(); await secondWorker; await queue.Reader.Completion; Console.WriteLine("Finished"); Разберите без запуска: 1. Что выведет программа? Возможны ли разные результаты? 2. Где окажется 42, если ни один воркер его не напечатает? 3. Почему Reader.Completion успешно завершится? 4. Чем отличаются эти две записи? reader.ReadAsync().AsTask().WaitAsync(token) reader.ReadAsync(token).AsTask() Усложнение: отмена и запись происходят одновременно. Достаточно ли второй записи, чтобы гарантировать, что сообщение не потеряется? Предложите протокол остановки: после извлечения сообщение должно быть обработано либо явно сохранено для повторной попытки. Очередь остаётся ограниченной, обработчики могут завершаться с ошибкой. 👇 В какой момент ответственность за сообщение переходит от канала к воркеру?
1 882
6
Эта задача проверяет понимание Memory<T>, pooling, ownership, IAsyncEnumerable, cancellation и одной из самых неприятных категорий ошибок высокопроизводительного C# — когда GC защищает объект от удаления, но не защищает вас от повторного использования его содержимого.
1 606
7
# C# 14: хитрая задача на ArrayPool, IAsyncEnumerable и время жизни памяти Есть поток данных, из которого нужно читать сообщения построчно без лишних аллокаций. Наивная реализация: static async IAsyncEnumerable<ReadOnlyMemory<byte>> ReadLinesAsync( Stream stream, [EnumeratorCancellation] CancellationToken cancellationToken = default) { byte[] buffer = ArrayPool<byte>.Shared.Rent(4096); try { while (true) { int read = await stream.ReadAsync(buffer, cancellationToken); if (read == 0) yield break; yield return buffer.AsMemory(0, read); } } finally { ArrayPool<byte>.Shared.Return(buffer); } } Использование: await foreach (var data in ReadLinesAsync(stream)) { queue.Add(data); } Код компилируется и выглядит эффективно. Но в production данные внутри queue иногда внезапно меняются или повреждаются. ## Вопрос Почему? --- # Проблема ReadOnlyMemory<byte> не владеет памятью. Он всего лишь указывает на: byte[] buffer А этот массив взят из: ArrayPool<byte>.Shared После следующего: ReadAsync(buffer) содержимое массива перезаписывается. А после: ArrayPool<byte>.Shared.Return(buffer); массив вообще может получить другой поток. Получается: yield memory ↓ consumer сохраняет ссылку ↓ buffer переиспользуется ↓ старый ReadOnlyMemory показывает новые данные Это логический аналог use-after-free, хотя runtime C# остаётся memory-safe. --- # Задача Исправьте API так, чтобы: - использовался пул памяти; - данные можно было безопасно хранить после yield; - не происходило скрытого копирования каждого сообщения; - consumer явно управлял временем жизни буфера; - отмена работала через CancellationToken. Подсказка: используйте IMemoryOwner<byte> --- # Один из вариантов решения public sealed class Message : IDisposable { private IMemoryOwner<byte>? _owner; public ReadOnlyMemory<byte> Data { get; } public Message(IMemoryOwner<byte> owner, int length) { _owner = owner; Data = owner.Memory[..length]; } public void Dispose() { _owner?.Dispose(); _owner = null; } } Чтение: static async IAsyncEnumerable<Message> ReadAsync( Stream stream, [EnumeratorCancellation] CancellationToken cancellationToken = default) { while (true) { IMemoryOwner<byte> owner = MemoryPool<byte>.Shared.Rent(4096); int read; try { read = await stream.ReadAsync( owner.Memory, cancellationToken); } catch { owner.Dispose(); throw; } if (read == 0) { owner.Dispose(); yield break; } yield return new Message(owner, read); } } Consumer: await foreach (var message in ReadAsync(stream, ct)) { using (message) { Process(message.Data); } } Теперь память возвращается в pool только тогда, когда consumer закончил с сообщением. --- # Главная ловушка Даже такой код опасен: ReadOnlyMemory<byte> saved; await foreach (var message in ReadAsync(stream)) { using (message) { saved = message.Data; } } Console.WriteLine(saved.Length); После Dispose() память больше не принадлежит consumer. Сам ReadOnlyMemory<byte> технически существует, но использовать его содержимое уже нельзя. --- # Вопрос уровня Senior Как изменить API так, чтобы разработчику было сложнее случайно сохранить ReadOnlyMemory<byte> после Dispose()? Дополнительно подумайте: ArrayPool<T> vs MemoryPool<T> vs обычный byte[] и ответьте, когда zero-copy действительно быстрее, а когда управление lifetime становится дороже простой копии.
1 407
8
# C# 14: конкурентный кеш без race condition Реализуйте потокобезопасный кеш: public sealed class AsyncCache<TKey, TValue> where TKey : notnull { public Task<TValue> GetOrCreateAsync( TKey key, Func<CancellationToken, Task<TValue>> factory, CancellationToken cancellationToken = default) { // TODO } } Условия: если 100 потоков одновременно запросят один key, factory должна выполниться только один раз. Остальные ждут тот же Task. Если вычисление завершилось ошибкой - запись удаляется из кеша. Отмена одного клиента не должна отменять работу для остальных. Глобальный lock использовать нельзя. Вопрос: как избежать race condition между созданием общего Task и удалением упавшего значения из кеша?
1 287
9
🔍Тестовое собеседование с Senior C# разработчиком уже завтра 15 сентября(уже завтра!) в 19:00 по мск приходи онлайн на откры
🔍Тестовое собеседование с Senior C# разработчиком уже завтра 15 сентября(уже завтра!) в 19:00 по мск приходи онлайн на открытое собеседование, чтобы посмотреть на настоящее интервью на Middle C# разработчика. Как это будет: 📂 Александр Моргунов, старший C# разработчик с опытом 7+ лет в Европейских высоконагруженных сервисах, будет задавать реальные вопросы и задачи разработчику-добровольцу 📂 Александр будет комментировать каждый ответ респондента, чтобы дать понять, чего от вас ожидает собеседующий на интервью 📂 В конце можно будет задать любой вопрос Александру Это бесплатно. Эфир проходит в рамках менторской программы от ШОРТКАТ для C# разработчиков, которые хотят повысить свой грейд, ЗП и прокачать скиллы. Переходи в нашего бота, чтобы получить ссылку на эфир → @shortcut_csharp_bot Реклама. О рекламодателе.
1 225
10
🔧 Как передать многострочный PEM через Aspire в ASP.NET Core Сертификаты и ключи в PEM содержат переносы строк, которые могут создавать проблемы при передаче через параметры Aspire. Damien Bod показал обходной вариант для локальной разработки с User Secrets и развёртывания в Azure. Схема простая: * закодировать PEM в однострочный Base64 * сохранить значение в конфигурации AppHost под ключом Parameters:ИмяПараметра * объявить приватный ключ через AddParameter(..., secret: true) * передать параметр приложению через WithEnvironment * в ASP.NET Core декодировать Base64 обратно в исходный PEM В статье есть helper-класс для преобразования, настройка AppHost и пример создания сертификата через X509Certificate2.CreateFromPem. Base64 сохраняет переносы строк при передаче. Приватный ключ после кодирования остаётся секретом: Base64 не обеспечивает шифрование. https://damienbod.com/2026/09/01/using-multiline-parameters-for-aspire-and-asp-net-core-with-user-secrets-and-azure-default-deployments/
1 679
11
Согласны ?
Согласны ?
1 742
12
⚡️ Задачи с технических собеседований в одном репозитории Tech-OA-Interview-Questions - подборка задач из онлайн-тестирований и интервью в технологических компаниях. Пригодится для подготовки к алгоритмическим этапам отбора. OA, или Online Assessment, - тестирование, которое кандидат обычно проходит перед собеседованиями. В репозитории собраны материалы для подготовки к таким заданиям, в том числе к отбору в Amazon. Можно использовать как список для практики: решать задачи с таймером, оценивать сложность решения и проверять граничные случаи. https://github.com/perixtar/Tech-OA-Interview-Questions
1 899
13
RabbitMQ в Production: Transactional Outbox, идемпотентность и DLQ в ASP.NET Core Отправить сообщение в RabbitMQ несложно. Го
RabbitMQ в Production: Transactional Outbox, идемпотентность и DLQ в ASP.NET Core Отправить сообщение в RabbitMQ несложно. Гораздо сложнее сделать так, чтобы система продолжала работать корректно в production: сообщения не терялись, не обрабатывались повторно, а ошибки не приводили к бесконечным ретраям и дублированию данных. На открытом уроке 17 сентября в 20:00 разберем типичные проблемы при построении событийно-ориентированных систем и рассмотрим проверенные подходы к их решению. Поговорим о паттерне Transactional Outbox, идемпотентности, и покажем, как Dead Letter Queue (DLQ) помогает работать с ошибками. Примеры на ASP.NET Core и RabbitMQ, но подходы применимы и к другим брокерам. Урок для backend-разработчиков, строящих микросервисные архитектуры, и инженеров, желающих довести event-driven системы до промышленной надежности. 👉 Записаться: https://otus.pw/PWKD/?erid=2W5zFHxScpR Реклама. ООО "ОТУС ОНЛАЙН-ОБРАЗОВАНИЕ". ИНН 9705100963.
856
14
✔️ Polly становится платной, но у .NET остаётся бесплатная альтернатива Polly много лет была одной из главных библиотек .NET
✔️ Polly становится платной, но у .NET остаётся бесплатная альтернатива Polly много лет была одной из главных библиотек .NET для устойчивости к временным сбоям: retry, timeout, fallback, rate limiting и circuit breaker. Теперь Polly движется в сторону платной модели, но Microsoft.Resilience по-прежнему можно использовать бесплатно. С .NET 8 работа с resilience стала заметно проще: появился новый API Polly и официальные библиотеки Microsoft для построения resilience pipelines. Что можно настроить: - Retry - Fallback - Timeout - Rate limiting - Circuit breaker Хороший разбор того, как собирать устойчивые cloud-приложения на современном .NET: https://milanjovanovic.tech/blog/building-resilient-cloud-applications-with-dotnet
1 649
15
.NET и Владимир: отличный повод совместить митап и выходные в городе с историей Офлайн-мероприятий для .NET-разработчиков сей
.NET и Владимир: отличный повод совместить митап и выходные в городе с историей Офлайн-мероприятий для .NET-разработчиков сейчас не так много, а тут получается приятное комбо: встреча с другими разработчиками вечером в пятницу и возможность остаться на выходные в городе с историей. В программе доклады от разработчиков Altenar и Рови Тех (часть Т-Банка): — Async/await — асинхронность, которую можно читать. — Как не терять данные при асинхронной интеграции программных систем. — EF Core + PostgreSQL: за рамками CRUD. Кстати, ещё на митапе запланированы активности для программистов: адаптации известных игр ("Сапер", "Крестики-нолики", "Гонки"), где для победы понадобится понимание математики и вероятностей. Участие бесплатное, а ещё можно сэкономить на проезде — организаторы разыграют несколько билетов на "Ласточку" среди участников. Для участия в розыгрыше: 1. Зарегистрируйтесь на митап. 2. Напишите «Хочу на .NET-митап на Ласточке» на почту aleksei.korneev@altenar.com с почты, указанной при регистрации. Итоги розыгрыша подведём 14 сентября. Регистрируйтесь, планируйте поездку и до встречи во Владимире!
1 603
16
Полноценный Lisp можно уместить всего в 99 строк C. Внутри при этом: - 21 примитив - REPL - сборщик мусора Cheney GC - числа+1
Полноценный Lisp можно уместить всего в 99 строк C. Внутри при этом: - 21 примитив - REPL - сборщик мусора Cheney GC - числа с плавающей точкой - указатели - типы значений И всё это без `struct`-тегов, без внешних библиотек и без обычных динамических аллокаций для представления объектов. Главный трюк - NaN boxing. IEEE 754 оставляет много битов внутри специальных NaN-значений. Их можно использовать как скрытое хранилище: - часть битов кодирует тип - до 48 бит можно использовать под указатель - обычные double при этом остаются обычными числами В итоге одно 64-битное значение может представлять и число, и указатель, и другие типы данных. Очень красивый пример того, как устройство IEEE 754 можно использовать для построения компактного рантайма языка.
1 892
17
ASP .NET Core API под нагрузкой: как сделать сервис устойчивым к сбоям и росту трафика Пока пользователей мало, API работает
ASP .NET Core API под нагрузкой: как сделать сервис устойчивым к сбоям и росту трафика Пока пользователей мало, API работает быстро. С ростом нагрузки запросы занимают все ресурсы, повторные обращения увеличивают нагрузку, операции продолжаются после отключения клиента, ошибки во внешних сервисах ведут к каскадным отказам. На открытом уроке 3 сентября в 20:00 разберём защиту API. Возьмём сервис с проблемами, проведём нагрузочное тестирование, найдём узкие места и поэтапно внедрим механизмы защиты. Сравним результаты после каждого изменения. Поговорим о Rate Limiting, контроле параллельных запросов, CancellationToken, Timeout, Circuit Breaker, кешировании в Redis и предотвращении перегрузки повторными попытками. Урок для C#-разработчиков Web API, backend-инженеров с растущей нагрузкой и всех, кто хочет перейти к production-практикам. 👉 Записаться: https://tglink.io/df8a3e9777dd3a?erid=2W5zFGZJoeZ #реклама О рекламодателе
841
18
Вышел Aspire 13.5 - обновление с упором на интерфейс и удобство повседневной разработки. Что добавили: - обновлённый Dashboar
Вышел Aspire 13.5 - обновление с упором на интерфейс и удобство повседневной разработки. Что добавили: - обновлённый Dashboard и новый дизайн aspire.dev - фильтрацию логов и трассировок по тексту, времени и числам - более понятные ошибки health-check - загрузку файлов прямо через команды AppHost - окна прогресса с возможностью отмены - полноценный терминал прямо внутри Dashboard через WithTerminal() - поддержку persistent volumes для Kubernetes - работу с существующими Azure-ресурсами из других resource group, подписок и tenants - установку Aspire CLI через Homebrew, WinGet, npm, Nix, mise и NuGet Отдельно удобно, что теперь часть инфраструктурных настроек можно описывать прямо в AppHost на C# или TypeScript, без постоянного ухода в YAML. https://devblogs.microsoft.com/aspire/whats-new-aspire-13-5/
2 083
19
Как собрать production-ready CRUD на ASP.NET Core Telerik разобрала не просто базовый CRUD, а структуру приложения, которую у
Как собрать production-ready CRUD на ASP.NET Core Telerik разобрала не просто базовый CRUD, а структуру приложения, которую уже можно нормально развивать дальше. В примере используются: - ASP.NET Core Web API - Entity Framework Core - PostgreSQL - DTO - Service layer - Repository pattern - AutoMapper - FluentValidation - Swagger / OpenAPI Отдельный акцент сделан на разделении ответственности. Контроллеры не должны содержать бизнес-логику, работа с БД выносится отдельно, входные данные валидируются до выполнения операций, а DTO не дают напрямую светить наружу модели базы. Также разбираются: - создание и настройка проекта - подключение PostgreSQL - миграции EF Core - CRUD endpoints - обработка ошибок - валидация - mapping между entity и DTO - организация структуры проекта Хороший материал, если базовый CRUD уже умеешь писать, но хочешь привести проект к более нормальной production-структуре. https://telerik.com/blogs/creating-production-ready-crud-application-aspnet-core #aspnetcore #dotnet
1 802
20
⚡ Race Conditions в ASP.NET Core - как они появляются и почему их сложно ловить В статье Assis Zang разбирается, что происходит, когда несколько запросов одновременно работают с общим состоянием и начинают вмешиваться друг в друга. Внутри: - откуда берутся race conditions - почему проблема может проявляться нестабильно - как воспроизвести конкурентный доступ - какие ошибки возникают при работе с shared state - как использовать синхронизацию и безопасные паттерны - почему потокобезопасность важна даже в обычном web API Полезно для .NET-разработчиков, которые работают с многопоточностью, shared state и высоконагруженными ASP.NET Core-приложениями. https://telerik.com/blogs/understanding-race-conditions-aspnet-core
1 972