Я не думаю, что вы сможете сделать то же самое с функцией блокировки, так как вы пытаетесь уступить изнутри. Сказав это, это выглядит как опасный подход на любом языке, поскольку это означает, что блокировка может удерживаться в течение произвольного промежутка времени (например, если один поток вызывает Enumerate()
, но не перечисляет весь путь до получающегося IEnumerable<_>
, тогда замок будет продолжать удерживаться).
Возможно, имеет смысл перевернуть логику, предоставив метод iter
в соответствии с:
let iter f =
if synchronize then
lock locker (fun () -> Seq.iter f dict)
else
Seq.iter f dict
Это возвращает итерацию обратно под ваш контроль, гарантируя, что последовательность полностью повторяется (при условии, что f
не блокирует, что в любом случае кажется необходимым предположением), и что блокировка снимается сразу после этого.
EDIT
Вот пример кода, который может навсегда удерживать блокировку.
let cached = enumerate() |> Seq.cache
let firstFive = Seq.take 5 cached |> Seq.toList
Мы взяли блокировку, чтобы начать перечисление первых 5 элементов. Однако, мы не продолжили в остальной части последовательности, поэтому блокировка не будет снята (возможно, мы перечислим остальную часть пути позже, основываясь на отзывах пользователей или что-то в этом случае, и в этом случае блокировка будет окончательно снята) .
В большинстве случаев правильно написанный код гарантирует, что он избавится от исходного перечислителя, но в общем случае это невозможно гарантировать. Следовательно, ваши выражения последовательности должны быть рассчитаны на то, чтобы быть перечисляемыми только частично. Если вы намереваетесь требовать, чтобы ваши вызывающие абоненты перечисляли коллекцию сразу, тогда лучше заставить их передать вам функцию, применяемую к каждому элементу, чем возвращать последовательность, которую они могут перечислить по своему усмотрению.