Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How to unsubscribe an event from inside the event handler?

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.
     )

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

(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.
     )
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading