C# Ready | Unity
10.4K subscribers
1.46K photos
84 videos
728 links
Авторский канал по разработке на C# и Unity.
Ресурсы, гайды, задачи, шпаргалки.
Информация ежедневно пополняется!

Cотрудничество: @energy_c

РКН: https://clck.ru/3SBaT3
Download Telegram
Разбираем 7 инструментов HttpClient!

HttpClient пригодится не только для простого GET. С ним можно проверять HTTP-статус, отправлять JSON, читать ответ как текст или поток и собирать запросы с нужным методом и заголовками.

В этой шпоре собраны GetAsync, EnsureSuccessStatusCode, ReadAsStringAsync, GetFromJsonAsync, PostAsJsonAsync, SendAsync и GetStreamAsync.

➡️ C# Ready | #шпора
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥8🤝4❤3👍2
Почему копия 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 | #совет
Please open Telegram to view this post
VIEW IN TELEGRAM
❤6👍4🔥3
Знали, когда в 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 | #совет
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9❤4🔥4
Почему цепочка LINQ иногда читает всю коллекцию до первого результата?

Where и Select могут отдавать элементы по одному. А вот OrderBy, GroupBy и Join устроены сложнее, им нужно подготовить данные, прежде чем продолжить обработку. Автор разбирает эту границу между ленивым вычислением и буферизацией.

В статье показывают:
• зачем OrderBy хранит элементы и сортирует индексы
• как GroupBy собирает группы и сохраняет порядок их появления
• почему Join сначала строит структуру для внутренней коллекции

Можно понять куда уходит память в длинных цепочках и почему перестановка операций иногда меняет стоимость запроса.

Продолжай читать на Habr!


➡️ C# Ready | #статья
Please open Telegram to view this post
VIEW IN TELEGRAM
❤6🔥6👍3
Шпаргалка по источникам памяти для Span<T> в C#!

На картинке рядом показаны три способа создать Span<T>. Он может ссылаться на обычный массив, область stackalloc или неуправляемый участок памяти. Отдельные примеры помогают увидеть, что Span<T> описывает диапазон, а не владеет памятью.

Сохрани, чтобы не потерять!

➡️ C# Ready | #ресурс
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3❤1👍1
🎓 Как гарантированно войти в сферу кибербезопасности с официальным дипломом?

Самостоятельное обучение в ИБ - это месяцы хаоса и разрозненных роликов с YouTube. Покупка курсов по отдельности на популярных платформах легко переваливает за 300 000 ₽.

🔥CyberYozh Academy собрали цельный карьерный трек в один пак: 5 фундаментальных программ + официальный Диплом системного администратора за 50 000 ₽ (вместо ~250 000 ₽)

Что входит в программу:
▪️ Linux CyberPunk - системное администрирование с выдачей диплома, открывающего двери в корпоративный сектор.
▪️ SQL для хакера - глубокое понимание архитектуры баз данных и векторов атак.
▪️ HackerPoint - продвинутый уровень пентеста и анализа уязвимостей.
▪️ HackerPoint (Blue vs Red Team) - база сетевой безопасности, защиты и атак.
▪️ AI-помощники на Python - автоматизация рутины безопасника при помощи нейросетей.

Вы получаете законченную квалификацию: от администрирования защищенных облачных решений до проведения тестов на проникновение.

⚠️ Обратите внимание: Из-за персональной проверки заданий и официального оформления дипломов на каждый поток действует жесткий лимит - не более 15 мест.

🦔Отправь промокод C#Ready в чат с менеджером, чтобы закрепить за собой скидку и узнать подробности:
👉@cyacademy_support
Please open Telegram to view this post
VIEW IN TELEGRAM
❤1
Почему await Task.WhenAll может показать не все ошибки сразу?

Допустим несколько независимых операций выполняются параллельно. Мы объединяем их в одну задачу:
var all = Task.WhenAll(first, second);
await all;


Если обе операции завершатся с ошибками, WhenAll дождётся обеих. Итоговая задача будет содержать исключения из всех упавших операций.

Для диагностики сохраните общую задачу перед await:
var all = Task.WhenAll(first, second);


Теперь можно дождаться её и обработать неудачу:
try
{
await all;
}
catch
{
Console.Error.WriteLine(all.Exception);
throw;
}


