Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥26❤11👍6🤝4👎2
Разные способы общения сервисов подходят под разные задачи: где-то нужны обычные запросы, где-то события, стриминг или real-time. Есть варианты попроще для типовых интеграций и более строгие/быстрые — для микросервисов, высокой нагрузки и IoT.
На картинке — краткая карта API-технологий и когда что выбирать. Сохрани, пригодится.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥13❤6👍4👎2
ReadOnlySpan<char> вместо Substring: парсим строки без лишних аллокаций!
Когда строка режется через
Привычный вариант:
Если нужен только разбор части строки, то лучше использовать
Здесь не создаётся промежуточная строка, поэтому уменьшается лишняя работа для GC.
Важно помнить, что
🔥 В итоге парсинг остаётся простым и при этом становится заметно дешевле по памяти.
➡️ C# Ready | #практика
Когда строка режется через
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> не хранит данные и только ссылается на источник, поэтому его нельзя держать в полях класса.Please open Telegram to view this post
VIEW IN TELEGRAM
🔥11❤5👍3
Как узнать, какой аргумент пришёл null, без ручных строк?
Обычно в проверках хочется написать “что именно было null”, но если делать это строками, они быстро устаревают после рефакторинга. В итоге кто-то переименовал переменную, а сообщение об ошибке осталось старым.
В C# можно сделать так, чтобы имя выражения подставлялось автоматически — через
Теперь при вызове:
если
И даже если передать выражение, оно тоже попадёт в текст:
🔥
➡️ C# Ready | #совет
Обычно в проверках хочется написать “что именно было null”, но если делать это строками, они быстро устаревают после рефакторинга. В итоге кто-то переименовал переменную, а сообщение об ошибке осталось старым.
В C# можно сделать так, чтобы имя выражения подставлялось автоматически — через
CallerArgumentExpression. Смотри на параметр:[CallerArgumentExpression("value")] string? expr = nullТеперь при вызове:
NotNull(user);
если
user окажется null, исключение будет ArgumentNullException("user") — без магических строк и без копипасты. И даже если передать выражение, оно тоже попадёт в текст:
NotNull(cache[key]);
CallerArgumentExpression — это “бесплатная диагностика”. Меньше ручных сообщений, лучше ошибки, и после переименований всё остаётся корректным автоматически.Please open Telegram to view this post
VIEW IN TELEGRAM
👍14🔥5❤3
❤19👍14🔥7😁2🤝1
В этой статье:
• Поймёшь, как устроен игровой цикл: Initialize → LoadContent → Update → Draw;
• Научишься загружать и рисовать текстуры (спрайты) и управлять позициями объектов;
• Разберёшь основы архитектуры 2D-игры на MonoGame и сделаешь первый рабочий прототип🔊 Продолжай читать на MonoGame
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11❤6🔥5
ArrayPool<T> в C#: снижаем нагрузку на GC в горячем коде!
Когда в каждом запросе создаётся новый
Обычно код выглядит так:
Если такая операция выполняется часто, лучше брать буфер из
Важно помнить, что пул может выдать массив больше запрошенного размера, поэтому работай только с нужным диапазоном данных. И всегда возвращай буфер в
🔥 В итоге ты заметно сокращаешь количество аллокаций и делаешь поведение сервиса ровнее под нагрузкой.
➡️ C# Ready | #практика
Когда в каждом запросе создаётся новый
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, иначе эффект от пула быстро пропадёт.Please open Telegram to view this post
VIEW IN TELEGRAM
👍12🔥5❤4
Например, HTTP/1.1 использует постоянные соединения, HTTP/2 умеет мультиплексировать запросы в одном TCP-канале, а HTTP/3 работает поверх QUIC и UDP.
На картинке — наглядная эволюция HTTP от первых версий до современных стандартов.
Сохрани, чтобы не забыть!
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥16❤9👍4
Зачем в библиотечном async-коде часто ставят `ConfigureAwait(false)`?
Потому что
Частая картина: внутри библиотеки есть
Правильнее — явно сказать: “мне не важно возвращаться в этот контекст”:
Так библиотечный код становится более предсказуемым. Он меньше зависит от того, откуда его вызвали. И он не навязывает окружению свои ожидания.
В приложении, где после
🔥 Меньше привязки к контексту, меньше неожиданностей, и код сразу говорит, что ему не нужен “возврат в UI”.
➡️ C# Ready | #совет
Потому что
await по умолчанию пытается “вернуться” в исходный контекст выполнения. В UI это может быть полезно. Но в библиотеке это обычно лишнее и иногда даже вредное.Частая картина: внутри библиотеки есть
await, а дальше никакого UI нет. Но метод всё равно тащит контекст вызывающего кода:await http.GetStringAsync("/data");Правильнее — явно сказать: “мне не важно возвращаться в этот контекст”:
await http.GetStringAsync("/data").ConfigureAwait(false);Так библиотечный код становится более предсказуемым. Он меньше зависит от того, откуда его вызвали. И он не навязывает окружению свои ожидания.
В приложении, где после
await ты обновляешь UI, ConfigureAwait(false) может быть неуместен. Это другое правило.Please open Telegram to view this post
VIEW IN TELEGRAM
👍15❤9🔥6
This media is not supported in your browser
VIEW IN TELEGRAM
На нём ты найдёшь roadmap из ~6 курсов: от основ C# и логики до Beginner DSA, а дальше — закрепление через сотни задач по DSA/алгоритмам (под интервью и контесты).
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10❤5🔥3
Когда логика и физика живут в правильных циклах, управление остается быстрым, а движение не ломается из-за разного FPS.
В этом гайде:
• Разбираем, почему смешивать физику и ввод в одном методе опасно;
• Показываем рабочую схему с Update и FixedUpdate без конфликтов;
• Объясняем, когда использовать Time.deltaTime и Time.fixedDeltaTime.
Примени этот подход в проекте, и поведение персонажа станет предсказуемым на любом устройстве.
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
2🤝24❤10🔥9👍3
В этой статье:
• Показаны цели фреймворка и базовые архитектурные решения.
• Разобраны ключевые возможности первой беты для реальных приложений.
• Объясняется, почему экосистема Avalonia стала заметной в .NET-мире.🔊 Продолжай читать на Habr!
Please open Telegram to view this post
VIEW IN TELEGRAM
❤12🤝4👍3
HttpClientFactory в ASP,NET Core: убираем таймауты и «умирающие» сокеты!
Частая проблема в сервисах такая: запросов становится больше, а внешнее API начинает отвечать дольше. В какой-то момент появляются случайные таймауты, хотя код «вроде простой».
Обычно это выглядит так:
Когда
В ASP.NET Core лучше один раз настроить клиент через
Сервис регистрируем отдельно, чтобы использовать настроенный клиент внутри бизнес-логики.
Теперь сам сервис. Через фабрику получаем именованный клиент и выполняем запрос.
Так соединения используются повторно, а поведение под нагрузкой становится заметно ровнее.
🔥 В итоге ты убираешь класс случайных сетевых сбоев и получаешь более предсказуемый прод.
➡️ C# Ready| #практика
Частая проблема в сервисах такая: запросов становится больше, а внешнее API начинает отвечать дольше. В какой-то момент появляются случайные таймауты, хотя код «вроде простой».
Обычно это выглядит так:
public async Task<string> LoadOrdersAsync(string url)
{
using var client = new HttpClient();
return await client.GetStringAsync(url);
}
Когда
HttpClient создаётся на каждый вызов, соединения не переиспользуются нормально. Под нагрузкой это бьёт по стабильности.В ASP.NET Core лучше один раз настроить клиент через
IHttpClientFactory и брать его из DI.using System.Net.Http;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpClient("orders", client =>
{
client.BaseAddress = new Uri("https://api.example.com/");
client.Timeout = TimeSpan.FromSeconds(5);
});
Сервис регистрируем отдельно, чтобы использовать настроенный клиент внутри бизнес-логики.
builder.Services.AddScoped<OrderService>();
var app = builder.Build();
app.Run();
Теперь сам сервис. Через фабрику получаем именованный клиент и выполняем запрос.
public sealed class OrderService
{
private readonly IHttpClientFactory _factory;
public OrderService(IHttpClientFactory factory)
{
_factory = factory;
}
public async Task<string> LoadOrdersAsync()
{
var client = _factory.CreateClient("orders");
return await client.GetStringAsync("orders/today");
}
}
Так соединения используются повторно, а поведение под нагрузкой становится заметно ровнее.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤12🔥6👍5