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

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

РКН: https://clck.ru/3SBaT3
Download Telegram
Полезная статья про тестирование ASP.NET Core API!

Автор показывает, как уменьшить повторение в интеграционных тестах и собрать удобное окружение с БД, фейковым временем и настройкой под конкретный тест.

В статье автор показывает:
• как устроить тестовое окружение для ASP.NET Core API
• почему setup-код быстро начинает повторяться
• как фикстуры помогают переиспользовать инфраструктуру

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


➡️ C# Ready | #статья
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5❤4🔥3
Собираем простой таймер в C#!

Иногда нужно запустить действие через задержку: показать уведомление, выполнить повторную проверку или отложить сохранение. Но важно уметь отменить задачу, если она уже не нужна.

Создадим CancellationTokenSource:
using var cts = new CancellationTokenSource();


Теперь напишем отложенное действие:
static async Task RunLater(
TimeSpan delay,
Func<Task> action,
CancellationToken token)
{
await Task.Delay(delay, token);
await action();
}


Запуск выглядит так:
var task = RunLater(
TimeSpan.FromSeconds(3),
() => SaveAsync(),
cts.Token
);


Если пользователь изменил данные ещё раз, старую задачу можно отменить:
cts.Cancel();


Чтобы отмена не выглядела как ошибка, обработаем её отдельно:
try
{
await task;
}
catch (OperationCanceledException)
{
Console.WriteLine("Задача отменена");
}


Такой подход удобно использовать для debounce-сценариев: например, не сохранять форму после каждого символа, а ждать короткую паузу.

Пример с новым запуском:
cts.Cancel();

using var nextCts = new CancellationTokenSource();
await RunLater(
TimeSpan.FromSeconds(1),
() => SaveAsync(),
nextCts.Token
);


В реальном приложении вместо SaveAsync может быть отправка запроса, пересчёт фильтра или обновление превью.

➡️ C# Ready | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6❤3🔥2
Разбираем CancellationToken 7 приёмов для отмены операций!

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

В этой шпоре: CancellationToken, CancellationTokenSource, CancelAfter, ThrowIfCancellationRequested, IsCancellationRequested, CreateLinkedTokenSource и Register.

➡️ C# Ready | #шпора
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥12👍4❤3🤝1
❤10👍6🔥4
Полезная статья про бенчмарки в одном C# файле!

Автор показывает, как запускать BenchmarkDotNet без полноценного проекта. Идея особенно удобна для маленьких проектов, когда нужно быстро проверить информацию по производительности.

В статье автор показывает:
• как работают однофайловые приложения в .NET 10
• почему BenchmarkDotNet не стартует из коробки
• как использовать in-process режим и какие у него ограничения

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


➡️ C# Ready | #статья
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4👍3🔥2
Почему нельзя удалять элементы из List прямо внутри foreach?

foreach в C# удобен для чтения коллекции, но в нём лучше не менять коллекцию во время обхода.

На первый взгляд такой код выглядит нормально:
foreach (var user in users)
{
if (!user.Active) users.Remove(user);
}


Но во время выполнения List меняется, а перечислитель foreach ожидает, что структура коллекции останется прежней.

В результате можно получить InvalidOperationException:
Collection was modified;
enumeration operation may not execute.


Для простого удаления по условию чаще всего лучше использовать RemoveAll:
users.RemoveAll(user => !user.Active);


Мы не вручную управляем индексами, а говорим списку удалить все элементы, которые подходят под условие.

Если нужна более сложная логика, можно идти с конца по индексам:
for (int i = users.Count - 1; i >= 0; i--)
{
if (!users[i].Active) users.RemoveAt(i);
}


Обход с конца важен, потому что удаление элемента сдвигает следующие элементы влево. При движении назад это не ломает ещё не проверенную часть списка.

Ещё один вариант подходит, когда исходный список лучше не трогать:
users = users
.Where(user => user.Active)
.ToList();


Так создаётся новый список только с нужными элементами. Это удобно для pipeline-логики и случаев, где мутация исходных данных ненужна.

foreach используют для чтения, а для удаления выбирают RemoveAll, обратный for или создание нового списка.

➡️ C# Ready | #совет
Please open Telegram to view this post
VIEW IN TELEGRAM
❤10👍5🔥4
Почему record в C# не делает объект полностью неизменяемым?

record часто воспринимают как “immutable-класс”:
public record User(string Name, List<string> Roles);


Но неизменяемым становится не всё содержимое объекта.

