fa
Feedback
Библиотека шарписта | C#, F#, .NET, ASP.NET

Библиотека шарписта | C#, F#, .NET, ASP.NET

رفتن به کانال در Telegram

Все самое полезное для C#-разработчика в одном канале. Наши курсы: https://clc.to/y3LDtw По рекламе: @proglib_adv Для обратной связи: @proglibrary_feeedback_bot РКН: https://gosuslugi.ru/snet/67a5c81cdc130259d5b7fead

نمایش بیشتر

📈 تحلیل کانال تلگرام Библиотека шарписта | C#, F#, .NET, ASP.NET

کانال Библиотека шарписта | C#, F#, .NET, ASP.NET (@csharpproglib) در بخش زبانی روسی بازیگری فعال است. در حال حاضر جامعه شامل 21 703 مشترک است و جایگاه 5 962 را در دسته فناوری و برنامه‌ها و رتبه 30 301 را در منطقه روسيا دارد.

📊 شاخص‌های مخاطب و پویایی

از زمان ایجاد در невідомо، پروژه رشد سریعی داشته و 21 703 مشترک جذب کرده است.

بر اساس آخرین داده‌ها در تاریخ 27 اوت, 2026، کانال فعالیت پایداری دارد. در ۳۰ روز گذشته تغییر اعضا برابر -42 و در ۲۴ ساعت گذشته برابر 3 بوده و همچنان دسترسی گسترده‌ای حفظ شده است.

  • وضعیت تأیید: تأیید نشده
  • نرخ تعامل (ER): میانگین تعامل مخاطب 15.91% است و در ۲۴ ساعت نخست پس از انتشار، محتوا معمولاً 7.92% واکنش نسبت به کل مشترکان کسب می‌کند.
  • دسترسی پست‌ها: هر پست به طور میانگین 3 454 بازدید دریافت می‌کند. در اولین روز معمولاً 1 718 بازدید جمع‌آوری می‌شود.
  • واکنش‌ها و تعامل: مخاطبان به‌طور فعال حمایت می‌کنند؛ میانگین واکنش به هر پست 26 است.
  • علایق موضوعی: محتوا بر موضوعات کلیدی مانند .net, шарписта, навигация, await, string تمرکز دارد.

📝 توضیح و سیاست محتوایی

نویسنده این فضا را محل بیان دیدگاه‌های شخصی توصیف می‌کند:
Все самое полезное для C#-разработчика в одном канале. Наши курсы: https://clc.to/y3LDtw По рекламе: @proglib_adv Для обратной связи: @proglibrary_feeedback_bot РКН: https://gosuslugi.ru/snet/67a5c81cdc130259d5b7fead

به لطف به‌روزرسانی‌های پرتکرار (آخرین داده در تاریخ 28 اوت, 2026)، کانال همواره به‌روز و دارای دسترسی بالاست. تحلیل‌ها نشان می‌دهد مخاطبان به‌طور فعال با محتوا تعامل دارند و آن را به نقطه اثرگذاری مهم در دسته فناوری و برنامه‌ها تبدیل کرده‌اند.

21 703
مشترکین
+324 ساعت
-137 روز
-4230 روز
آرشیو پست ها
👨‍💻 Конфигурация везде это проблема Когда конфигурация разбросана по всему коду, проект становится хрупким. Строки вроде _configuration["Stripe:ApiKey"] встречаются в контроллерах, сервисах, хелперах — и каждый раз с риском опечатки, без типизации, без валидации. Поменяли ключ в appsettings — ищете, где всё сломалось. Что не так с таким подходом Прямое обращение к IConfiguration через магические строки создаёт несколько реальных проблем. Нет единого места, где видно всю конфигурацию приложения. Парсинг типов (int.Parse, bool.Parse) повторяется в разных местах. Опечатка в ключе не вызовет ошибку компиляции — только падение в рантайме. Тестировать такой код неудобно:
// Так делать не стоит — магические строки, парсинг вручную
var apiKey = _configuration["Stripe:ApiKey"];
var timeout = int.Parse(_configuration["Timeout"] ?? "30");
Одна точка входа для конфигурации Решение: завести типизированные классы под каждую область конфигурации и привязать их один раз при старте приложения.
// Infrastructure/Configuration/ApplicationOptions.cs
public sealed class ApplicationOptions
{
    public PaymentOptions Payment { get; set; } = new();
    public DatabaseOptions Database { get; set; } = new();
    public CacheOptions Cache { get; set; } = new();
    public FeatureFlags Features { get; set; } = new();
}

public sealed class PaymentOptions
{
    public string StripeApiKey { get; set; } = string.Empty;
    public string StripeWebhookSecret { get; set; } = string.Empty;
    public int RetryAttempts { get; set; } = 3;
}
В Program.cs одна привязка для всего:
builder.Services.AddOptions<ApplicationOptions>()
    .Bind(builder.Configuration)
    .ValidateDataAnnotations()
    .ValidateOnStart();
ValidateOnStart выбрасывает исключение при запуске, если конфигурация невалидна. Не в рантайме, не при первом запросе — сразу при старте. Чистое внедрение через extension method Чтобы не засорять Program.cs, выносим регистрацию в extension method и сразу открываем под-опции для инжекции:
public static class OptionsExtensions
{
    public static IServiceCollection AddApplicationOptions(
        this IServiceCollection services,
        IConfiguration configuration)
    {
        services.AddOptions<ApplicationOptions>()
            .Bind(configuration)
            .ValidateDataAnnotations()
            .ValidateOnStart();

        services.AddSingleton(sp =>
            sp.GetRequiredService<IOptions<ApplicationOptions>>().Value.Payment);
        services.AddSingleton(sp =>
            sp.GetRequiredService<IOptions<ApplicationOptions>>().Value.Database);

        return services;
    }
}
Теперь в сервисах не нужна обёртка IOptions<T>. Инжектируем напрямую:
public class OrderService
{
    private readonly PaymentOptions _paymentOptions;
    private readonly DatabaseOptions _dbOptions;

    public OrderService(
        PaymentOptions paymentOptions,
        DatabaseOptions dbOptions)
    {
        _paymentOptions = paymentOptions;
        _dbOptions = dbOptions;
    }
}
В итоге конфигурация живёт в одном месте и имеет чёткую структуру. Все ключи типизированы и никаких магических строк. 📍 Навигация: ВакансииЗадачиСобесы 🐸 Библиотека шарписта #sharp_view

🤨 10 месяцев с Copilot Coding Agent в dotnet/runtime Microsoft опубликовали детальный разбор использования GitHub Copilot Co
🤨 10 месяцев с Copilot Coding Agent в dotnet/runtime Microsoft опубликовали детальный разбор использования GitHub Copilot Coding Agent в репозитории dotnet/runtime за последние 10 месяцев. Это один из самых сложных проектов в мире: основа .NET, 14 миллионов строк кода, миллионы активных разработчиков. Репозиторий использовали как полигон для эксперимента: может ли AI-агент полноценно участвовать в разработке такого масштаба? Общая картина: 878 PR за 10 месяцев С мая 2025 по март 2026 команда открыла 878 PR через CCA. Из них принято 535 (67.9%), закрыто 253, ещё 90 остаются открытыми. Для сравнения: PR от разработчиков Microsoft принимаются в 87.1% случаев, от сообщества — в 79.7%, от ботов вроде dependabot — в 85.9%. CCA уступает людям по этому показателю, но авторы подчёркивают: это разные задачи. Важный показатель качества — процент откатов. Из 535 принятых PR через CCA откатили 3 (0.6%). Среди остальных PR — 33 из 4251 (0.8%). Разница статистически незначима, но это говорит о том, что AI-код не хуже по качеству в плане регрессий. Главный урок: инструкции важнее модели До появления файла .github/copilot-instructions.md успешность выполнения задач была 38%. После — 69%. Это самый показательный факт во всей статье. Изначально CCA не мог скачать NuGet-пакеты, потому что firewall блокировал внешние ресурсы. Не знал, как собирать репозиторий. Не мог запустить тесты. Это было похоже на то, как взять нового разработчика и поставить ему задачу, не дав доступа ни к чему. Основные выводы авторов: думайте об агенте как о паре, а не замене; задачи с чётким описанием и понятным скоупом — лучшие кандидаты; ожидайте несколько итераций; следите за «ленивостью» агента, который делает минимум и не экстраполирует; каждый урок, вложенный в файл инструкций, окупается на всех следующих PR. ➡️ Блог разработчиков 📍 Навигация: ВакансииЗадачиСобесы 🐸 Библиотека шарписта #async_news

