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

Автор: @energy_it

РКН: https://clck.ru/3SBaT3

Реклама на бирже: https://telega.in/c/csharp_ready
Download Telegram
Как писать SQL / JSON с интерполяцией без +, \n и экранирования?

Когда в коде появляются большие SQL или JSON, обычные строки быстро превращаются в кашу: конкатенации, \n, кавычки, сложно читать и ещё сложнее править.

В C# 11 появились raw-строки ("""), которые позволяют писать многострочный текст “как есть”:
var sql = """
SELECT * FROM Users
""";


Но что делать, если в тексте нужны переменные?

Для этого используются raw-строки с интерполяцией$$""" и {{ }}:
var sql = $$"""
FROM {{table}}
WHERE Name = '{{name}}'
""";


Количество $ определяет, сколько { нужно для вставки значения — это позволяет без боли писать JSON, SQL и шаблоны с фигурными скобками внутри.

🔥 raw-строки с интерполяцией — лучший способ хранить большие тексты в коде.

➡️ C# Ready | #совет
Please open Telegram to view this post
VIEW IN TELEGRAM
17👍11🔥4
This media is not supported in your browser
VIEW IN TELEGRAM
❤️ Refactoring.Guru — это образовательный сайт о рефакторинге, паттернах проектирования и принципах SOLID!

На нём вы найдёте каталог code smells (запахов кода) и техник рефакторинга, а также разбор 22 классических паттернов с понятными объяснениями и примерами. Плюс — книги и материалы для системного изучения темы.

📌 Оставляю ссылочку: refactoring.guru

➡️ C# Ready | #ресурс
Please open Telegram to view this post
VIEW IN TELEGRAM
13🔥5👍3
CallerArgumentExpression: показываем точное выражение в ошибке без ручных строк!

Часто в коде есть проверки аргументов: null, пустая строка, отрицательное значение. Обычно хочется, чтобы ошибка сразу говорила, какое именно выражение провалилось, но это быстро превращается в ручные строки и копипасту.

Раньше приходилось писать сообщения руками, чтобы понять причину падения:
static void Ensure(bool condition, string message)
{
if (!condition)
throw new ArgumentException(message);
}


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

И вот как это выглядит на реальном вызове:
var user = "Анна";
var age = -1;

Ensure(!string.IsNullOrWhiteSpace(user), $"Некорректный user: '{user}'");
Ensure(age > 0, $"Некорректный age: {age}");


Проблема в том, что это шумно: строки надо поддерживать, легко забыть обновить при рефакторинге, а сложные условия превращаются в “конструктор сообщений”.

В C# 10 появился CallerArgumentExpression — он умеет получать исходный текст выражения, которое передали в метод:
using System.Runtime.CompilerServices;

static void Ensure(bool condition, string? message = null,
[CallerArgumentExpression("condition")] string? expr = null)
{
if (!condition)
throw new ArgumentException(message ?? $"Проверка не прошла: {expr}");
}


А вызов теперь можно сделать коротким, без ручных строк:
var user = "Анна";
var age = -1;

Ensure(!string.IsNullOrWhiteSpace(user));
Ensure(age > 0);


Если условие провалится, сообщение получится информативным автоматически, например “Проверка не прошла: age > 0”.

🔥 Проверки становятся короче, а сообщения об ошибках — намного полезнее без копипасты.

➡️ C# Ready | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
15👍7🔥3
А у вас в проекте “unsafe” когда-нибудь появлялся незаметно?

В C# обсуждают идею caller-unsafe: опасный API помечается так, что вызвать его можно только из кода в unsafe.

Почему это важно: сейчас метод может быть объявлен unsafe, но это не всегда означает, что вызывающий код тоже обязан быть unsafe. Из-за этого небезопасные места иногда прячутся “между строк” и хуже ловятся на ревью.

Если фичу примут, контракт станет честнее: хочешь вызвать такой метод — явно отмечай место вызова как unsafe (осознанно).

Обсуждение:
dotnet/csharplang

➡️ C# Ready | #новость
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8🔥54
Почему ??= читается лучше, чем if (x == null)?

Самая частая “мелкая боль” в C# — ленивые дефолты: “если ещё не задано — создай”. Из-за этого в коде растут одинаковые проверки null, которые не добавляют смысла и мешают читать логику.

Оператор ??= делает ровно то же самое, но прямо выражает намерение:
user ??= new User();


Это эквивалентно:
if (user == null)
user = new User();


Особенно полезно, когда значение может прийти из разных мест (DI, конфиг, кеш), и ты просто хочешь гарантировать дефолт без лишнего ветвления.

🔥??= — дешёвый способ убрать шум, снизить шанс “забыл присвоить” и сделать код читаемым

➡️ C# Ready | #совет
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3611🔥6👎3
👩‍💻 Преобразования типов без лишней магии!

В этой шпаргалке — как приводить значения к нужному типу без сюрпризов: где ловятся ошибки формата и переполнения, почему числа и даты зависят от культуры, как безопасно работать с null, и чем “пусто из базы” отличается от обычного null.

➡️ C# Ready | #шпора
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2611👍6🤝4👎2
📂 Шпаргалка по API-протоколам!

Разные способы общения сервисов подходят под разные задачи: где-то нужны обычные запросы, где-то события, стриминг или real-time. Есть варианты попроще для типовых интеграций и более строгие/быстрые — для микросервисов, высокой нагрузки и IoT.

На картинке — краткая карта API-технологий и когда что выбирать. Сохрани, пригодится.

➡️ C# Ready | #ресурс
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥136👍4👎2
ReadOnlySpan<char> вместо Substring: парсим строки без лишних аллокаций!

Когда строка режется через Substring, чаще всего создаётся новый объект string, и на потоке логов или CSV это быстро становится заметно по памяти.

Привычный вариант:
string line = "id=42;name=alice";
string idPart = line.Substring(3, 2);
int id = int.Parse(idPart);


Если нужен только разбор части строки, то лучше использовать ReadOnlySpan<char>.
ReadOnlySpan<char> line = "id=42;name=alice";
int sep = line.IndexOf(';');
ReadOnlySpan<char> idPart = line.Slice(3, sep - 3);
int id = int.Parse(idPart);


Здесь не создаётся промежуточная строка, поэтому уменьшается лишняя работа для GC.

Важно помнить, что ReadOnlySpan<char> не хранит данные и только ссылается на источник, поэтому его нельзя держать в полях класса.

🔥 В итоге парсинг остаётся простым и при этом становится заметно дешевле по памяти.

➡️ C# Ready | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥115👍3
14👍6🔥4
Как узнать, какой аргумент пришёл null, без ручных строк?

Обычно в проверках хочется написать “что именно было null”, но если делать это строками, они быстро устаревают после рефакторинга. В итоге кто-то переименовал переменную, а сообщение об ошибке осталось старым.

В C# можно сделать так, чтобы имя выражения подставлялось автоматически — через CallerArgumentExpression. Смотри на параметр:
[CallerArgumentExpression("value")] string? expr = null


Теперь при вызове:
NotNull(user);


если user окажется null, исключение будет ArgumentNullException("user") — без магических строк и без копипасты.

И даже если передать выражение, оно тоже попадёт в текст:
NotNull(cache[key]);


🔥 CallerArgumentExpression — это “бесплатная диагностика”. Меньше ручных сообщений, лучше ошибки, и после переименований всё остаётся корректным автоматически.

➡️ C# Ready | #совет
Please open Telegram to view this post
VIEW IN TELEGRAM
👍14🔥53
13👍7🔥4
Что же выведет консоль?
Anonymous Quiz
39%
A
35%
B
16%
C
10%
D
19👍14🔥7😁2🤝1
✍️ Отличная статья — про то, как собрать свою первую 2D-игру на MonoGame!

В этой статье:
• Поймёшь, как устроен игровой цикл: Initialize → LoadContent → Update → Draw;
• Научишься загружать и рисовать текстуры (спрайты) и управлять позициями объектов;
• Разберёшь основы архитектуры 2D-игры на MonoGame и сделаешь первый рабочий прототип


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


➡️ C# Ready | #статья
Please open Telegram to view this post
VIEW IN TELEGRAM
👍116🔥5
ArrayPool<T> в C#: снижаем нагрузку на GC в горячем коде!

Когда в каждом запросе создаётся новый byte[], приложение начинает чаще упираться в сборку мусора. На небольшом трафике это незаметно, но под нагрузкой появляются лишние паузы.

Обычно код выглядит так:
static void Handle(ReadOnlySpan<byte> payload, Stream output)
{
var buffer = new byte[8192];
payload.CopyTo(buffer);
output.Write(buffer, 0, payload.Length);
}


Если такая операция выполняется часто, лучше брать буфер из ArrayPool<byte>.Shared и возвращать его после работы:
using System.Buffers;

static void Handle(ReadOnlySpan<byte> payload, Stream output)
{
byte[] buffer = ArrayPool<byte>.Shared.Rent(8192);

try
{
payload.CopyTo(buffer);
output.Write(buffer, 0, payload.Length);
}
finally
{
ArrayPool<byte>.Shared.Return(buffer, clearArray: true);
}
}


Важно помнить, что пул может выдать массив больше запрошенного размера, поэтому работай только с нужным диапазоном данных. И всегда возвращай буфер в finally, иначе эффект от пула быстро пропадёт.

🔥 В итоге ты заметно сокращаешь количество аллокаций и делаешь поведение сервиса ровнее под нагрузкой.

➡️ C# Ready | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12🔥54
📂 Напоминалка по HTTP и сетевым протоколам!

Например, HTTP/1.1 использует постоянные соединения, HTTP/2 умеет мультиплексировать запросы в одном TCP-канале, а HTTP/3 работает поверх QUIC и UDP.

На картинке — наглядная эволюция HTTP от первых версий до современных стандартов.

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

➡️ C# Ready | #ресурс
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥169👍4
Зачем в библиотечном async-коде часто ставят `ConfigureAwait(false)`?

Потому что await по умолчанию пытается “вернуться” в исходный контекст выполнения. В UI это может быть полезно. Но в библиотеке это обычно лишнее и иногда даже вредное.

Частая картина: внутри библиотеки есть await, а дальше никакого UI нет. Но метод всё равно тащит контекст вызывающего кода:
await http.GetStringAsync("/data");


Правильнее — явно сказать: “мне не важно возвращаться в этот контекст”:
await http.GetStringAsync("/data").ConfigureAwait(false);


Так библиотечный код становится более предсказуемым. Он меньше зависит от того, откуда его вызвали. И он не навязывает окружению свои ожидания.

В приложении, где после await ты обновляешь UI, ConfigureAwait(false) может быть неуместен. Это другое правило.

🔥 Меньше привязки к контексту, меньше неожиданностей, и код сразу говорит, что ему не нужен “возврат в UI”.

➡️ C# Ready | #совет
Please open Telegram to view this post
VIEW IN TELEGRAM
👍159🔥6
This media is not supported in your browser
VIEW IN TELEGRAM
❤️ CodeChef: C# with Beginner DSA — это пошаговый учебный на CodeChef

На нём ты найдёшь roadmap из ~6 курсов: от основ C# и логики до Beginner DSA, а дальше — закрепление через сотни задач по DSA/алгоритмам (под интервью и контесты).

📌 Оставляю ссылочку: codechef.com

➡️ C# Ready | #ресурс
Please open Telegram to view this post
VIEW IN TELEGRAM
👍105🔥3