Библиотека шарписта | C#, F#, .NET, ASP.NET
Все самое полезное для C#-разработчика в одном канале. Наши курсы: https://clc.to/y3LDtw По рекламе: @proglib_adv Для обратной связи: @proglibrary_feeedback_bot РКН: https://gosuslugi.ru/snet/67a5c81cdc130259d5b7fead
Показати більше📈 Аналітичний огляд Telegram-каналу Библиотека шарписта | C#, F#, .NET, ASP.NET
Канал Библиотека шарписта | C#, F#, .NET, ASP.NET (@csharpproglib) у мовному сегменті Російська є активним учасником. На даний момент спільнота об'єднує 21 701 підписників, посідаючи 5 943 місце в категорії Технології та додатки та 30 267 місце у регіоні Росія.
📊 Показники аудиторії та динаміка
З моменту свого створення невідомо, проект продемонстрував стрімке зростання, зібравши аудиторію у 21 701 підписників.
За останніми даними від 29 серпня, 2026, канал демонструє стабільну активність. Хоча за останні 30 днів спостерігається зміна кількості учасників на -48, а за останні 24 години на -6, загальне охоплення залишається високим.
- Статус верифікації: Не верифікований
- Рівень залученості (ER): Середній показник залученості аудиторії становить 16.72%. Протягом перших 24 годин після публікації контент зазвичай збирає 7.84% реакцій від загальної кількості підписників.
- Охоплення публікацій: В середньому кожен допис отримує 3 628 переглядів. Протягом першої доби публікація в середньому набирає 1 702 переглядів.
- Реакції та взаємодія: Аудиторія активно підтримує контент: середня кількість реакцій на один пост – 23.
- Тематичні інтереси: Контент зосереджений навколо ключових тем, таких як .net, шарписта, навигация, await, string.
📝 Опис та контентна політика
Автор описує ресурс як майданчик для висловлення суб'єктивної думки:
“Все самое полезное для C#-разработчика в одном канале.
Наши курсы: https://clc.to/y3LDtw
По рекламе: @proglib_adv
Для обратной связи: @proglibrary_feeedback_bot
РКН: https://gosuslugi.ru/snet/67a5c81cdc130259d5b7fead”
Завдяки високій частоті оновлень (останні дані отримано 30 серпня, 2026), канал підтримує актуальність та високий рівень охоплення публікацій. Аналітика показує, що аудиторія активно взаємодіє з контентом, що робить його важливою точкою впливу в категорії Технології та додатки.
var text = WaffleEngine.Html(paragraphs: 2, includeHeading: true);
var text = WaffleEngine.Text(paragraphs: 1, includeHeading: true);
var markdown = WaffleEngine.Markdown(paragraphs: 1, includeHeading: true);
Поддерживает три формата: HTML, обычный текст и Markdown.
➡️ Попробовать либу
🐸Библиотека шарписта
#sharp_viewif (counts.ContainsKey(key))
counts[key]++;
else
counts[key] = 1;
Но есть способ проще:
counts[key] = counts.GetValueOrDefault(key) + 1;
Метод GetValueOrDefault возвращает значение, если ключ есть, или значение по умолчанию (для int это 0). Затем добавляем единицу. Никаких условных операторов, одна строка.
Если можете — используйте LINQ:
var counts = items.GroupBy(x => x.Key)
.ToDictionary(g => g.Key, g => g.Count());
Это явно показывает намерение: группируем по ключу, считаем количество в каждой группе.
Но если вы наполняете словарь в цикле или обрабатываете поток данных, GetValueOrDefault — идеальный выбор.
🐸Библиотека шарписта
#sharp_view<>c__DisplayClass2_0, d__5``1.MoveNext() и прочих артефактов, которые сгенерировал компилятор. Это не ошибка — это просто то, как .NET преобразует современный C# в IL. Но это делает поиск проблемы медленнее, чем нужно.
Demystifier восстанавливает оригинальный вид кода:
• Вместо ValueTuple``2 param показывает (string val, bool) param
• Вместо Func``1 показывает Func<string>
• async методы помечает как async Task<string>
• Локальные функции и лямбды показывает с контекстом
Как применить
Вызовите exception.Demystify() и передайте результат:
try { /* ваш код */ }
catch (Exception ex)
{
logger.LogError(ex.Demystify(), "Ошибка");
}
Анализ стека стоит ресурсов. На высоконагруженной системе вызывать Demystify для каждого исключения неэкономно. Используйте его выборочно — для критических путей, для отладки в development окружении или для редких, но важных ошибок.
➡️ Репозиторий либы
🐸Библиотека шарписта
#sharp_viewIActionResult без типов.
Проблема с IActionResult:
[HttpGet("{id:guid}")]
public async Task<IActionResult> GetById(Guid id, ISender mediator, CancellationToken ct)
{
var dto = await mediator.Send(new GetUserQuery(id), ct);
return dto is null ? NotFound() : Ok(dto);
}
Возвращаемый тип — IActionResult. Просто интерфейс. Ничего конкретного. Кто читает этот код, не знает, что именно вернётся. Может быть UserDto, может быть ошибка, может быть что угодно.
Вот так выглядит сгенерированная Swagger документация:
{
"responses": {
"200": { "description": "Success" }
}
}
Никакой информации о схеме. Кто использует ваш API, не знает, какие поля будут в ответе. IDE не может подсказать структуру. Тесты пишутся вслепую.
Решение: ActionResult<T>
[HttpGet("{id:guid}")]
public async Task<ActionResult<UserDto>> GetById(Guid id, ISender mediator, CancellationToken ct)
{
var dto = await mediator.Send(new GetUserQuery(id), ct);
return dto is null ? NotFound() : Ok(dto);
}
Возвращаемый тип — ActionResult<UserDto>. Конкретно и ясно. Читающий код понимает мгновенно: метод возвращает UserDto при успехе или ошибку. Swagger генератор видит типы и строит правильную документацию.
IActionResult можно использовать, когда метод не возвращает тело, к примеру ответ 204.
🐸Библиотека шарписта
#sharp_viewstatic с изменяемым состоянием. Удобно? Да. Безопасно? Совсем нет.
Почему static плохо сочетается с данными
Static — это ключевое слово, которое любят новички и используют для удобства. А потом из этого вырастают проблемы, которые отъедают часы отладки. Главная беда в том, что статические поля существуют всё время работы программы и доступны отовсюду.
Четыре золотых правила
1. Статические поля могут быть только для чтения. Лучше — константы.
2. Статические методы должны работать как математические функции: дали параметры — получили результат. Никаких побочных эффектов, никаких изменений состояния. Например: Select, Where, First из LINQ — это всё статические методы расширения, которые не трогают исходную последовательность.
3. Если в классе есть методы, которые не используют поля экземпляра, эту логику лучше вынести в отдельный статический класс-помощник. Это делает код чище, тесты проще.
4. Если вы создаёте статическое поле, пусть оно указывает на что-то, что не меняется. На объект конфигурации? Хорошо. На список данных, который вы потом модифицируете? Катастрофа.
Когда static — ваш друг
• Вспомогательные классы с чистыми функциями
Создайте статический класс StringUtils с методом static string ToPascalCase(string input). Нет состояния, нет побочных эффектов, нет проблем. Это хорошее использование.
• Методы расширения для преобразований
Select, Where и компания — статические методы расширения, которые берут данные, преобразуют их и возвращают новые. Функциональный подход, никакого волшебства.
• ThreadStatic для действительно отдельного состояния
Если каждому потоку нужно своё состояние, можно использовать ThreadStatic. Но даже здесь нужна осторожность — каждый поток всё равно должен управлять своим состоянием.
Передайте зависимость через конструктор, используйте DI-контейнер, создайте объект на сессию. Ваш будущий я, сидящий в отладчике в три утра, скажет вам спасибо.
🐸Библиотека шарписта
#il_люминаторdotnet --info, она покажет версии SDK и рантаймов и архитектуру хоста.
Сборка проекта выполняется командой dotnet build, по умолчанию в конфигурации Debug и с выводом артефактов в bin, причем команда учитывает инкрементальные изменения для скорости.
Запуск приложения через dotnet run объединяет сборку и старт процесса, что эквивалентно кнопке Run в IDE и удобно для ручных проверок локально.
Горячая перезагрузка из терминала через dotnet watch отслеживает изменения файлов и повторно запускает приложение с Hot Reload без ручного рестарта, что ускоряет цикл правка и проверка.
Если сборка ведет себя странно, стоит выполнить dotnet clean, чтобы удалить выходные артефакты и заставить следующий build собрать все заново.
Для развертывания используйте dotnet publish, который соберет релиз и положит готовый к деплою набор файлов в папку publish, включая веб приложения и сервисы.
🐸Библиотека шарписта
#sharp_view(int)Math.Sqrt(num) * (int)Math.Sqrt(num) == numНо на собесе после этого последует вопрос: «А можете без встроенной функции?» Вот тогда начинается интересное. Вместо математики используем логику: если x * x = num, то x находится где-то между 1 и num. Сужаем диапазон поиска, пока не найдём точный ответ.
public bool IsPerfectSquare(int num)
{
long left = 1;
long right = num;
while (left <= right)
{
long mid = (left + right) / 2;
long square = mid * mid;
if (square == num)
return true;
else if (square < num)
left = mid + 1;
else
right = mid - 1;
}
return false;
}
Есть ещё метод Ньютона для поиска корня — он даже быстрее для больших чисел:public bool IsPerfectSquare(int num)
{
long x = num;
while (x * x > num)
{
x = (x + num / x) / 2;
}
return x * x == num;
}
Главное: объясните почему вы выбрали именно этот подход, а не просто скопировали решение. На собесе вас оценивают не только по скорости, а по способности мыслить.
➡️ Попробовать решить
🐸Библиотека шарписта
#dotnet_challengepublic interface IBackgroundTaskQueue
{
ValueTask QueueAsync(Func<CancellationToken, Task> workItem);
ValueTask<Func<CancellationToken, Task>> DequeueAsync(CancellationToken cancellationToken);
}
public class BackgroundTaskQueue : IBackgroundTaskQueue
{
private readonly Channel<Func<CancellationToken, Task>> _queue;
public BackgroundTaskQueue(int capacity = 100)
{
var options = new BoundedChannelOptions(capacity)
{
SingleReader = false,
SingleWriter = false,
FullMode = BoundedChannelFullMode.Wait
};
_queue = Channel.CreateBounded<Func<CancellationToken, Task>>(options);
}
public async ValueTask QueueAsync(Func<CancellationToken, Task> workItem)
=> await _queue.Writer.WriteAsync(workItem);
public async ValueTask<Func<CancellationToken, Task>> DequeueAsync(CancellationToken cancellationToken)
=> await _queue.Reader.ReadAsync(cancellationToken);
}
Фоновые сервисы для обработки:
public class BackgroundWorker : BackgroundService
{
private readonly IBackgroundTaskQueue _taskQueue;
private readonly ILogger<BackgroundWorker> _logger;
public BackgroundWorker(IBackgroundTaskQueue taskQueue, ILogger<BackgroundWorker> logger)
{
_taskQueue = taskQueue;
_logger = logger;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
_logger.LogInformation("Фоновый worker запущен");
while (!stoppingToken.IsCancellationRequested)
{
var workItem = await _taskQueue.DequeueAsync(stoppingToken);
try
{
await workItem(stoppingToken);
}
catch (Exception ex)
{
_logger.LogError(ex, "Ошибка при выполнении задачи");
}
}
_logger.LogInformation("Worker останавливается...");
}
}
Использование в контроллере:
app.MapPost("/send-email", async (IBackgroundTaskQueue queue) =>
{
await queue.QueueAsync(async token =>
{
await Task.Delay(1000, token); // имитация отправки
Console.WriteLine($"Email отправлен в {DateTime.UtcNow}");
});
return Results.Accepted();
});
Запрос возвращается немедленно, а работа продолжается в фоне. Queue автоматически буферизирует задачи, управляет нагрузкой и применяет обратное давление, если очередь переполнится.
Когда использовать этот подход
Подходит:
• Внутренняя обработка задач в приложении
• Нет нужды в UI-панели мониторинга
• Self-contained сервисы
Возьмите библиотеку, если:
• Нужна распределённая обработка
• Требуется веб-интерфейс для управления
• Задачи должны пережить перезагрузку приложения
➡️ Источник
🐸 Библиотека шарписта
#sharp_view