👨‍💻 Хватит мучить MongoDB через EF Core Вы выбрали MongoDB ради гибкости. А потом два часа потратили на то, чтобы EF Core позволил сделать элементарный фильтр. Поздравляем, вы сами себе враг. EF Core для MongoDB это иллюзия комфорта. Знакомый синтаксис, но в обмен на всё, ради чего вообще брали Mongo: агрегационные пайплайны, геозапросы, полнотекстовый поиск. Провайдер этого просто не умеет. Правильный путь — это MongoDB.Driver напрямую. Ставите пакет:
dotnet add package MongoDB.Driver
Делаете кастомный атрибут, чтобы сущность сама знала свою коллекцию:
[CollectionName("orders")]
public class Order
{
    [BsonId]
    [BsonRepresentation(BsonType.ObjectId)]
    public string Id { get; set; }
    public string CustomerName { get; set; }
}
Generic-репозиторий читает атрибут сам и никаких магических строк в Program.cs:
public class MongoRepository<T> : IMongoRepository<T>
{
    private readonly IMongoCollection<T> _collection;

    public MongoRepository(IMongoDatabase db)
    {
        var name = typeof(T)
            .GetCustomAttribute<CollectionNameAttribute>()?.Name
            ?? typeof(T).Name;
        _collection = db.GetCollection<T>(name);
    }
}
Регистрируете один раз через и больше никогда не трогаете Program.cs при добавлении новых коллекций:
services.AddScoped(typeof(IMongoRepository<>), typeof(MongoRepository<>));
Новая коллекция? Просто новый класс с [CollectionName]. А для сложных запросов Builders<T>:
var filter = Builders<Order>.Filter.Eq(o => o.Status, "pending");
var sort = Builders<Order>.Sort.Descending(o => o.CreatedAt);
var results = await _collection.Find(filter).Sort(sort).ToListAsync();
📍 Навигация: ВакансииЗадачиСобесы 🐸 Библиотека шарписта #sharp_view

⚡️ Прячем секреты и не ломаем тесты Одна из самых частых причин инцидентов на проде это конфиг, который не зависит от окружения. Кто-то закоммитил строку подключения к боевой базе, кто-то запустил тесты против продакшн-платёжки. Паттерн Options хорош сам по себе, но без правильной иерархии конфигов он не спасёт. .NET читает конфигурацию слоями. Каждый следующий слой перекрывает предыдущий. В Program.cs это выглядит так:
var builder = WebApplication.CreateBuilder(args);

builder.Configuration
    // 1. Базовые настройки — коммитим в репо, только безопасные дефолты
    .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)

    // 2. Настройки под окружение — Development.json коммитим, Production.json нет
    .AddJsonFile($"appsettings.{builder.Environment.EnvironmentName}.json",
        optional: true, reloadOnChange: true)

    // 3. User Secrets — только для разработки, никогда не коммитим
    .AddUserSecrets<Program>(optional: true)

    // 4. Переменные окружения — CI/CD, Docker, Kubernetes
    .AddEnvironmentVariables()

    // 5. Хранилище секретов — для прода
    .AddVaultSecrets(builder.Configuration);
Структура файлов:
├── appsettings.json                 # безопасные дефолты, коммитим
├── appsettings.Development.json     # локальные настройки, коммитим
├── appsettings.Production.json      # только структура без значений, коммитим
└── secrets.json                     # User Secrets, в .gitignore
В appsettings.Production.json пишем только заглушки, никаких реальных значений:
{
  "Database": {
    "ConnectionString": "CONFIGURED_IN_SECRETS_MANAGER"
  },
  "PaymentGateway": {
    "ApiKey": "CONFIGURED_IN_SECRETS_MANAGER"
  }
}
Можно спрятать секреты в GitLab CI, например:
# .gitlab-ci.yml
deploy_production:
  stage: deploy
  script:
    - dotnet publish -c Release
    - ./deploy.sh
  variables:
    Database__ConnectionString: $PROD_DB_CONNECTION
    PaymentGateway__ApiKey: $STRIPE_API_KEY
  only:
    - main
