Библиотека шарписта | C#, F#, .NET, ASP.NET
22.6K subscribers
2.41K photos
39 videos
85 files
4.6K links
Все самое полезное для C#-разработчика в одном канале.

По рекламе: @proglib_adv

Учиться у нас: https://proglib.io/w/b60af5a4

Для обратной связи: @proglibrary_feeedback_bot

РКН: https://gosuslugi.ru/snet/67a5c81cdc130259d5b7fead
Download Telegram
⚙️ Почему async void ломает ваш код

В C# у async void есть дурная репутация, и не зря. Такой метод не возвращает Task, а значит, его нельзя await-ить, нельзя встроить в пайплайн и невозможно корректно отследить завершение.

Исключения из него не ловятся обычным образом — они пробиваются в синхронизационный контекст или в пул потоков, где легко превращаются в необработанные и могут уронить процесс.

// Контроллер ASP.NET Core
[HttpPost]
public async void Create() { await _svc.DoAsync(); } // Исключения мимо pipeline

// Библиотека
public async void SaveAsync(Item item) { await _repo.Save(item); } // Вызывающему не сконтролировать


Правильно — всегда возвращать Task:
[HttpPost]
public async Task<IActionResult> Create() { await _svc.DoAsync(); return Ok(); }

public Task Invoke(HttpContext ctx) => _next(ctx);

public Task SaveAsync(Item item) => _repo.Save(item);


Единственный сценарий, где async void уместен, — обработчики событий в UI-фреймворках вроде WPF или WinForms, где сигнатура задаётся самим фреймворком. Там приходится мириться, но даже там стоит ловить исключения локально и логировать их.

🐸Библиотека шарписта

#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
❤‍🔥88👍2
🔢 Когда числа становятся понятными

UnitsNet — .NET-библиотека, которая превращает голые числа в осмысленные физические величины.

Пример: вместо double speed = 27.8;
вы пишете Speed speed = Speed.FromMetersPerSecond(27.8);
и работаете уже с километрами в час, милями или узлами — без ручных пересчётов.

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

Ещё один плюс — читаемость кода. Ваши расчёты выглядят как документация: сразу видно, где давление, где скорость, а где длина.

➡️ Попробовать либу

🐸Библиотека шарписта

#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
32👍12🔥31
⏱️ Как ускорить асинхронный код в C#

Частая ошибка — писать асинхронные вызовы последовательно:
await GetUser();
await GetOrders();
await GetRecommendations();


Каждая операция ждёт предыдущую и если каждый запрос занимает по секунде, общее время = 3 секунды.

А можно иначе:
var userTask = GetUser();
var ordersTask = GetOrders();
var recsTask = GetRecommendations();

await Task.WhenAll(userTask, ordersTask, recsTask);


Все задачи стартуют сразу. Теперь общее время = 1 секунда (ожидание самой длинной операции).

Маленький приём — большая разница во времени выполнения.

🐸Библиотека шарписта

#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
👍39🥱911
👨‍💻 Каналы в .NET

Когда в приложении нужно обрабатывать поток данных от продюсеров к потребителям, первым делом вспоминают про очереди или ConcurrentQueue. Но в асинхронном мире этого мало. Поэтому в .NET есть каналы.

Канал устроен как пара из продюсера и потребителя. Когда продюсер пишет элемент в канал, он либо сразу уходит к потребителю, либо ждёт, если очередь переполнена. Потребитель, в свою очередь, может ждать новые элементы без блокировки потоков — всё работает на async/await.

Главная сила каналов — балансировка нагрузки.

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

Неограниченные каналы — вариант попроще, они всегда принимают новые элементы, но это может обернуться непредсказуемым ростом памяти.

Мини-пример:
var channel = Channel.CreateBounded<int>(5);

// producer
_ = Task.Run(async () =>
{
for (int i = 0; i < 10; i++)
{
await channel.Writer.WriteAsync(i);
Console.WriteLine($"Produced {i}");
}
channel.Writer.Complete();
});

// consumer
await foreach (var item in channel.Reader.ReadAllAsync())
{
Console.WriteLine($"Consumed {item}");
}


Почему это лучше, чем ConcurrentQueue? Потому что Channel создан сразу с учётом асинхронности. Вам не нужно городить блокировки и таймеры ожидания — достаточно написать await reader.ReadAsync(), и код будет сам по себе масштабироваться без блокировки потоков.

🐸Библиотека шарписта

#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
24👍11🤩4