Свойство Roles нельзя просто заменить, если оно init-only:
var user = new User("Ann", new List<string>());


Но сам список внутри всё ещё изменяемый:
user.Roles.Add("admin");


То есть record защищает ссылку на список, но не защищает сам список от изменений.

Это особенно важно, если объект передаётся между слоями приложения:
public record Profile(string Name, List<string> Permissions);


Код снаружи может сохранить ссылку и позже поменять содержимое:
var roles = new List<string> { "user" };
var profile = new Profile("Ann", roles);

roles.Add("admin");


Если нужен более безопасный вариант, лучше принимать IReadOnlyList:
public record Profile(
string Name,
IReadOnlyList<string> Permissions
);


А внутри создавать копию:
var profile = new Profile(
"Ann",
roles.ToArray()
);


Для публичных моделей это часто снижает риск случайных мутаций.

record даёт удобное сравнение и init-свойства, но не делает вложенные коллекции immutable. Изменяемые поля всё равно нужно контролировать отдельно.

➡️ C# Ready | #совет
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6❤3🔥2
This media is not supported in your browser
VIEW IN TELEGRAM
❤️ dotnet-learning — большая база ресурсов для изучения .NET!

Здесь собраны полезные материалы для обучения, практики и более глубокого изучения подходов разработки на .NET. Репозиторий помогает не просто изучать отдельные технологии, а выстраивать целостное понимание платформы. Такой формат удобен и новичкам, и разработчикам с опытом, которые хотят структурировать знания или закрыть пробелы.

Оставляю ссылочку: GitHub 📱


➡️ C# Ready | #репозиторий
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9❤6🔥4
👍8❤5🔥5
Шпаргалка по DateTime и форматам дат в C#!

Например, yyyy отвечает за год, MM за месяц, dd за день, HH за часы в 24-часовом формате, а zzz показывает смещение часового пояса.

На картинке собраны частые преобразования дат и времени. Есть Parse, ParseExact, ToString с форматами, Unix timestamp, DateTimeOffset и примеры конвертации между строками, DateTime и DateTimeOffset.

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

➡️ C# Ready | #совет
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6❤3🔥3👎2
Разбираем File и Path 7 инструментов для работы с файлами!

В C# для повседневной работы с файлами чаще всего хватает стандартных классов File, Directory и Path. Они закрывают проверку существования, чтение, запись, создание папок, обход директорий и безопасную сборку путей.

В этой шпоре собраны File.Exists, ReadAllText, WriteAllText, Directory.CreateDirectory, Directory.EnumerateFiles, Path.Combine и Path.GetExtension.

➡️ C# Ready | #совет
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥8❤3🤝3👍1
Почему Count() в LINQ может сделать лишнюю работу?

В C# часто нужно проверить, есть ли в последовательности хотя бы один элемент. Иногда для этого пишут так:
if (items.Count() > 0)
{
Console.WriteLine("not empty");
}


Для List<T> это может выглядеть безобидно, но LINQ работает не только со списками. Если items является IEnumerable<T>, Count() может пройти всю последовательность до конца.

На ленивых источниках это особенно неприятно:
var items = GetRows()
.Where(row => row.IsActive);


Проверка через Count() заставит перебрать все подходящие элементы, хотя для ответа достаточно первого.

Когда нужен только факт наличия элемента, лучше использовать Any():
if (items.Any())
{
Console.WriteLine("not empty");
}


Any() останавливается сразу после первого найденного элемента. Это проще по смыслу и часто дешевле по выполнению.

Если коллекция уже лежит в памяти как List<T>, массив или HashSet<T>, можно использовать свойство:
if (users.Count > 0)
{
Send(users);
}


А если действительно нужно точное количество, тогда Count() уместен:
var activeCount = users.Count(u => u.IsActive);


Для вопроса есть ли что-то используй Any(), для точного числа используй Count(), а для готовых коллекций смотри на свойство Count или Length.

➡️ C# Ready | #совет
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9❤6🔥4
This media is not supported in your browser
VIEW IN TELEGRAM
🐱 C# Job Questions — большая база для подготовки к собеседованиям!

Здесь собраны вопросы с развернутыми ответами и примерами кода по C# и .NET, ООП, алгоритмам и структурам данных, архитектуре, базам данных и многопоточности. Дополнительная тренировка, чтобы системно повторить теорию, проверить пробелы и подготовиться к технической части собесов.

Оставляю ссылочку: GitHub 📱


➡️ C# Ready | #репозиторий
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7❤4🔥3