По итогу в репозитории будут только безопасные дефолтные значения, а все секреты вынесены. 📍 Навигация: ВакансииЗадачиСобесы 🐸 Библиотека шарписта #sharp_view

💡 Generative AI for Beginners .NET v2 Microsoft выпустила вторую версию бесплатного открытого курса «Generative AI for Begin
💡 Generative AI for Beginners .NET v2 Microsoft выпустила вторую версию бесплатного открытого курса «Generative AI for Beginners .NET». Это не обновление старого материала, а полностью новый курс с другой структурой и свежими примерами. Курс рассчитан на .NET-разработчиков, которые хотят разобраться в генеративном ИИ — от основ до работающих паттернов в продакшене. В первой версии основой был Semantic Kernel. В v2 его заменили на Microsoft.Extensions.AI (MEAI). MEAI входит в экосистему .NET 10, следует тем же принципам, что ILogger и IConfiguration, и не привязывает к конкретному оркестратору. ➡️ Репозиторий | Блог разработчиков 📍 Навигация: ВакансииЗадачиСобесы 🐸 Библиотека шарписта #async_news

⚡️ Утечка памяти, которую не видно до прода Channel<T> — это стандартный выбор для producer-consumer в .NET. Быстрее ConcurrentQueue, дружит с cancellation, не аллоцирует лишнего. Документация рекомендует. Коллеги используют. Дефолтный способ создать канал выглядит так:
var channel = Channel.CreateUnbounded<WorkItem>();
Канал принимает записи бесконечно. Никаких исключений, никаких предупреждений, никаких логов. Пока producer пишет быстрее, чем consumer успевает читать, очередь просто растёт в хипе. В разработке нагрузка маленькая, producer и consumer держат примерно одинаковый темп. На проде, при трафике чуть выше нормы, разрыв может быть огромным. Microsoft сделала такой дефолт намеренно: в некоторых сценариях потеря записи хуже, чем рост памяти. Логирование, например. Но для платёжных событий или команд это выбор, который стоит делать осознанно, а не получать по умолчанию. Переходим на CreateBounded и явно выбираем поведение при переполнении:
var channel = Channel.CreateBounded<WorkItem>(
    new BoundedChannelOptions(capacity: 500)
    {
        FullMode = BoundedChannelFullMode.Wait,
        SingleReader = true
        SingleWriter = false
    }
);
BoundedChannelFullMode это настоящее архитектурное решение. Четыре варианта с разным поведением по отношению к потере данных: Wait — блокирует producer до появления места DropNewest — выбрасывает только что записанное DropOldest — выбрасывает самое старое DropWrite — возвращает false на TryWrite Как считать capacity
capacity = пик записи в секунду × P99 время обработки в секундах  × 2
Пример: 500 записей в секунду, p99 обработки 200 мс:
capacity = 500 × 0.2 × 2 = 200
📍 Навигация: ВакансииЗадачиСобесы 🐸 Библиотека шарписта #il_люминатор

🧑‍💻 Пусть приложение падает при старте, а не в 2 часа ночи Представьте сценарий. Платёжный сервис ушёл в прод. Конфиг собран наспех, API-ключ не тот, URL без HTTPS. Всё тихо до первой реальной транзакции. Потом звонок в ночь, инцидент, откат. Паттерн Options с валидацией на старте решает именно эту проблему. Вместо того чтобы читать конфиг в рантайме и падать где попало, мы проверяем всё один раз при запуске. Если что-то не так, то приложение не поднимается вообще. Это лучше, чем ловить NPE или невалидный URL в середине бизнес-логики. Шаг первый. Описываем класс опций с атрибутами валидации:
public sealed class PaymentGatewayOptions
{
    [Required(ErrorMessage = "API Key is required - check your key")]
    [StringLength(100, MinimumLength = 20)]
    public string ApiKey { get; set; } = string.Empty;

    [Required]
    [Range(1, 10, ErrorMessage = "Retry count must be between 1 and 10")]
    public int MaxRetries { get; set; } = 3;

    [Required]
    [RegularExpression(@"^https://", ErrorMessage = "Base URL must use HTTPS")]
    public string BaseUrl { get; set; } = string.Empty;

