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

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

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

Все самое полезное для 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 873 مشترک است و جایگاه 6 218 را در دسته فناوری و برنامه‌ها و رتبه 30 852 را در منطقه روسيا دارد.

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

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

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

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

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

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

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

21 873
مشترکین
-724 ساعت
-187 روز
-8830 روز
آرشیو پست ها
🕸 Пять типичных ошибок при проектировании интеграции с помощью Kafka Система работала нормально, пока обработка батча не зан
🕸 Пять типичных ошибок при проектировании интеграции с помощью Kafka Система работала нормально, пока обработка батча не заняла слишком много времени. Координатор консьюмер-групп решил, что консьюмер мёртв, отверг коммит оффсета — и консьюмер начал читать сообщения заново. По кругу. Это называется ложная ребалансировка, и это один из самых неочевидных сценариев поломки. Архитектор Альфа-Банка разобрал пять таких историй из реального прода — с объяснением механики и тем, как этого избежать. ➡️ Читать статью 📍 Навигация: ВакансииЗадачиСобесы 🐸 Библиотека шарписта

⚙️ yield return не бесплатный Итераторы выглядят просто, но работают иначе:
IEnumerable<int> GetIds()
{
    foreach (var item in _items)
        yield return item.Id;
}
Читается как обычный цикл. Но компилятор превращает такой метод в конечный автомат со вспомогательными классами и состоянием. Именно поэтому итераторы такие выразительные — но и именно поэтому они не бесплатны. Где это становится проблемой На большинстве путей yield return это правильный выбор. Код чище, API удобнее, читаемость выше. Но на горячих путях, где метод вызывается тысячи раз в секунду, повторное создание объектов итератора и дополнительные слои абстракции начинают влиять на производительность. Не катастрофически, но измеримо. Что делать на критичных участках Если профилировщик показал, что итератор узкое место, есть несколько альтернатив. Заполнение буфера, переданного вызывающей стороной:
void FillIds(Span<int> buffer)
{
    for (int i = 0; i < _items.Count; i++)
        buffer[i] = _items[i].Id;
}
Возврат конкретной коллекции:
List<int> GetIds()
{
    var result = new List<int>(_items.Count);
    foreach (var item in _items)
        result.Add(item.Id);
    return result;
}
Прямой цикл внутри горячего кода без промежуточных перечислений:
for (int i = 0; i < _items.Count; i++)
    Process(_items[i].Id);
yield return стоит использовать тогда, когда он делает API лучше и код понятнее. Но не стоит считать его нулевым по стоимости. Если участок горячий, то сначала замерьте, потом решайте. 📍 Навигация: ВакансииЗадачиСобесы 🐸 Библиотека шарписта #il_люминатор

🔎 Удалённое комбо вакансий для шарпистов Подобрали три вакансии для тех, кто не хочет выходить из дома: .NET-разработчик C#/.NET-разработчик Senior Backend .NET Engineer ➡️ Еще больше топовых вакансий — в нашем канале C# Jobs 🐸 Библиотека шарписта

👨‍💻 Конфигурация везде это проблема Когда конфигурация разбросана по всему коду, проект становится хрупким. Строки вроде _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_люминатор