Библиотека шарписта | 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 212 in the Technologies & Applications category and 30 851 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 10 June, 2026, the channel demonstrates stable activity. Although there has been a change in the number of participants by -87 over the last 30 days and by -4 over the last 24 hours, overall reach remains high.
- Verification status: Not verified
- Engagement rate (ER): The average audience engagement rate is 12.06%. Within the first 24 hours after publication, content typically collects 7.04% reactions from the total number of subscribers.
- Post reach: On average, each post receives 2 638 views. Within the first day, a publication typically gains 1 540 views.
- Reactions and interaction: The audience actively supports content: the average number of reactions per post is 8.
- 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 11 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.
Where и Select сами по себе ленивые, они не выполняются пока не началось перечисление. Но как только появляется ToArray, начинается реальная работа и выделяется новый массив под результат
Если внутри цикла постоянно вызывается ToArray, то постоянно создаются новые массивы.
Если еще и лямбды захватывают переменные, добавляются лишние замыкания, и это тоже может стать частью мусора, который потом будет собирать GC.
Пример:
foreach (var batch in batches)
{
var validItems = batch
.Where(IsValid)
.Select(Transform)
.ToArray();
Process(validItems);
}
Ручной цикл выглядит скучнее, но дает контроль над буфером и позволяет переиспользовать память:
var buffer = new List<Result>(batch.Count);
foreach (var item in batch)
{
if (!IsValid(item))
continue;
buffer.Add(Transform(item));
}
Process(CollectionsMarshal.AsSpan(buffer));
buffer.Clear();
CollectionsMarshal.AsSpan дает доступ к внутреннему массиву List как Span, то есть можно передать данные дальше без копирования, но важно не менять List пока Span используется.
📍 Навигация: Вакансии • Задачи • Собесы
🐸Библиотека шарписта
#sharp_view Microsoft, это шанс занять нишу архитектора автономных систем.
Ваш план развития:
— понимание основ агентной логики и Reasoning;
— проектирование систем памяти и доступа к данным;
— создание мультиагентных пайплайнов для рабочих задач;
— интеграция агентов в бизнес-процессы компании.
Курс «Разработка ИИ-агентов» — это интенсивный путь от теории до создания сложных производственных систем.
Начать погружение в ИИ
До 19 января купите курс и заберите два дополнительных в подарок (акция «3 в 1»).IEnumerable.
Пример который встречается постоянно:
IEnumerable<Order> orders = GetOrders();
if (orders.Count() > 0)
{
// do something
}
Если внутри реально List или массив, то количество элементов доступно быстро через свойство Count или Length, то есть без прохода по данным.
Но Count() как LINQ метод обязан работать для любого IEnumerable, поэтому в общем случае он перечисляет элементы, пока не посчитает все.
Так проверка на пустоту внезапно становится полным обходом, и это особенно больно если orders это запрос с отложенным выполнением или поток данных.
А если хочется сохранить быстрый путь для коллекций, можно явно проверить интерфейс с Count:
if (orders is ICollection<Order> collection)
{
if (collection.Count > 0)
{
// fast path
}
}
else if (orders.Any())
{
// fallback
}
Если в профилировщике внезапно появился лишний проход по данным, стоит проверить где коллекция превратилась в IEnumerable и где после этого зовется Count().
📍 Навигация: Вакансии • Задачи • Собесы
🐸Библиотека шарписта
#sharp_viewusing IronPdf;
var renderer = new ChromePdfRenderer();
string html = @"
<html>
<body>
<img src='logo.png' style='width: 200px;' />
<p>Текст под картинкой</p>
</body>
</html>";
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("document_with_image.pdf");
Если картинка приходит из базы данных или веб-формы, удобнее встроить её прямо в HTML через Data URI:
byte[] imageBytes = File.ReadAllBytes("logo.png");
string base64 = Convert.ToBase64String(imageBytes);
string html = $@"
<html>
<body>
<img src='data:image/png;base64,{base64}' style='width: 200px;' />
<h2>Отчёт за декабрь</h2>
</body>
</html>";
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("report.pdf");
Если нужно добавить штамп или подпись на готовый документ, IronPdf позволяет работать со слоями:
var existingPdf = PdfDocument.FromFile("contract.pdf");
// Создаём HTML со штампом
string stampHtml = @"
<div style='position: absolute; bottom: 50px; right: 50px;'>
<img src='approved_stamp.png' style='width: 100px; opacity: 0.7;' />
</div>";
var stampPdf = renderer.RenderHtmlAsPdf(stampHtml);
// Накладываем на каждую страницу
foreach (var page in existingPdf.Pages)
{
page.AddBackgroundPdf(stampPdf);
}
existingPdf.SaveAs("contract_approved.pdf");
Частые ошибки
• Картинка не появляется — проверьте путь к файлу. IronPdf ищет относительно рабочей директории приложения. Используйте Path.GetFullPath() для отладки или встраивайте через Base64.
• Размытые изображения — убедитесь, что исходное разрешение картинки достаточное. Для печати нужно минимум 300 DPI. Если растягиваете маленькое изображение через width в CSS, оно будет мыльным.
• Огромный размер файла — IronPdf встраивает оригиналы. Оптимизируйте картинки заранее: сжимайте JPEG до 80-85% качества, для PNG используйте инструменты вроде TinyPNG.
📍 Навигация: Вакансии • Задачи • Собесы
🐸Библиотека шарписта
#sharp_viewGroupBy в LINQ удобный и выразительный, поэтому его часто тянут в любой код, где надо что то посчитать по ключу.
Проблема в том, что GroupBy решает задачу группировки, а агрегация это частный случай, и за него иногда приходится платить лишним.
Типичный паттерн выглядит так:
var totals = orders
.GroupBy(o => o.CustomerId)
.Select(g => new
{
CustomerId = g.Key,
Total = g.Sum(o => o.Amount)
})
.ToList();
Выглядит читабельно, но GroupBy внутри строит структуру групп, а значит элементы буферизуются и создаются объекты группировок, даже если в итоге нужен только итоговый Total.
Если нужна именно аккумуляция, проще и дешевле сделать один проход и складывать суммы в словарь:
var totals = new Dictionary<int, decimal>();
foreach (var order in orders)
{
if (totals.TryGetValue(order.CustomerId, out var current))
totals[order.CustomerId] = current + order.Amount;
else
totals[order.CustomerId] = order.Amount;
}
Это скучно, зато алгоритм читается буквально, один проход, явные обновления, без сюрпризов с материализацией групп.
📍 Навигация: Вакансии • Задачи • Собесы
🐸Библиотека шарписта
#sharp_viewAppWidgetProvider — следит за событиями виджета (создали, обновили, удалили)
RemoteViews — рисует интерфейс виджета
BroadcastReceiver — ловит клики и другие действия пользователя
Вы создаёте класс на C#, прописываете его в манифесте Android, рисуете layout в XML. Стандартная Android-разработка, просто на C#.
➡️ Блог Microsoft
📍 Навигация: Вакансии • Задачи • Собесы
🐸Библиотека шарписта
#il_люминаторvar youngest = people
.OrderBy(p => p.Age)
.First();
На вид код нормальный, но по факту он платит за сортировку, хотя нужна всего одна крайняя точка.
Правильнее выразить намерение напрямую через MinBy:
var youngest = people.MinBy(p => p.Age);
MinBy возвращает элемент с минимальным ключом и не требует полной сортировки последовательности. Если в коде встречается OrderBy().First() или OrderByDescending().First(), это повод остановиться и проверить, не ищется ли просто минимум или максимум.
📍 Навигация: Вакансии • Задачи • Собесы
🐸Библиотека шарписта
#sharp_viewdotnet new gitignore делает все за вас. В ней уже прописаны все типичные исключения: каталоги bin/, obj/, кэш NuGet, файлы публикаций, временные артефакты IDE и прочие служебные данные, которые не должны попадать в репозиторий.
Не нужно искать шаблон на GitHub или копировать его вручную — всё доступно из коробки.
📍 Навигация: Вакансии • Задачи • Собесы
🐸Библиотека шарписта
#лучшее_из_библиотеки_2025var collection = new BlockingCollection<int>();
// Поток-поставщик (Producer)
Task.Run(() =>
{
for (int i = 0; i < 10; i++)
{
collection.Add(i);
Console.WriteLine($"Производитель: добавил {i}");
Thread.Sleep(500);
}
collection.CompleteAdding();
});
// Поток-потребитель (Consumer)
Task.Run(() =>
{
foreach (var item in collection.GetConsumingEnumerable())
{
Console.WriteLine($"Потребитель: получил {item}");
}
}).Wait();
2️⃣ Использование TaskCompletionSource<T>
Когда нужно передать значение между потоками в будущем.
var tcs = new TaskCompletionSource<int>();
// Поток-поставщик
Task.Run(() =>
{
Thread.Sleep(2000);
tcs.SetResult(42);
});
// Поток-потребитель
int result = await tcs.Task;
Console.WriteLine($"Получено: {result}");
3️⃣ Использование ConcurrentQueue<T>
Если нужно неблокирующее хранилище данных.
var queue = new ConcurrentQueue<int>();
// Поток-поставщик
Task.Run(() =>
{
for (int i = 0; i < 10; i++)
{
queue.Enqueue(i);
Console.WriteLine($"Добавлено {i}");
Thread.Sleep(500);
}
});
// Поток-потребитель
Task.Run(() =>
{
while (true)
{
if (queue.TryDequeue(out int item))
{
Console.WriteLine($"Получено {item}");
}
Thread.Sleep(100);
}
}).Wait();
4️⃣ Использование Channel<T> (System.Threading.Channels)
Альтернативный подход к BlockingCollection<T>
var channel = Channel.CreateUnbounded<int>();
// Поток-поставщик
_ = Task.Run(async () =>
{
for (int i = 0; i < 10; i++)
{
await channel.Writer.WriteAsync(i);
Console.WriteLine($"Производитель: {i}");
await Task.Delay(500);
}
channel.Writer.Complete();
});
// Поток-потребитель
await foreach (var item in channel.Reader.ReadAllAsync())
{
Console.WriteLine($"Потребитель: {item}");
}
💬 Какой вариант используете в проде?
📍 Навигация: Вакансии • Задачи • Собесы
🐸Библиотека шарписта
#лучшее_из_библиотеки_2025Thread из пространства имен System.Threading. Поток проходит несколько этапов на протяжении своего жизненного цикла. Давайте разберём эти этапы.
— Unstarted. Не запущен
Поток создан, но ещё не запущен. Он находится в этом состоянии сразу после инициализации объекта Thread, но до вызова метода Start().
Thread thread = new Thread(MyMethod);
// Поток создан, но не запущен
— Running. Выполняется
Поток начинает выполнение после вызова Start(). В этом состоянии поток выполняет код, переданный в качестве делегата.
thread.Start();
// Поток запущен и выполняется
— Waiting. Ожидание
Поток приостанавливается, ожидая выполнения какого-либо условия или ресурса. Это может быть вызвано методами:
• Thread.Sleep() — поток засыпает на заданное время.
• Monitor.Wait() или lock — поток ожидает захвата монитора.
• Thread.Join() — поток ожидает завершения другого потока.
Thread.Sleep(1000);
// Поток приостановлен на 1 секунду
— Blocked. Заблокирован
Поток заблокирован, пытаясь получить доступ к ресурсу, уже занятому другим потоком. Например, ожидание захвата блокировки через lock.
— Stopped. Остановлен
Поток завершает выполнение. Это состояние наступает, когда метод, выполняемый в потоке, завершает работу или вызывается устаревший метод Abort(). Поток в этом состоянии больше нельзя запустить снова.
thread.Join();
// Основной поток ожидает завершения
Дополнительные состояния
— Background. Фоновый поток
Поток может быть фоновым, если свойство IsBackground установлено в true. Фоновые потоки завершаются автоматически, когда завершается основной поток приложения.
thread.IsBackground = true;
// Устанавливаем поток как фоновый
— Suspended. Приостановлен (устарело)
Метод Suspend() приостанавливал выполнение потока, но был удалён из новых версий .NET из-за возможных проблем с безопасностью.
📍 Навигация: Вакансии • Задачи • Собесы
🐸Библиотека шарписта
#лучшее_из_библиотеки_2025docker run -d --hostname my-rabbit --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:management
2️⃣ Настраиваем MassTransit
Необходимо зарегистрировать MassTransit и подключить его к RabbitMQ:
builder.Services.AddMassTransit(x =>
{
x.UsingRabbitMq((context, cfg) =>
{
cfg.Host("localhost", "/", h =>
{
h.Username("guest");
h.Password("guest");
});
});
});
Этот код создает подключение к RabbitMQ, которое позволяет сервису отправлять и получать сообщения.
3️⃣ Создаем производителя
Производитель отправляет сообщения в очередь, используя MassTransit:
public async Task SendMessage(IBus bus, string message)
{
var endpoint = await bus.GetSendEndpoint(new Uri("queue:order-queue"));
await endpoint.Send(new OrderCreated { OrderId = Guid.NewGuid(), Message = message });
}
4️⃣ Создаем потребителя
Потребитель автоматически получает и обрабатывает сообщения из очереди:
public class OrderConsumer : IConsumer<OrderCreated>
{
public Task Consume(ConsumeContext<OrderCreated> context)
{
Console.WriteLine($"Получено сообщение: {context.Message.Message}");
return Task.CompletedTask;
}
}
💾 Сохраняйте мини-гайд себе, чтобы не потерять
📍 Навигация: Вакансии • Задачи • Собесы
🐸Библиотека шарписта
#лучшее_из_библиотеки_2025await несколько раз для одного и того же ValueTask нельзя, так как это может привести к неожиданным результатам:
ValueTask<int> task = GetValueAsync();
int value1 = await task;
int value2 = await task; // Ошибка
• Конвертация в Task
Eсли требуется передать ValueTask в API, которое ожидает Task, можно вызвать метод .AsTask():
Task<int> task = GetValueAsync().AsTask();
• Когда использовать ValueTask:
+ Операция часто завершается синхронно.
+ Создание объекта Task может быть слишком накладным.
+ Вы пишете библиотеку с высокой производительностью.
• Когда НЕ использовать ValueTask:
- Операция всегда асинхронна.
- Производительность не является критически важной.
- Приложение не оптимизировано под работу с ValueTask.
📍 Навигация: Вакансии • Задачи • Собесы
🐸Библиотека шарписта
#лучшее_из_библиотеки_2025
Available now! Telegram Research 2025 — the year's key insights 
