Библиотека шарписта | C#, F#, .NET, ASP.NET
Все самое полезное для C#-разработчика в одном канале. По рекламе: @proglib_adv Учиться у нас: https://proglib.io/w/b60af5a4 Для обратной связи: @proglibrary_feeedback_bot РКН: https://gosuslugi.ru/snet/67a5c81cdc130259d5b7fead
إظهار المزيد📈 نظرة تحليلية على قناة تيليجرام Библиотека шарписта | C#, F#, .NET, ASP.NET
تُعد قناة Библиотека шарписта | C#, F#, .NET, ASP.NET (@csharpproglib) في القطاع اللغوي الروسية لاعباً نشطاً. يضم المجتمع حالياً 21 866 مشتركاً، محتلاً المرتبة 6 209 في فئة التكنولوجيات والتطبيقات والمرتبة 30 824 في منطقة روسيا.
📊 مؤشرات الجمهور والحراك
منذ تأسيسه في невідомо، حقق المشروع نمواً سريعاً وجمع 21 866 مشتركاً.
بحسب آخر البيانات بتاريخ 11 يونيو, 2026، تحافظ القناة على نشاط مستقر. خلال آخر 30 يوماً تغيّر عدد الأعضاء بمقدار -95، وفي آخر 24 ساعة بمقدار -6، مع بقاء الوصول العام مرتفعاً.
- حالة التحقق: غير موثّقة
- معدل التفاعل (ER): يبلغ متوسط تفاعل الجمهور 12.48%. وخلال أول 24 ساعة من النشر يحصد المحتوى عادةً 7.13% من ردود الفعل نسبةً إلى إجمالي المشتركين.
- وصول المنشورات: يحصل كل منشور على متوسط 2 729 مشاهدة. وخلال اليوم الأول يجمع عادةً 1 560 مشاهدة.
- التفاعلات والاستجابة: يتفاعل الجمهور بانتظام؛ متوسط التفاعلات لكل منشور يبلغ 9.
- الاهتمامات الموضوعية: يركز المحتوى على مواضيع رئيسية مثل .net, шарписта, навигация, await, string.
📝 الوصف وسياسة المحتوى
يصف المؤلف القناة بأنها مساحة للتعبير عن الآراء الذاتية:
“Все самое полезное для C#-разработчика в одном канале.
По рекламе: @proglib_adv
Учиться у нас: https://proglib.io/w/b60af5a4
Для обратной связи: @proglibrary_feeedback_bot
РКН: https://gosuslugi.ru/snet/67a5c81cdc130259d5b7fead”
بفضل وتيرة التحديث المرتفعة (أحدث البيانات بتاريخ 12 يونيو, 2026) تحافظ القناة على حداثتها ومستوى وصول مرتفع. وتُظهر التحليلات تفاعلاً نشطاً من الجمهور، ما يجعلها نقطة تأثير مهمة ضمن فئة التكنولوجيات والتطبيقات.
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_люминатор
متاح الآن! بحث تيليغرام 2025 — أهم رؤى العام 