    [Required]
    public TimeSpan Timeout { get; set; } = TimeSpan.FromSeconds(30);
}
Шаг второй. Регистрируем в Program.cs с вызовом ValidateOnStart():
builder.Services.AddOptions<PaymentGatewayOptions>()
    .BindConfiguration("PaymentGateway")
    .ValidateDataAnnotations()
    .ValidateOnStart(); // упадёт при старте, если конфиг невалиден
Шаг третий. Используем в сервисе через IOptions<T>:
public class PaymentService
{
    private readonly PaymentGatewayOptions _options;

    public PaymentService(IOptions<PaymentGatewayOptions> options)
    {
        _options = options.Value;
    }

    public async Task ProcessPaymentAsync(decimal amount)
    {
        using var client = new HttpClient
        {
            BaseAddress = new Uri(_options.BaseUrl),
            Timeout = _options.Timeout
        };

        client.DefaultRequestHeaders.Add("X-API-Key", _options.ApiKey);

        for (int i = 0; i < _options.MaxRetries; i++)
        {
            try { /* логика запроса */ }
            catch { if (i == _options.MaxRetries - 1) throw; }
        }
    }
}
Паттерн не новый, но cтоит использовать везде, где конфиг критичен для работы сервиса. 📍 Навигация: ВакансииЗадачиСобесы 🐸 Библиотека шарписта #sharp_view

❓ Насколько вы близки с F#
Anonymous voting

😈 Ручное тестирование мертво Металлург → Fullstack QA Engineer в Альфа-Банке. Звучит нереально, но именно такой путь описан
😈 Ручное тестирование мертво Металлург → Fullstack QA Engineer в Альфа-Банке. Звучит нереально, но именно такой путь описан в новой статье. Путь начался в 2021 с первого собеседования в IT без понимания, зачем нужен бэкенд. Финал: тестирование аналитических HTAP-систем, автотесты на Java и работа с Kafka-потоками. ➡️ В статье собрано 5 советов, что работает на рынке прямо сейчас 📍 Навигация: ВакансииЗадачиСобесы 🐸 Библиотека шарписта

🤨 Вопрос про стриминг на собесе Эндпоинт возвращает тысячи записей. Что происходит, если просто сделать return Ok(list)? Правильно — всё копится в памяти. Сервер ждёт, пока соберётся весь ответ, только потом отправляет клиенту. При высокой нагрузке это убивает и память, и растёт задержка. Возникает вопрос:
Как не держать весь ответ в памяти и какими инструментами воспользоваться?
Данные можно отдавать данные по мере готовности, без лишних аллокаций и с контролем над потоком. ➡️ Ответ в библиотеке собеса по C# 📍 Навигация: ВакансииЗадачиСобесы 🐸 Библиотека шарписта #dotnet_challenge

🤖 AI-агенты в .NET MAUI Контрибьют в .NET MAUI исторически требовал огромных затрат времени даже на простые баги: воспроизве
🤖 AI-агенты в .NET MAUI Контрибьют в .NET MAUI исторически требовал огромных затрат времени даже на простые баги: воспроизведение проблемы: 30–60 минут, поиск причины: 1–3 часа, реализация фикса ещё до двух часов, написание тестов ещё два. Итого 4–8 часов на один issue, и это у опытных разработчиков. Команда Syncfusion опубликовала разбор того, как они встроили кастомных AI-агентов в процесс разработки. Что построили Набор специализированных агентов и переиспользуемых навыков, которые покрывают полный цикл: pr-review skill — четырёхфазный процесс: анализ issue, проверка наличия тестов, до четырёх попыток фикса разными моделями, финальный отчёт с объяснением выбора лучшего подхода. write-tests-agent — анализирует issue и выбирает нужный тип тестов: UI-тесты через Appium или XAML-тесты. Обязательно проверяет, что тест падает без фикса и проходит с ним. sandbox-agent — ручная валидация в Sandbox-приложении. Для сценариев, которые трудно автоматизировать: визуальные баги, сложные жесты, поворот экрана. learn-from-pr agent — анализирует смёрженные PR и улучшает инструкции и документацию. Система становится умнее после каждого цикла. Для поиска фикса используются четыре модели последовательно — каждая предлагает независимый подход, тестирует его, записывает результат. После первого раунда модели видят чужие попытки и предлагают новые идеи. Одновременный доступ к одним файлам и одному устройству всё сломает. ➡️ Блог разработчиков 📍 Навигация: ВакансииЗадачиСобесы 🐸 Библиотека шарписта #пульс_индустрии

