Библиотека шарписта | C#, F#, .NET, ASP.NET
Все самое полезное для C#-разработчика в одном канале. По рекламе: @proglib_adv Учиться у нас: https://proglib.io/w/b60af5a4 Для обратной связи: @proglibrary_feeedback_bot РКН: https://gosuslugi.ru/snet/67a5c81cdc130259d5b7fead
Mostrar más📈 Análisis del canal de Telegram Библиотека шарписта | C#, F#, .NET, ASP.NET
El canal Библиотека шарписта | C#, F#, .NET, ASP.NET (@csharpproglib) en el segmento lingüístico de Ruso es un actor destacado. Actualmente la comunidad reúne a 21 866 suscriptores, ocupando la posición 6 209 en la categoría Tecnologías y Aplicaciones y el puesto 30 824 en la región Rusia.
📊 Métricas de audiencia y dinámica
Desde su creación el невідомо, el proyecto ha mostrado un crecimiento acelerado, reuniendo a 21 866 suscriptores.
Según los últimos datos del 11 junio, 2026, el canal mantiene una actividad estable. En los últimos 30 días la variación de miembros fue de -95, y en las últimas 24 horas de -6, conservando un alto alcance.
- Estado de verificación: No verificado
- Tasa de interacción (ER): El promedio de interacción de la audiencia es 12.48%. Durante las primeras 24 horas tras publicar, el contenido suele obtener 7.13% de reacciones respecto al total de suscriptores.
- Alcance de las publicaciones: Cada publicación recibe en promedio 2 729 visualizaciones. En el primer día suele acumular 1 560 visualizaciones.
- Reacciones e interacción: La audiencia responde de forma activa: el promedio de reacciones por publicación es 9.
- Intereses temáticos: El contenido se centra en temas clave como .net, шарписта, навигация, await, string.
📝 Descripción y política de contenido
El autor describe el recurso como un espacio para expresar opiniones subjetivas:
“Все самое полезное для C#-разработчика в одном канале.
По рекламе: @proglib_adv
Учиться у нас: https://proglib.io/w/b60af5a4
Для обратной связи: @proglibrary_feeedback_bot
РКН: https://gosuslugi.ru/snet/67a5c81cdc130259d5b7fead”
Gracias a la alta frecuencia de actualizaciones (últimos datos recibidos el 12 junio, 2026), el canal mantiene la vigencia y un amplio alcance. La analítica demuestra que la audiencia interactúa activamente con el contenido, lo que lo convierte en un punto de referencia dentro de la categoría Tecnologías y Aplicaciones.
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_люминатор
¡Ya disponible! Investigación de Telegram 2025 — los principales insights del año 
