Передавайте Состояние. Продолжение
Начало
Начнём с нескольких простых случаев. Первый максимально прост - агрегирующая функция:
public static TAccumulate
Aggregate<TSource,TAccumulate>(
this IEnumerable<TSource> source,
TAccumulate seed,
Func<TAccumulate,TSource,TAccumulate> func);
Это метод расширения, который перебирает перечислимый объект. Он принимает контекст в виде параметра seed. У него есть функция, которая принимает контекст и элемент перечисляемого объекта. Тот факт, что он возвращает значение типа контекста, является особенностью агрегирующей функции. Это не имеет ничего общего с идеей передачи контекста. Использование:
var sumOfEven = numbers
.Aggregate(
0,
static (a, item) =>
a + (item % 2 == 0 ? 1 : 0));
Как видите, мы передали контекст и использовали статическую лямбда-функцию, чем избежали захвата контекста.
Следующий пример основан на методе, который принимает делегат и некоторое состояние. В данном случае мы рассматриваем одну из перегрузок AddOrUpdate из ConcurrentDictionary:
TValue AddOrUpdate<TArg>(TKey key,
Func<TKey,TArg,TValue> addValueFactory,
Func<TKey,TValue,TArg,TValue> updateValueFactory,
TArg factoryArgument);
ConcurrentDictionary — словарь, который может обрабатывать одновременный доступ нескольких потоков. Один из распространённых сценариев — добавление или обновление значения. Вот не самый удачный пример его использования (просто для демонстрации):
var counters =
new ConcurrentDictionary<string, long>();
counters.AddOrUpdate("tag",
static (_, v) => v, // задаём значение
static (_, prev, update) => prev + update, // обновляем
1); // начальное значение
Состояния такого счетчика:
1. Счётчик для конкретного ключа не существует и требуется его создать.
Нужен ключ и делегат для создания значения, который принимает ключ и контекст.
2. Счётчик для конкретного ключа существует и требуется его обновить.
Аналогично, но здесь потребуется ещё один параметр – предыдущее значение.
Синхронизация их выполнения остаётся на усмотрение реализации словаря. Вы можете быть уверены, что после завершения работы этого метода возвращаемое значение будет тем, которое было установлено одним из методов. Обратите внимание: благодаря использованию дополнительного параметра контекста можно использовать статические лямбда-функции! Захват контекста не требуется.
Окончание следует…
Источник: https://blog.scooletz.com/2025/10/08/pass-the-state