Веб-версияОткрыть в Telegram
CC# Ready | Unity

C# Ready | Unity

✅ Высокое доверие
@csharp_ready · канал · Технологии · в индексе с 2026-06-16
10 383подписчиков+25 за неделю
1 659средний охват поста
16%ER — охват к подписчикам
48постов за 30 дней
C
C# Ready | Unity
Фотография
нажмите — покажем
Как в C# не забыть про ConfigureAwait(false)? Когда пишешь библиотечный async-код, часто встречается такой вариант: var json = await httpClient.GetStringAsync(url); return JsonSerializer.Deserialize<User>(json); Для приложения это обычно нормально. Но для библиотек и низкоуровневого кода часто лучше явно сказать, после await не нужно возвращаться в исходный context. Для этого используют ConfigureAwait(false): var json = await httpClient .GetStringAsync(url) .ConfigureAwait(false); После await продолжение может выполниться на любом подходящем потоке: return JsonSerializer.Deserialize<User>(json); Это особенно полезно в shared-библиотеках, SDK, инфраструктурном коде и клиентах к внешним API. Например: public async Task<User> LoadUserAsync(string id) { var response = await client.GetAsync($"/users/{id}") .ConfigureAwait(false); return await ParseAsync(response) .ConfigureAwait(false); } Но в UI-коде всё иначе. Если после await нужно обновить интерфейс, context может быть нужен: label.Text = "Loaded"; В таком случае ConfigureAwait(false) может увести продолжение с UI-потока. ➡️ C# Ready | #совет
7 · 2K ·
C
C# Ready | Unity
Фотография
нажмите — покажем
Blazor против Vue.js глазами C# разработчика! Автор сравнивает два frontend-подхода на опыте реальных проектов. Статья показывает, что будет привычным, а что неожиданным для разработчика, который приходит в интерфейсы из C# и .NET. В статье разбирают: • как ощущается компонентная разработка в Blazor и Vue • где C# стек даёт сильную сторону на frontend • какие различия важнее синтаксиса и шаблонов Продолжай читать на Habr ➡️ C# Ready | #статья
12 · 1.9K ·
C
C# Ready | Unity
Фотография
нажмите — покажем
Шпаргалка по поколениям сборщика мусора в .NET! На картинке показаны поколения управляемой кучи, продвижение выживших объектов и три основные фазы GC. Mark находит достижимые объекты, sweep освобождает мусор, а compact уменьшает фрагментацию памяти. Например, Gen 0 хранит новые короткоживущие объекты, Gen 1 служит промежуточной зоной, а Gen 2 содержит долгоживущие данные. Объекты крупнее 85 КБ обычно попадают в Large Object Heap. Сохрани, чтобы не потерять! ➡️ C# Ready | #ресурс
12 · 1.8K ·
C# Ready | Unity
Читаем все страницы API через IAsyncEnumerable в C#! Многие API отдают данные порциями. Если собрать все страницы в List сразу, код быстро разрастается, а юзер не увидит ни одной записи до конца загрузки. IAsyncEnumerable позволяет отдавать элементы по мере чтения следующей страницы. Вызывающий код использует await foreach и не знает, сколько запросов понадобилось внутри. record Page<T>(IReadOnlyList<T> Items, string? NextCursor); Метод клиента пусть возвращает страницу и курсор для следующего запроса. Null означает, что сервер больше ничего не отдаёт. Task<Page<Order>> GetPageAsync( string? cursor, CancellationToken token); В итераторе сохраняем текущий курсор. После каждого ответа возвращаем заказы по одному и только потом запрашиваем следующую страницу. string? cursor = null; do { var page = await GetPageAsync(cursor, token); foreach (var order in page.Items) yield return order; cursor = page.NextCursor; } while (cursor is not null); Юзер может остановиться в любой момент. CancellationToken важно передавать в сетевой вызов, чтобы отмена не ждала лишнюю страницу. await foreach (var order in ReadOrders(token)) { await SaveAsync(order, token); } Такой подход полезен для импорта каталога, обработки событий и синхронизации данных. Память не растёт вместе с общим количеством страниц, а обработка начинается сразу после первого ответа. ➡️ C# Ready | #практика
15 · 2K ·
C
C# Ready | Unity
Фотография
нажмите — покажем
Фотография
нажмите — покажем
Фотография
нажмите — покажем
Фотография
нажмите — покажем
Фотография
нажмите — покажем
Разбираем 7 инструментов для работы со временем! В .NET важно различать длительность, измерение прошедшего времени и ожидание. TimeSpan хранит интервал, Stopwatch измеряет выполнение, а PeriodicTimer и Task.Delay помогают управлять асинхронной работой. ➡️ C# Ready | #шпора
12 · 2.1K ·
C
C# Ready | Unity
Фотография
нажмите — покажем
Схема прохождения запроса через middleware в ASP.NET Core! На картинке показан путь HTTP-запроса через обработчик исключений, HTTPS, статические файлы, маршрутизацию, CORS, аутентификацию и авторизацию. Например, проверка прав должна выполняться после определения пользователя. Если поставить middleware не в том порядке, приложение может неожиданно возвращать 401, пропускать нужную обработку или выполнять лишнюю работу. Сохрани, чтобы не потерять! ➡️ C# Ready | #совет
26 · 1.5K ·
C
C# Ready | Unity
Фотография
нажмите — покажем
Почему фабрика в ConcurrentDictionary.GetOrAdd может сработать несколько раз? ConcurrentDictionary удобно использовать, когда несколько потоков обращаются к одному словарю. Кажется, что GetOrAdd одновременно проверяет ключ и ровно один раз создаёт значение: var profile = cache.GetOrAdd(id, key => LoadProfile(key)); В словаре действительно останется одно значение для ключа. Но это не означает, что LoadProfile обязательно вызовется только один раз. Фабрика выполняется вне внутренней блокировки словаря. Если два потока одновременно не нашли ключ, оба могут начать загрузку: var first = cache.GetOrAdd(id, LoadProfile); var second = cache.GetOrAdd(id, LoadProfile); Словарь сохранит один результат и вернёт его обоим вызовам, а результат другой загрузки окажется лишним. Поэтому в фабрику не стоит помещать побочные эффекты, например списание денег или отправку письма. Если повторное вычисление недорого и безопасно, обычный GetOrAdd подходит. Для дорогой инициализации можно хранить в словаре Lazy<T>: var pending = cache.GetOrAdd(id, key => new Lazy<Profile>(() => LoadProfile(key))); var profile = pending.Value; Здесь у разных потоков тоже могут создаться несколько объектов Lazy, но в словаре останется один. У него загрузка при обращении к Value выполнится один раз при стандартном режиме Lazy. Не забывайте и про ошибки. По умолчанию Lazy запоминает исключение фабрики, а значит последующие обращения к тому же Value снова получат эту ошибку: cache.TryRemove(id, out _); Удалять запись для повтора нужно с учётом конкуренции с другими запросами. ➡️ C# Ready | #совет
5 · 1.4K ·
C
C# Ready | Unity
Проверяем целостность скачанного файла в C#! После загрузки архива полезно убедиться, что полученные байты совпадают с опубликованной контрольной суммой. Пусть ожидаемый SHA-256 приходит из источника, отдельно от самого файла. Сначала проверим его формат и превратим шестнадцатеричную строку в байты: if (expectedHex.Length != 64) throw new ArgumentException("Неверный SHA-256"); byte[] expected = Convert.FromHexString(expectedHex); Теперь expected содержит ровно 32 байта. Если строка нужной длины, но содержит не шестнадцатеричные символы, Convert.FromHexString выбросит FormatException. Так произвольный текст не пройдёт за корректный хеш. Откроем файл потоком, чтобы не загружать весь архив в память: await using var stream = File.OpenRead(path); byte[] actual = await SHA256.HashDataAsync(stream); HashDataAsync прочитает файл до конца и вернёт 32 байта. Для больших файлов потребление памяти остаётся небольшим, поскольку поток обрабатывается постепенно. Сравним результат с ожидаемым значением: bool valid = CryptographicOperations.FixedTimeEquals(actual, expected); if (!valid) throw new InvalidDataException("SHA-256 не совпал"); ➡️ C# Ready | #практика
11 · 1.7K ·
C# Ready | Unity
Фотография
нажмите — покажем
Фотография
нажмите — покажем
Фотография
нажмите — покажем
Фотография
нажмите — покажем
Фотография
нажмите — покажем
Разбираем 7 инструментов HttpClient! HttpClient пригодится не только для простого GET. С ним можно проверять HTTP-статус, отправлять JSON, читать ответ как текст или поток и собирать запросы с нужным методом и заголовками. В этой шпоре собраны GetAsync, EnsureSuccessStatusCode, ReadAsStringAsync, GetFromJsonAsync, PostAsJsonAsync, SendAsync и GetStreamAsync. ➡️ C# Ready | #шпора
8 · 801 ·
Фотография
нажмите — покажем
Как оплачивать зарубежные сервисы в 2026 году? Можно бегать между посредниками и бояться блокировок после оплаты, а можно выпустить международную карту Lumio Pay и пользоваться любимыми сервисами без рисков. — выпуск карты за 2 минуты — лучший курс пополнения на рынке (у конкурентов на 20% выше) — пополнение рублями или криптой — чистые BIN карт, оплата без риска блокировок Пока все ищут идеальное решение, оно у тебя перед глазами: @LumioPay
5 · 615 ·
Фотография
нажмите — покажем
Почему копия record через with может изменить исходные данные? Выражение with удобно для создания нового record с одним изменённым полем. Кажется, что после копирования два объекта полностью независимы. Представим профиль со списком тегов: record Profile(string Name, List<string> Tags); var original = new Profile("Ana", new() { "dev" }); Создадим копию с другим именем: var copy = original with { Name = "Bob" }; Сам record действительно новый. Но with делает поверхностную копию, поэтому поле Tags в обоих объектах указывает на один и тот же список. Теперь изменим теги только у копии: copy.Tags.Add("admin"); Console.WriteLine(string.Join(", ", original.Tags)); Результат у исходного профиля тоже станет dev, admin. С новым именем всё в порядке, проблема только во вложенном изменяемом объекте. Если нужен отдельный список, явно создайте его при копировании: var independent = original with { Tags = new List<string>(original.Tags) }; Теперь добавление в independent.Tags не изменит original.Tags. Но это копия только самого списка. Если элементы списка тоже изменяемые объекты, их придётся копировать отдельно. ➡️ C# Ready | #совет
2 · 443 ·
Фотография
нажмите — покажем
🦈 Открытое собеседование на Middle C# | 6 октября, 19:00 МСК Приглашаем на открытое собеседование: Senior C# разработчик проведёт его в прямом эфире. Можно посмотреть, как всё устроено изнутри, и понять, насколько ты готов к такому интервью. Как это будет: 📂 Собеседует Александр Моргунов — Senior C# разработчик, 7+ лет в европейских высоконагруженных сервисах. Отвечает разработчик-доброволец; 📂 Всё как на настоящем собесе: Александр задаёт те вопросы и задачи, которые даёт кандидатам на своих интервью. Заранее их никто не знает; 📂 После каждого ответа Александр даст обратную связь: что прозвучало сильно, а что стоило раскрыть иначе. Так станет понятнее, на что обращают внимание на собесе; 📂 В конце можно задать любой вопрос. Это бесплатно. Эфир проходит в рамках менторской программы от ШОРТКАТ для C# разработчиков, которые хотят повысить свой грейд, ЗП и прокачать скиллы. Переходи в нашего бота, чтобы получить ссылку на эфир -> @shortcut_csharp_bot Реклама. О рекламодателе.
4 · 964 ·
C
Фотография
нажмите — покажем
Знали, когда в C# удобно использовать Random.Shared? Для простого случайного числа нередко создают отдельный генератор прямо в месте вызова: int dice = new Random().Next(1, 7); Такой код работает, но при частых вызовах приходится снова и снова создавать объект. Если генератор нужен во многих местах приложения, проще взять общий экземпляр: int dice = Random.Shared.Next(1, 7); Random.Shared доступен начиная с .NET 6 и безопасен для одновременного использования из разных потоков. Для обычных игровых событий, тестовых данных и случайного выбора этого достаточно. Обратите внимание на границы Next. Нижняя включается, верхняя нет: int index = Random.Shared.Next(0, items.Count); Так можно выбрать индекс, не выйдя за пределы списка. Для шестигранного кубика верхняя граница должна быть 7, а не 6: int dice = Random.Shared.Next(1, 7); А вот пароли, токены и коды подтверждения этим способом генерировать нельзя. Для значений, которые должны быть непредсказуемы для атакующего, нужен криптографический генератор: int code = RandomNumberGenerator.GetInt32(100000, 1000000); Random.Shared хорош для обычной случайности, а RandomNumberGenerator нужен там, где от случайности зависит безопасность. ➡️ C# Ready | #совет
6 · 1K ·
C
C# Ready | Unity
Фотография
нажмите — покажем
Почему цепочка LINQ иногда читает всю коллекцию до первого результата? Where и Select могут отдавать элементы по одному. А вот OrderBy, GroupBy и Join устроены сложнее, им нужно подготовить данные, прежде чем продолжить обработку. Автор разбирает эту границу между ленивым вычислением и буферизацией. В статье показывают: • зачем OrderBy хранит элементы и сортирует индексы • как GroupBy собирает группы и сохраняет порядок их появления • почему Join сначала строит структуру для внутренней коллекции Можно понять куда уходит память в длинных цепочках и почему перестановка операций иногда меняет стоимость запроса. Продолжай читать на Habr! ➡️ C# Ready | #статья
12 · 705 ·
C
C# Ready | Unity
Фотография
нажмите — покажем
Шпаргалка по источникам памяти для Span<T> в C#! На картинке рядом показаны три способа создать Span<T>. Он может ссылаться на обычный массив, область stackalloc или неуправляемый участок памяти. Отдельные примеры помогают увидеть, что Span<T> описывает диапазон, а не владеет памятью. Сохрани, чтобы не потерять! ➡️ C# Ready | #ресурс
4 · 434 ·

Открытая публичная лента из поискового индекса ChatCrawler — «Google по публичному Telegram»; обновляется по мере обхода площадки. Время — UTC.

Только публичный контент, официальный API Telegram. О проекте · Вопросы · Чего мы не делаем · Убрать страницу из выдачи · Каталог · Поиск · Как мы считаем