Свойство all.Exception содержит AggregateException. Его InnerExceptions позволяют увидеть ошибки нескольких операций, а не только ту, которую выбросил await. Например, внутри обработки именно ошибочной задачи можно пройтись по ним:
foreach (var error in all.Exception!.InnerExceptions)
Console.WriteLine(error.Message);


Знак ! здесь уместен только внутри ветки, где общая задача действительно завершилась с ошибкой. Если она была отменена без ошибок, Exception будет null, и обработку отмены нужно делать отдельно.


Почему await Task.WhenAll может показать не все ошибки сразу?

Допустим, несколько независимых операций выполняются параллельно. Мы объединяем их в одну задачу:
var all = Task.WhenAll(first, second);
await all;


Если обе операции завершатся с ошибками, WhenAll дождётся обеих. Итоговая задача будет содержать исключения из всех упавших операций. Но обычный await выбрасывает одно исключение, поэтому в catch легко увидеть только часть картины.

Для диагностики сохраните общую задачу перед await:
var all = Task.WhenAll(first, second);


Теперь можно дождаться её и обработать неудачу:
try
{
await all;
}
catch
{
Console.Error.WriteLine(all.Exception);
throw;
}


Свойство all.Exception содержит AggregateException. Его InnerExceptions позволяют увидеть ошибки нескольких операций, а не только ту, которую выбросил await. Например, внутри обработки именно ошибочной задачи можно пройтись по ним:
foreach (var error in all.Exception!.InnerExceptions)
Console.WriteLine(error.Message);


Знак ! здесь уместен только внутри ветки, где общая задача действительно завершилась с ошибкой. Если она была отменена без ошибок, Exception будет null, и обработку отмены нужно делать отдельно.

➡️ C# Ready | #совет
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5❤2👍2
Альфа-Банк ищет скиллового коллегу QA Fullstack на C#

Предлагаем полную удалёнку или гибридный график – у нас классные ИТ-офисы в Москве, Питере и Екатеринбурге.

Что нужно делать

– Разрабатывать автотесты на C#.
– Запускать функциональные, регрессионные и интеграционные тесты, включая API.
– Снижать количество дефектов в диалоге с разработкой и бизнесом.

Какие навыки важны

– Опыт автоматизации на C# и ручного тестирования от года.
– Знание API (SOAP, REST), SQL, основ клиент-серверной архитектуры и тест-дизайна.

Условия и развитие

– Сильное сообщество QA и C#-разработчиков: можно получить совет и поделиться опытом на митапе и в блоге на Хабре.
– Реальная перспектива роста: технический трек развития, в том числе до C#-лида

Оставляйте отклик по ссылке.
❤3🔥1
Читаем большой JSON-массив по одному объекту в C#!

Пусть orders.json содержит тысячи заказов одним массивом. Если загрузить файл целиком через ReadAllText, память займут и исходный текст, и созданные объекты. Для последовательной обработки удобнее читать поток и получать элементы по мере разбора.

Сначала опишем модель входных данных. В примере у каждого заказа есть номер и сумма:
public sealed record Order(int Id, decimal Total);


Откроем файл как поток. JsonSerializer.DeserializeAsyncEnumerable ожидает JSON-массив и возвращает асинхронную последовательность его элементов:
await using var stream = File.OpenRead("orders.json");
var orders = JsonSerializer.DeserializeAsyncEnumerable<Order>(
stream, cancellationToken: cancellationToken);


Здесь cancellationToken позволяет прервать длительную обработку, например при остановке запроса или фоновой задачи. Не надо самостоятельно резать JSON на строки, переносы строк не определяют границы объектов.

Обработаем элементы по одному и накопим итог. Нулевые элементы пропустим, а отрицательную сумму считаем ошибкой данных:
decimal total = 0;
await foreach (Order? order in orders) {
if (order is null) continue;
if (order.Total < 0) throw new InvalidDataException("Сумма меньше нуля");
total += order.Total;
}


После завершения цикла в total будет сумма всех валидных заказов. В нужном месте вместо накопления можно отправлять запись в базу. Если важна устойчивость к повторной обработке, используй Id как ключ идемпотентности.

➡️ C# Ready | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🔥4❤2
❤6👍2🔥2