Почитали тут свежий отчёт по рынку ИИ-ускорителей в РФ: оказывается, 54% компаний тормозят внедрение ИИ исключительно из-за конских цен на инфраструктуру. Ну, то есть написать пет-проект с вызовом API это задача на вечер, а вот запустить агента в продакшн так, чтобы он не сжёг бюджет отдела за неделю — суровая инженерия. По сути, сейчас мало уметь собирать RAG. Нужно считать токены, настраивать time-travel дебаг в LangGraph и уметь роутить запросы на лету. Всё это мы учли в обновлённом курсе по разработке AI-агентов, где акцент сделан именно на AgentOps и жёсткий контроль ресурсов. Также в программе: — оценка качества, трейсинг и защита от деградации пайплайнов; — мультиагентные паттерны и интеграция по протоколу MCP; — локальный деплой Open Source под 152-ФЗ (когда данные нельзя выносить наружу). Кажется, это единственный адекватный roadmap по переходу от блокнотов к enterprise-решениям. Прямо сейчас можно урвать курс с увесистой скидкой (49 000 ₽ 62 990 ₽ за базовый тариф и 99 000 ₽ 124 990 ₽ за продвинутый трек), но стоит поторопиться — на потоке осталось всего 5 мест. 👉 Зафиксировать цену и начать собирать агентов, за которых не стыдно в проде

📎 ref vs out vs in C# передаёт параметры по значению — метод получает копию, оригинал не меняется. Иногда это не то, что нужно. ref — вы даёте, метод меняет, вы получаете обратно Переменная должна быть инициализирована до вызова. Метод может изменить её — а может и не изменить, это не обязательно:
void Add(ref int total, int value) => total += value;

int sum = 0;
Add(ref sum, 5); // sum == 5
Add(ref sum, 3); // sum == 8
out — метод обязан заполнить Переменную инициализировать не нужно. Но компилятор требует, чтобы метод присвоил значение до возврата, иначе ошибка компиляции. Именно поэтому весь паттерн Try* в стандартной библиотеке построен на out.
bool TryParse(string s, out int result)
in — только читать, не трогать Передаёт по ссылке — без копирования. Но запрещает запись. Нужен исключительно для производительности с большими структурами. С классами смысла нет — они и так передаются по ссылке.
float Dot(in Vector3 a, in Vector3 b) => ...
📍 Навигация: ВакансииЗадачиСобесы 🐸 Библиотека шарписта #sharp_view

🛠 Почему C# сравнивает списки по ссылке — и это правильно Многие удивляются: почему list1.Equals(list2) возвращает false, даже если содержимое одинаковое? Это не баг и не лень. Это осознанное решение. Причина 1: равенство коллекций неоднозначно [1, 2, 3] и [3, 2, 1] — равны? Зависит от задачи: — порядок важен → нет — порядок не важен → да — разные типы (List vs Stack) → может быть Нет одного правильного ответа, поэтому язык не навязывает ни один. Причина 2: производительность Равенство ссылок — O(1). Сравнение по содержимому — O(n) или O(n log n). В ранние годы C# строился на скорости. Причина 3: мутабельность всё ломает Допустим, вы сравнили два списка, получили true, сохранили флаг. Потом кто-то добавил элемент в один из них. Флаг стал false. равеноство на изменяемых объектах концептуально сломано. Как правильно Реализуйте IEqualityComparer<IEnumerable<T>> под свою задачу: — SequenceComparer — порядок важен — ContentComparer — порядок не важен Вы сами выбираете семантику. Язык не угадывает за вас. 📍 Навигация: ВакансииЗадачиСобесы 🐸 Библиотека шарписта #il_люминатор

👩‍💻 Открытый урок «Анатомия памяти: типы данных, способы хранения, аллокации и работа GC» 🗓 2 апреля в 20:00 МСК 🆓 Заняти
👩‍💻 Открытый урок «Анатомия памяти: типы данных, способы хранения, аллокации и работа GC» 🗓 2 апреля в 20:00 МСК 🆓 Занятие посвящено разбору данных вопросов. От понимания жизненного цикла переменной и того, как она хранится в памяти приложения, напрямую зависит его производительность и работоспособность. Мы обязательно разберем эти вопросы на нашем занятии. На открытом уроке рассмотрим: ✔️ Рассмотрим фрагменты памяти, из которых состоит память .net-приложения, поговорим о том какие бывают типы; ✔️ Узнаем что из себя представляют процессы упаковки и распаковки; ✔️ Посмотрим на нюансы работы с управляемой кучей; ✔️ Разберем принципы работы сборки мусора. 🔗 Ссылка на регистрацию: https://clc.to/0Bt0-Q Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576

