Библиотека шарписта | C#, F#, .NET, ASP.NET
Все самое полезное для C#-разработчика в одном канале. По рекламе: @proglib_adv Учиться у нас: https://proglib.io/w/b60af5a4 Для обратной связи: @proglibrary_feeedback_bot РКН: https://gosuslugi.ru/snet/67a5c81cdc130259d5b7fead
Show more📈 Analytical overview of Telegram channel Библиотека шарписта | C#, F#, .NET, ASP.NET
Channel Библиотека шарписта | C#, F#, .NET, ASP.NET (@csharpproglib) in the Russian language segment is an active participant. Currently, the community unites 21 866 subscribers, ranking 6 209 in the Technologies & Applications category and 30 824 in the Russia region.
📊 Audience metrics and dynamics
Since its creation on невідомо, the project has demonstrated rapid growth, gathering an audience of 21 866 subscribers.
According to the latest data from 11 June, 2026, the channel demonstrates stable activity. Although there has been a change in the number of participants by -95 over the last 30 days and by -6 over the last 24 hours, overall reach remains high.
- Verification status: Not verified
- Engagement rate (ER): The average audience engagement rate is 12.48%. Within the first 24 hours after publication, content typically collects 7.13% reactions from the total number of subscribers.
- Post reach: On average, each post receives 2 729 views. Within the first day, a publication typically gains 1 560 views.
- Reactions and interaction: The audience actively supports content: the average number of reactions per post is 9.
- Thematic interests: Content is focused on key topics such as .net, шарписта, навигация, await, string.
📝 Description and content policy
The author describes the resource as a platform for expressing subjective opinions:
“Все самое полезное для C#-разработчика в одном канале.
По рекламе: @proglib_adv
Учиться у нас: https://proglib.io/w/b60af5a4
Для обратной связи: @proglibrary_feeedback_bot
РКН: https://gosuslugi.ru/snet/67a5c81cdc130259d5b7fead”
Thanks to the high frequency of updates (latest data received on 12 June, 2026), the channel maintains relevance and a high level of publication reach. Analytics show that the audience actively interacts with content, making it an important point of influence in the Technologies & Applications category.
partial. Компилятор проверит согласованность.
Живой пример:
// Employee.Core.cs — базовая структура
public partial class Employee
{
public string Name { get; set; }
public decimal Salary { get; set; }
public partial void ValidateName();
public partial void ValidateSalary();
public void Hire()
{
ValidateName();
ValidateSalary();
Console.WriteLine($"{Name} нанят с зарплатой {Salary:C}!");
}
}
// Employee.Validation.cs — бизнес-правила
public partial class Employee
{
public partial void ValidateName()
{
if (string.IsNullOrWhiteSpace(Name) || Name.Length < 2)
throw new ArgumentException("Имя должно быть не короче 2 символов!");
}
public partial void ValidateSalary()
{
if (Salary < 50000) throw new ArgumentException("Зарплата не может быть ниже 50k!");
}
}
// Employee.Extensions.cs — расширения (опционально)
public partial class Employee
{
public void Promote() => Salary *= 1.2m;
}
Partial методы уникальны: если реализация отсутствует, метод полностью удаляется из IL. Идеально для опциональных хуков в генерируемом коде.
📍 Навигация: Вакансии • Задачи • Собесы
🐸Библиотека шарписта
#sharp_viewIQueryable<T> и IEnumerable<T> помимо синтаксиса?
Можете оставить свой ответ в комментариях и сравнить его с нашим.
👉 Посмотреть ответ в нашем канале с задачами
📍 Навигация: Вакансии • Задачи • Собесы
🐸Библиотека шарписта
#dotnet_challengeConditional, который полностью выкидывает вызовы метода из Release сборки.
Базовый пример:
[Conditional("DEBUG")]
public static void Trace(string message)
{
Console.WriteLine("[TRACE] " + message);
}
Это удобно для временного трассинга, сложных проверок и дорогих assert’ов, которые нужны только при разработке. Debug.Assert и Debug.WriteLine работают так же — они помечены [Conditional("DEBUG")], поэтому автоматически исчезают из релизной сборки.
📍 Навигация: Вакансии • Задачи • Собесы
🐸Библиотека шарписта
#il_люминаторpublic sealed record Paginated<T>(
IReadOnlyList<T> Items,
int Page,
int Size,
int Total
);
• Items то, что реально отображаем.
• Page номер текущей страницы.
• Size сколько элементов на странице.
• Total сколько записей всего под заданным фильтром.
Зачем DTO, а не сущность из EF
• EF сущность часто содержит поля, которые нельзя светить наружу (пароли, внутренние флаги, технические поля).
• DTO можно менять отдельно от внутренней модели база может жить своей жизнью, а API остаётся стабильным.
• EF Core умеет проецировать прямо в DTO через Select, не тянуть все поля сущности и не включать трекинг.
В итоге хендлер не выкидывает наружу сырые сущности, а отдаёт ровно то, что нужно клиенту.
Как выглядит запрос сверху
public sealed record SearchUsersQuery(
string? Q,
int Page = 1,
int Size = 20
) : IRequest<Paginated<UserSummary>>;
• Q — строка поиска.
• Page — номер страницы.
• Size — размер страницы.
Контроллер ничего не знает о базе и EF он просто пробрасывает запрос в Application слой:
[HttpGet]
public async Task<ActionResult<Paginated<UserSummary>>> Search(
[FromQuery] string? q,
[FromQuery] int page,
[FromQuery] int size,
ISender sender,
CancellationToken ct
)
{
var result = await sender.Send(new SearchUsersQuery(q, page, size), ct);
return Ok(result);
}
Что делает хендлер под капотом
public async Task<Paginated<UserSummary>> Handle(
SearchUsersQuery query,
CancellationToken ct)
{
var users = _db.Users.AsQueryable();
if (!string.IsNullOrWhiteSpace(query.Q))
{
var q = query.Q.Trim();
users = users.Where(u =>
u.Email.Contains(q) ||
u.Name.Contains(q));
}
var total = await users.CountAsync(ct);
var items = await users
.OrderBy(u => u.Email)
.Skip((query.Page - 1) * query.Size)
.Take(query.Size)
.AsNoTracking()
.Select(u => new UserSummary(
u.Id,
u.Email,
u.IsActive
))
.ToListAsync(ct);
return new Paginated<UserSummary>(
items,
query.Page,
query.Size,
total
);
}
• AsQueryable() чтобы можно было постепенно навешивать фильтры.
• Фильтрация по Q делается в базе, а не в памяти. Email и Name фильтруются прямо в SQL.
• CountAsync считает Total для уже отфильтрованного набора, без Skip/Take. Это количество строк, которые удовлетворяют фильтрам.
• Skip и Take делают пагинацию на стороне БД через OFFSET / FETCH или аналог, а не в памяти приложения.
• AsNoTracking() говорит EF Core не отслеживать сущности в change tracker, что ускоряет чистые запросы на чтение.
• Select сразу проецирует в UserSummary EF не создаёт полноценные сущности, не подгружает лишние поля и не собирает сложные графы.
Всё это превращается в один адекватный SQL запрос, а не в серию SELECT * плюс ручная фильтрация и подсчёты.
Паттерн пагинации это не про сложность, а наоборот про простоту и предсказуемость. Отдельные DTO, контейнер Paginated<T>, один явный запрос с фильтрами, подсчётом и AsNoTracking() дают API, которое не врёт клиенту, хорошо масштабируется и остаётся читабельным через год.
📍 Навигация: Вакансии • Задачи • Собесы
🐸Библиотека шарписта
#sharp_viewpublic sealed record Paginated<T>(
IReadOnlyList<T> Items,
int Page,
int Size,
int Total
);
Это контейнер для любого списка: пользователей, заказов или логов.
Items то, что реально отображаем.
Page номер текущей страницы.
Size сколько элементов на странице.
Total сколько записей всего под заданным фильтром.
📍 Навигация: Вакансии • Задачи • Собесы
🐸Библиотека шарписта
#sharp_viewDiagnosticSource и DiagnosticListener.
Смысл DiagnosticListener в том что вы можете из кода публиковать диагностические события, не навязывая никому ни конкретный логгер, ни конкретный APM.
Источник событий ничего не знает о подписчиках, а подписчики могут подключаться и отключаться динамически, не требуя изменений основной логики.
Простой пример:
public static class OrderDiagnostics
{
public static readonly DiagnosticListener Listener =
new("MyApp.Orders");
}
public async Task ProcessOrder(Order order)
{
if (OrderDiagnostics.Listener.IsEnabled("OrderProcessed"))
OrderDiagnostics.Listener.Write("OrderProcessed", new { order.Id });
// основная логика обработки
}
Если никто не подписан, проверка IsEnabled сразу вернет false и код почти ничего не стоит по времени. Как только появляется listener, он может наблюдать за событиями, строить трейс, метрики или слать данные в OpenTelemetry.
📍 Навигация: Вакансии • Задачи • Собесы
🐸Библиотека шарписта
#il_люминаторStopwatch.GetTimestamp и Stopwatch.GetElapsedTime.
Классический шаблон выглядит так:
long start = Stopwatch.GetTimestamp();
// код, который нужно измерить
await ProcessOrderAsync();
TimeSpan elapsed = Stopwatch.GetElapsedTime(start);
GetElapsedTime вычисляет разницу между текущим timestamp и сохранённым значением и возвращает TimeSpan без создания экземпляра Stopwatch. В результате нет лишней аллокации.
📍 Навигация: Вакансии • Задачи • Собесы
🐸Библиотека шарписта
#sharp_viewWaitAsync и finally и семафор навсегда занят поэтому все будущие вызовы повисают. Помогает только жесткое правило всегда оборачивать WaitAsync в try finally и не вставлять лишний код между ними особенно никакой логики которая может бросить исключение.
Вторая классика — блокировки внутри async кода. Варианты вроде _lock.Wait() или .Result внутри секции под SemaphoreSlim открывают прямую дорогу к дедлокам, потому что блокирующий вызов держит поток, а продолжение ждет этот же поток.
Общий принцип не блокировать внутри асинхронной критической секции если нужно синхронное API выносить его в Task.Run до входа в lock.
Поэтому в проде почти всегда лучше прятать SemaphoreSlim за абстракцией AsyncLock. Обертка с LockAsync() возвращающей IDisposable снимает часть рисков.
📍 Навигация: Вакансии • Задачи • Собесы
🐸Библиотека шарписта
#il_люминатор
Available now! Telegram Research 2025 — the year's key insights 
