Ваш код - прекрасный способ создания рекурсивного объекта. Компилятор выдает предупреждение, потому что он не может гарантировать, что ссылка не будет доступна до ее инициализации (что может вызвать ошибку времени выполнения). Однако, если вы знаете, что EventHandler
не вызывает предоставленную лямбда-функцию во время построения (это не так), вы можете спокойно проигнорировать предупреждение.
Чтобы привести пример, в котором предупреждение фактически указывает на проблему, вы можете попробовать следующий код:
type Evil(f) =
let n = f()
member x.N = n + 1
let rec e = Evil(fun () ->
printfn "%d" (e:Evil).N; 1)
Класс Evil
берет функцию в конструкторе и вызывает ее во время построения . В результате рекурсивная ссылка в лямбда-функции пытается получить доступ к e
до того, как ей будет присвоено значение (и вы получите ошибку времени выполнения). Однако, особенно при работе с обработчиками событий, это не проблема (и вы получаете предупреждение при правильном использовании рекурсивных объектов).
Если вы хотите избавиться от предупреждения, вы можете переписать код, используя явные значения ref
и null
, но тогда вы будете в той же опасности ошибки времени выполнения, просто без предупреждения и с более уродливым кодом:
let foo (evt:IEvent<_, _>) =
let eh = ref null
eh := new EventHandler(fun _ _ ->
evt.RemoveHandler(!eh) )
evt.AddHandler(!eh)