Reputation: 5275
My code subscribes to an event and it needs to unsubscribe (Dispose
) once the event has been handled. However this looks like a chicken-egg problem. Using rec
doesn't work and I cannot find how to do it.
It there any well-konwn pattern to bypass this limitation?
let process = new Process()
let exitSubscription = process.Exited.Subscribe (
fun evntArg ->
exitSubscription.Dispose() <---------- Compiler complains here
// do more something here.
)
Upvotes: 1
Views: 112
Reputation: 80744
(you're saying in your question that rec
doesn't work, but do not clarify why or how; so I'm going to ignore that part for this answer)
One way to do this is to declare the value "recursive" with the rec
keyword. This will allow the value initialization code to reference the value itself - just like with a recursive function.
let rec exitSubscription : IDisposable = process.Exited.Subscribe (
fun evntArg ->
exitSubscription.Dispose()
// do more something here.
)
This will work, but will also produce a warning saying "this is a recursive value, and I can't tell if you're actually accessing it while it's being constructed, so you have to make sure that you don't, and if you do anyway, it'll be a runtime error".
Note that you also have to add a type signature to the variable, otherwise the compiler can't quite grok it and complains that it might not have a Dispose
method.
Another way is to make the variable mutable and then mutate it:
let mutable exitSubscription : IDisposable = null
exitSubscription <- process.Exited.Subscribe (
fun evntArg ->
exitSubscription.Dispose()
// do more something here.
)
Here you have to use a type signature too (for the same reason), and you have to initialize it with null
, because there is no such thing as an uninitialized variable.
Also, this is a tiny bit less safe, because the variable is mutable, and that's always a source of bugs. As long as you pinky-promise not to mutate it (beyond this initialization), you're ok.
But a "proper" way is to use an observable combinator to limit the observable to only one element. That way you don't have to unsubscribe explicitly, which is always more reliable:
#r "nuget: System.Reactive"
open System.Reactive.Linq
process.Exited.Take(1).Subscribe (
fun evntArg ->
// do more something here.
)
Upvotes: 3