⭐️ Швейцарский нож отказоустойчивости для .NET Polly — библиотека, которая позволяет описывать стратегии устойчивости: ретрай
⭐️ Швейцарский нож отказоустойчивости для .NET Polly — библиотека, которая позволяет описывать стратегии устойчивости: ретрай, circuit breaker, таймаут, rate limiter. Быстрый старт
dotnet add package Polly.Core
Всё строится через ResiliencePipelineBuilder — стратегии комбинируются цепочкой и применяются в порядке добавления:
ResiliencePipeline pipeline = new ResiliencePipelineBuilder()
    .AddRetry(new RetryStrategyOptions())
    .AddTimeout(TimeSpan.FromSeconds(10))
    .Build();

await pipeline.ExecuteAsync(async token => { /* ваша логика */ }, cancellationToken);
Реактивные стратегии Retry — повторные попытки при сбое:
new RetryStrategyOptions
{
    BackoffType = DelayBackoffType.Exponential,
    UseJitter = true,      // случайный разброс задержки
    MaxRetryAttempts = 4,
    Delay = TimeSpan.FromSeconds(3),
}
Circuit Breaker — разрывает связь при превышении порога ошибок:
new CircuitBreakerStrategyOptions
{
    FailureRatio = 0.5,                          
// 50% ошибок...
    SamplingDuration = TimeSpan.FromSeconds(10), 
// ...за 10 секунд
    MinimumThroughput = 8,                       
// при минимум 8 запросах
    BreakDuration = TimeSpan.FromSeconds(30),    
// разрываем на 30с
}
Fallback — возвращает запасное значение при сбое:
new FallbackStrategyOptions<UserAvatar>
{
    FallbackAction = static args => Outcome.FromResultAsValueTask(UserAvatar.Blank)
}
Проактивные стратегии Timeout — гарантирует, что ожидание не превысит лимит:
new ResiliencePipelineBuilder().AddTimeout(TimeSpan.FromSeconds(3));
// бросает TimeoutRejectedException при превышении
Rate Limiter — ограничивает интенсивность запросов:
// 100 запросов в минуту (скользящее окно)
.AddRateLimiter(new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions
{
    PermitLimit = 100,
    Window = TimeSpan.FromMinutes(1)
}));
Polly де-факто стандарт во многих командах. ➡️ Репозиторий 📍 Навигация: ВакансииЗадачиСобесы 🐸 Библиотека шарписта #sharp_view

👨‍💻 F#: `partitionWith` для разбивки коллекций на части с разными типами Стандартная partition делит коллекцию на две части, но обе остаются одного типа. Если нужно одновременно отфильтровать и преобразовать элементы — приходилось делать два прохода или писать свою функцию. partitionWith принимает функцию-разделитель с типом 'T -> Choice<'T1, 'T2> и возвращает два списка, которые могут иметь разные типы элементов:
val inline partitionWith:
    partitioner: ('T -> Choice<'T1, 'T2>) -> list: 'T list -> 'T1 list * 'T2 list
Удобно то, что total active pattern (|A|B|) уже имеет сигнатуру 'T -> Choice<'T1, 'T2>, поэтому его можно передать напрямую:
let (|Valid|Invalid|) (s: string) =
    match System.Int32.TryParse s with
    | true, n -> Valid n
    | _ -> Invalid s
 
let parsed, errors =
    ["42"; "hello"; "7"; "oops"; "99"]
    |> List.partitionWith (|Valid|Invalid|)
 
// parsed = [42; 7; 99]
// errors = ["hello"; "oops"]
За один проход получаем распарсенные числа и строки с ошибками — каждая в своём типе. Функция доступна для Array, List, Set и Array.Parallel. 📍 Навигация: ВакансииЗадачиСобесы 🐸 Библиотека шарписта #sharp_view