Шпаргалка по class, record и struct в C#!
Например, class и record class являются ссылочными типами, а struct и record struct передают значения как отдельные данные.
На карточках сравниваются равенство, присваивание и копирование через with. Отдельно показано, почему with не создаёт глубокую копию вложенного списка.
Сохрани, чтобы не потерять!
➡️ C# Ready | #шпора
Gemini Pro на 24 месяца за 800₽!
Вместо 39.000₽ — всего 800₽ ($9.9) за 2 года. По акции сейчас это 33₽ в месяц, в 48 раз выгоднее!
➡Argon 4.0 + Claude Opus 5.5 — для кода
➡Nano Banana 2 Pro — для картинок
➡Генерация видео — ролики и анимации
➡AntiGravity + 5 ТБ облака
➡Opus 5.5 и Sonnet 5.5
➡Youtube Premium
Акция ограничена по времени, дальше будет официальная цена 480$!
Приобрести можно в Магазине с 20.000+ покупок и 2000+ отзывов (есть возвраты и замены).
Почему ValueTask не стоит использовать ради ускорения?
ValueTask часто воспринимают как более быстрый Task. На практике он полезен не всегда и может сделать код сложнее.
Главный сценарий для ValueTask появляется, когда результат часто уже готов синхронно. Например, значение нашлось в памяти и не нужно создавать полноценный Task.
Такой метод может вернуть готовое значение без лишней аллокации:
if (cache.TryGetValue(id, out var user))
{
return new ValueTask(user);
}
А если значения нет, можно перейти к обычной async-операции:
return new ValueTask(LoadAsync(id));
Но у ValueTask есть ограничения. Его нельзя бездумно ждать несколько раз, сохранять на потом или передавать по цепочке как обычный Task.
Плохой пример выглядит так:
var result = GetUserAsync(id);
await result;
await result;
С Task такое обычно безопасно, а с ValueTask можно получить неожиданное поведение, особенно если внутри используется IValueTaskSource.
Если метод почти всегда делает настоящий async I/O, лучше оставить Task:
Task LoadUserAsync(int id)
{
return db.Users.FindAsync(id).AsTask();
}
ValueTask используйте только там, где на то есть причина и польза.
➡️ C# Ready | #совет
CSharpGuide по C# и .NET!
Каталог разбит на шесть этапов, основы языка, управление потоком, методы и коллекции, ООП, продвинутый C# и практический .NET. Внутри этапов собраны отдельные уроки по переменным, LINQ, async/await, JSON, тестированию и другим темам.
В уроках есть примеры кода, которые запускаются прямо в браузере, и последовательные переходы между темами.
Оставляю ссылочку на CSharpGuide
➡️ C# Ready | #ресурс
Почему арендованный ArrayPool буфер нельзя использовать как обычный массив?
ArrayPool<T> позволяет повторно использовать массивы и уменьшать число выделений памяти. Но Rent может вернуть массив больше запрошенного, а его содержимое может остаться от предыдущего владельца.
Запрашиваем буфер для нужной операции:
byte[] buffer = ArrayPool<byte>.Shared.Rent(4096);
Размер массива может быть больше 4096. Поэтому передавай дальше только диапазон, в который действительно записаны данные:
int written = await stream.ReadAsync(buffer);
await destination.WriteAsync(buffer.AsMemory(0, written));
Если отправить весь массив, в файл или ответ попадут лишние байты. В них может оказаться старое содержимое, а не только нули.
Возвращем массив в пул даже при исключении:
try { await ProcessAsync(buffer.AsMemory(0, written)); }
finally { ArrayPool<byte>.Shared.Return(buffer); }
После Return считаем буфер чужим и не сохраняй на него ссылки. Следующий Rent может получить этот же массив другой операции, пока прежний код продолжает его читать.
Для паролей, токенов и других секретов очищаем массив при возврате:
ArrayPool<byte>.Shared.Return(buffer, clearArray: true);
➡️ C# Ready | #совет
Шпаргалка по TimeProvider в .NET 8!
TimeProvider объединяет системные часы, монотонные метки и таймеры за одним интерфейсом. Его можно заменить тестовым источником времени, чтобы проверять задержки и дедлайны без ожидания настоящих секунд.
На карточках собраны чтение даты, замер интервалов, запуск таймера и ограничение ожидания асинхронной операции. Для длительности используются GetTimestamp и GetElapsedTime, а не разность календарных дат.
Сохрани, чтобы не потерять!
➡️ C# Ready | #шпора
🔴В 2025 году Россияне заработали 5,3 млрд рублей на арбитраже криптовалют
По данным Минфин 32% граждан покинули своё место работы поскольку в среднем уже в первый месяц смогли заработать 250 000 рублей, а через 2-3 месяца с легкостью вышли на семизначные числа.
Самое смешное, что лишь 8% россиян что-то слышали об этой профессии хотя все инструкции бесплатно лежат на канале Арбитраж Криптовалют
Там объясняют, как имея телефон и доступ в интернет заработать свои первые $3000. Причём разжёвывают так доступно, что поймёт даже ребенок. Кстати, на канале сегодня вышла новая рабочая связка!
Ссылка для входа — https://t.me/+lvVed8tyOGg5ZWNi
Находим лишние аллокации в C#!
Когда код создаёт много короткоживущих объектов, сборщик мусора начинает запускаться чаще. Быстро оценим объём управляемых аллокаций вокруг синхронной операции.
Сначала прогреваем метод, чтобы вынести первичную компиляцию из измеряемого участка:
Render(records);
Снимаем счётчик до серии одинаковых вызовов:
long before = GC.GetAllocatedBytesForCurrentThread();
for (int i = 0; i < 100; i++) Render(records);
long allocated = GC.GetAllocatedBytesForCurrentThread() - before;
Счётчик относится только к текущему потоку. Поэтому измеряемая операция должна быть синхронной и не переносить основную работу на Task, пул потоков или нативный код.
Делим результат на количество повторов и сравниваем варианты:
double bytesPerCall = allocated / 100.0;
Console.WriteLine($"{bytesPerCall:F1} bytes/call");
Такой счётчик помогает заметить, что изменение уменьшило или увеличило выделение памяти в синхронном коде.
➡️ C# Ready | #практика
Как Dictionary<TKey, TValue> находит и добавляет запись!
На схеме показано, как ключ проходит через GetHashCode и попадает в bucket. Если в нём уже есть записи с таким же hash code, поле next связывает их в цепочку, а совпадение ключа проверяется отдельно.
➡️ C# Ready | #ресурс
Собираем динамический фильтр товаров на C#!
Нужно отбирать активные товары по минимальной цене, но набор условий может меняться. Построим predicate из expression tree, а затем применим его к коллекции.
В этой задаче:
• создаём параметр товара и обращаемся к его свойствам
• строим условия цены и активности
• объединяем узлы в готовый предикат
Для коллекции в памяти дерево можно скомпилировать в Func. Для IQueryable передаём само выражение провайдеру, чтобы он мог обработать его дальше.
➡️ C# Ready | #задача
«ИИ — новая атомная бомба». «Все айтишники — солдаты».
Это не цитата из антиутопии. Это официальный манифест Palantir — компании, чей софт стоит на службе у Пентагона и полиции США.
В апреле манифест опубликовали открыто. Суть: следить за всеми — во благо. А алгоритмы Palantir уже давно умеют выбирать цели для ударов и собирать профили людей.
Они обещают следить за всеми во благо. Спасибо, конечно. Но от такой заботы лучше отказаться. В «Пакете безопасности» показываем, как затереть цифровой след, отключить настройки слежки и спрятать то, что не должно всплыть.
Планы технократов теперь в открытом доступе, и им не стыдно. Дальше — больше. Подпишись: @package_security
Зачем задавать таймаут для регулярного выражения?
Некоторые шаблоны с повторяющимися группами могут замедлиться на строке, которая почти совпадает с образцом. Если вход приходит от пользователя, один такой запрос способен надолго занять поток обработки.
Шаблон выглядит вполне обычно:
var pattern = new Regex(@"^(a+)+$");
bool matches = pattern.IsMatch(input);
При длинной последовательности символов и несовпадающем последнем символе движок может перебирать множество вариантов. Это называют катастрофическим возвратом.
Задаём конечное время на одну проверку:
var pattern = new Regex(
@"^(a+)+$",
RegexOptions.None,
TimeSpan.FromMilliseconds(200));
Таймаут ограничивает работу одного сопоставления. Для сервера его выбирают с учётом размера входа и нагрузки, а не выставляют бесконечное ожидание.
Обрабатываем превышение отдельно от обычного несовпадения:
try
{
return pattern.IsMatch(input);
}
catch (RegexMatchTimeoutException)
{
return ValidationResult.TimedOut;
}
Таймаут не означает, что строка просто не подошла. Возвращаем контролируемый результат, фиксируем метрику и не запускаем тот же шаблон повторно на том же вводе.
Когда вложенные группы не нужны, упрощаем сам шаблон:
var pattern = new Regex(
@"^a+$",
RegexOptions.None,
TimeSpan.FromMilliseconds(200));
Таймаут остаётся защитным ограничением, а более простой шаблон сокращает лишний перебор.
➡️ C# Ready | #совет