Библиотека шарписта | 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 873 suscriptores, ocupando la posición 6 218 en la categoría Tecnologías y Aplicaciones y el puesto 30 852 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 873 suscriptores.
Según los últimos datos del 09 junio, 2026, el canal mantiene una actividad estable. En los últimos 30 días la variación de miembros fue de -88, y en las últimas 24 horas de -7, conservando un alto alcance.
- Estado de verificación: No verificado
- Tasa de interacción (ER): El promedio de interacción de la audiencia es 11.86%. Durante las primeras 24 horas tras publicar, el contenido suele obtener 7.09% de reacciones respecto al total de suscriptores.
- Alcance de las publicaciones: Cada publicación recibe en promedio 2 594 visualizaciones. En el primer día suele acumular 1 550 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 10 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.
find . -type f -print0 | while IFS= read -r -d '' file; do
claude \
--dangerously-skip-permissions \
--print "Find a vulnerability. hint: look at $file.
Write the most serious one to /out/report.txt."
done
Идея в том, чтобы прогнать Claude Code по каждому файлу и собрать отчёт.
Адаптация для C# на Windows:
Get-ChildItem -Path . -Recurse -Filter "*.cs" | ForEach-Object {
$file = $_.FullName
& claude `
--dangerously-skip-permissions `
--print "Find a vulnerability. hint: look at $file
Write the most serious one to report.txt"
}
На выходе список строк с предупреждениями. Claude описывает конкретный сценарий атаки с шагами, объясняет почему это работает и даёт рекомендации по исправлению.
Классический аудит стоит десятки тысяч евро и занимает месяцы. Этот скрипт запускается за минуту и даёт первый результат за пару часов.
➡️ Источник
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека шарписта
#sharp_viewVolatile решает проблему видимости, то Interlocked решает проблему атомарности. Операции реализованы на уровне процессора и выполняются как неделимые единицы — никакой другой поток не может вмешаться в середину
Самый частый сценарий это счётчик, который обновляют несколько потоков:
private int _counter;
public void Increment()
{
Interlocked.Increment(ref _counter);
}
Без Interlocked операция _counter++ на самом деле три шага: прочитать, прибавить, записать. Два потока могут выполнить их одновременно и затереть результат друг друга. Interlocked.Increment делает всё это за один неделимый шаг.
Lock-free генератор ID
Interlocked подходит для генерации уникальных идентификаторов без блокировок:
public int GetNextId()
{
return Interlocked.Increment(ref _id);
}
Каждый вызов гарантированно вернёт уникальное значение, даже если тысячи потоков вызывают метод одновременно.
CompareExchange: условное обновление
Самая мощная операция в арсенале Interlocked:
if (Interlocked.CompareExchange(ref _state, 1, 0) == 0)
{
// Успешно перешли из состояния 0 в 1
}
Логика простая: если текущее значение равно 0, заменить на 1 и вернуть старое значение. Если кто-то уже изменил _state, операция ничего не сделает. Это паттерн, на котором строятся lock-free кэши, планировщики и конкурентные очереди.
Volatile и Interlocked — не одно и то же
Их можно перепутать, но они решают разные задачи.
Volatile гарантирует, что поток видит актуальное значение переменной. Interlocked гарантирует, что сама операция выполняется безопасно, без вмешательства других потоков.
В реальных системах нередко нужны оба. Volatile чтобы читать свежие данные, Interlocked чтобы безопасно их менять.
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека шарписта
#sharp_viewdd - День с нулем ddd - Короткий день недели dddd - Полный день недели MM - Месяц с нулем MMM - Короткий месяц MMMM - Полный месяц yy - Год две цифры yyyy - Год четыре цифры HH - Часы 24 hh - Часы 12 mm - Минуты ss - Секунды fff - Миллисекунды tt - AM/PM zzz - Часовой поясПримеры в кодe:
var dt = new DateTime(2026, 4, 7, 17, 34, 12);
dt.ToString("yyyy-MM-dd") // 2026-04-07
dt.ToString("dd.MM.yyyy") // 07.04.2026
dt.ToString("HH:mm:ss") // 17:34:12
dt.ToString("dddd, dd MMMM") // вторник, 07 апреля
Для разбора строки используйте ParseExact или TryParseExact. Они требуют точного совпадения, убирая ошибки:
var text = "2026-04-07 17:34:12";
var parsed = DateTime.ParseExact(text, "yyyy-MM-dd HH:mm:ss", null);
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека шарписта
#sharp_viewVolatile.
Как это работает
Volatile.Read и Volatile.Write расставляют барьеры памяти в нужных местах:
• запись до Volatile.Write не может быть перенесена после неё
• чтение после Volatile.Read не может быть перенесено до него
На практике это значит: когда один поток устанавливает флаг, другие потоки рано или поздно увидят актуальное значение:
private int _flag;
public void Set()
{
Volatile.Write(ref _flag, 1);
}
public bool IsSet()
{
return Volatile.Read(ref _flag) == 1;
}
Это легче, чем lock
Volatile не захватывает монитор и не блокирует поток. Это просто барьер памяти. Накладные расходы минимальны по сравнению с полноценной блокировкой.
Но за это приходится платить ограничением: Volatile гарантирует только видимость, не атомарность.
Где это работает корректно
Типичный сценарий это флаг инициализации, который устанавливается один раз:
if (Volatile.Read(ref _initialized) == 0)
{
Initialize();
Volatile.Write(ref _initialized, 1);
}
Если этот код выполняется только в одном потоке, всё в порядке. Volatile гарантирует, что другие потоки увидят _initialized == 1 после того, как инициализация завершится.
Где это не работает
Если несколько потоков могут одновременно войти в этот блок, код становится небезопасным. Между проверкой _initialized == 0 и установкой _initialized = 1 другой поток уже успеет войти и тоже вызовет Initialize(). Здесь нужен Interlocked или полноценный lock.
Volatile подходит, когда один поток пишет, остальные читают. Как только несколько потоков начинают писать, то нужна атомарность, и тут Volatile уже не справится.
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека шарписта
#il_люминаторSingleton → может зависеть от → Singleton Scoped → может зависеть от → Singleton, Scoped Transient → может зависеть от → Singleton, Scoped, Transient📍 Навигация: Вакансии • Задачи • Собесы 🐸 Библиотека шарписта #sharp_view
TaskCompletionSource<T> решает одну конкретную проблему: вы хотите вернуть Task, но не можете использовать async/await, потому что результат приходит через коллбэк, событие или другой внешний сигнал.
Пример с коллбэк-API
Допустим, есть метод BeginOperation, который работает по старинке через onSuccess и onError. Оборачиваем его в нормальный Task:
public Task<string> GetDataAsync()
{
var tcs = new TaskCompletionSource<string>(
TaskCreationOptions.RunContinuationsAsynchronously);
BeginOperation(
onSuccess: result => tcs.SetResult(result),
onError: ex => tcs.SetException(ex));
return tcs.Task;
}
Теперь вызывающий код просто пишет await GetDataAsync() и не знает, что внутри коллбэки.
Почему важен RunContinuationsAsynchronously
Это не просто флаг для галочки. Без него продолжения выполняются прямо на том потоке, который вызвал SetResult. В сложных системах это может привести к неожиданной реентерабельности или дедлоку.
С флагом продолжения уходят в пул потоков и поведение становится предсказуемым.
Координация сигналов
Настоящая сила TaskCompletionSource проявляется, когда нужно синхронизировать несколько частей системы:
public Task WaitForSignalAsync()
{
return _signalTcs.Task;
}
public void Signal()
{
_signalTcs.TrySetResult();
}
Один компонент ждёт сигнала через await WaitForSignalAsync(), другой вызывает Signal() когда готов. Это базовый паттерн для кастомных async-локов, очередей и event-систем.
Когда использовать
Подходит, если нужно обернуть коллбэк-API в Task, реализовать собственный примитив синхронизации, или управлять завершением задачи вручную из внешнего кода. Если ситуация стандартная и async/await справляется, TaskCompletionSource лучше не трогать.
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека шарписта
#sharp_view# ядро dotnet add package Moongazing.Veil # HTTP middleware dotnet add package Moongazing.Veil.AspNetCore # structured logs dotnet add package Moongazing.Veil.SerilogСлой 1. Строки и объекты Авто-обнаружение типа данных: email, телефон, карта, IBAN, JWT, IP, API-ключ и маскировка без конфига:
Veil.Mask("john.doe@gmail.com");
// j******e@g****.com
Veil.Mask("5425123456789012");
// 5425 **** **** 9012
Veil.Mask("Bearer eyJhbGci...");
// Bearer eyJh***...
Для DTO атрибут [Veiled]:
public class CustomerDto
{
public string Name { get; set; }
[Veiled]
public string Email { get; set; }
[Veiled(Show = 4, Position = VeilPosition.Last)]
public string CardNumber { get; set; }
}
var masked = Veil.MaskObject(original); // original не трогается
Слой 2. HTTP-трафик:
app.UseVeilRedaction(); // middleware в pipeline
// конфиг:
http.RedactHeaders("Authorization", "X-Api-Key");
http.RedactBodyFields("$.password", "$.creditCard");
http.RedactQueryParams("token", "api_key");
Данные редактируются до того, как попадают в логи.
Слой 3. Serilog без изменений в коде:
Log.Logger = new LoggerConfiguration()
.Destructure.WithVeil()
.Enrich.WithVeilRedaction()
.WriteTo.Console()
.CreateLogger();
Все существующие Log.Information("User {@User}", user) начинают маскировать данные автоматически. Ни один вызов переписывать не нужно.
➡️ NuGet
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека шарписта
#async_newsdotnet add package Moongazing.Veil # ядро dotnet add package Moongazing.Veil.AspNetCore # HTTP middleware dotnet add package Moongazing.Veil.Serilog # structured logsСлой 1. Строки и объекты ➡️ 📍 Навигация: Вакансии • Задачи • Собесы 🐸 Библиотека шарписта #async_news
IMemoryCache для одного узла, либо Redis для распределённых сценариев. А если нужно и то, и другое одновременно, с нормальной устойчивостью к сбоям, то приходится писать обёртки самим.
FusionCache это гибридный кэш для .NET с открытым исходным кодом. Он работает как двухуровневый кэш: L1 в памяти и L2 в распределённом хранилище. Переключение между режимами прозрачно, поэтому код менять не нужно.
Минимальный пример без DI:
var cache = new FusionCache(new FusionCacheOptions());
var product = cache.GetOrSet<Product>(
$"product:{id}",
_ => GetProductFromDb(id),
TimeSpan.FromSeconds(30)
);
С DI и настройками устойчивости:
services.AddFusionCache()
.WithDefaultEntryOptions(new FusionCacheEntryOptions()
.SetDuration(TimeSpan.FromMinutes(2))
.SetPriority(CacheItemPriority.High)
.SetFailSafe(true, TimeSpan.FromHours(2))
.SetFactoryTimeouts(
TimeSpan.FromMilliseconds(100), // soft timeout
TimeSpan.FromSeconds(2) // hard timeout
)
);
Fail-safe здесь означает: если фабрика данных упала или превысила таймаут, кэш вернёт устаревшее значение вместо ошибки на срок до двух часов.
Три сценария, с которыми сталкиваются почти все
1. Cache Stampede. Когда ключ протухает, сотни одновременных запросов идут прямо в базу. FusionCache блокирует параллельные вычисления и делает один запрос вместо ста.
2. Медленная фабрика данных. Если база или внешний сервис тормозит, запросы накапливаются. FusionCache поддерживает soft и hard таймауты: при soft таймауте возвращается устаревшее значение (если оно есть), при hard таймауте бросается исключение, и вы сами решаете, что делать.
3. Согласованность в кластере. Если у вас несколько нод, их L1-кэши могут разойтись. Backplane, например, через Redis Pub/Sub, уведомляет все ноды об изменениях.
FusionCache также совместим с HybridCache от Microsoft и может использоваться как его реализация.
➡️ Репозиторий
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека шарписта
#sharp_viewpublic union OneOrMore<T>(T, IEnumerable<T>)
{
public IEnumerable<T> AsEnumerable() => Value switch
{
T single => [single],
IEnumerable<T> multiple => multiple,
null => []
};
}
Использование:
OneOrMore<string> tags = "dotnet";
OneOrMore<string> moreTags = new[] { "csharp", "unions", "preview" };
foreach (var tag in tags.AsEnumerable())
Console.Write($"[{tag}] ");
// [dotnet]
Поддержка UnionAttribute и IUnion в рантайме ещё не добавлена, поэтому в Preview 2 нужно вручную добавить в проект небольшой полифил:
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct,
AllowMultiple = false)]
public sealed class UnionAttribute : Attribute;
public interface IUnion
{
object? Value { get; }
}
}
После этого синтаксис union работает в полном объёме.
➡️ Блог разработчиков
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека шарписта
#il_люминаторUnion-тип объявляет закрытое множество допустимых типов. Компилятор знает полный список, поэтому проверяет исчерпываемость switch-выражений прямо при сборке.
Простейший пример:
public record class Cat(string Name);
public record class Dog(string Name);
public record class Bird(string Name);
public union Pet(Cat, Dog, Bird);
Переменная Pet хранит ровно один из трёх типов. Присваивание работает через неявное преобразование:
Pet pet = new Dog("Rex");
Console.WriteLine(pet.Value); // Dog { Name = Rex }
switch по такой переменной не требует ветки default или _. Если вы позже добавите четвёртый тип в объявление union, компилятор выдаст предупреждение в каждом месте, где не хватает обработчика.
string name = pet switch
{
Dog d => d.Name,
Cat c => c.Name,
Bird b => b.Name,
};
Фича доступна начиная с .NET 11 Preview 2.
➡️ Блог разработчиков
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека шарписта
#il_люминаторlabel.Text или textBox.Value, получаем InvalidOperationException. В WPF для этого используется Dispatcher.BeginInvoke, в WinForms — Control.Invoke или Control.BeginInvoke.
Казалось бы, очевидное правило. Но баг всё равно появляется: чаще всего тогда, когда разработчик делает Task.Run, внутри него обращается к UI, а анализатор это не видит.
С Dispatcher.Invoke другая история. Это синхронный вызов, он блокирует текущий поток до завершения. Если вызвать Invoke из самого UI-потока или из кода, который UI-поток уже ждёт, получаем дедлок. Правило простое: почти всегда нужен BeginInvoke (асинхронный), а не Invoke.
Как находить такие баги до прода
Статические анализаторы: Roslyn, AsyncFixer, Microsoft.VisualStudio.Threading.Analyzers и ThreadSafetyAnalyzer умеют находить прямые обращения к UI из неправильного потока, синхронные блокировки async-методов и потенциальные дедлоки в диспетчере.
Подключить их можно через NuGet:
dotnet add package Microsoft.VisualStudio.Threading.Analyzers dotnet add package AsyncFixerПосле подключения анализаторы начинают предупреждать прямо в IDE, до сборки. Часть правил даже предлагает автофикс. На практике это работает: после включения анализаторов в одном проекте удалось найти три гонки данных ещё до того, как они добрались до пользователей. 📍 Навигация: Вакансии • Задачи • Собесы 🐸 Библиотека шарписта #sharp_view
¡Ya disponible! Investigación de Telegram 2025 — los principales insights del año 
