2

I have a observable made by the Using helper:

var o = Observable.Using(
 () => { 
          return new MyResource 
       },
 res => {
          return new Observable.Create<string>(observer => ....);
        });

How can I cancel the observable? And by that make sure MyResource is disposed of?

I see there are a Observable.Using( ) that includes a cancellationToken, but signature is so different, that I'm not able to make it work...

Update: As James points out, by disposing the observable, my resource will be disposed as well. In my case, a plain disposal is not enough. I need to call a method on the resource first. How can that be archived?

Vegar
  • 12,828
  • 16
  • 85
  • 151

1 Answers1

8

You don't need to clean up an observable - just the subscription. Simply call Dispose on the handle returned from Subscribe when you make a subscription to cancel it.

The resource created by the factory delegate supplied as the first argument to Using has a lifetime governed by lifetime of subscriptions to the observable created by Using.

Here's an example:

var xs = Observable.Using(
    () => {                        
        var resource =  Disposable.Create(() => Console.WriteLine("Binned"));
        Console.WriteLine("Created");
        return resource;
    },
    res => Observable.Never<Unit>());

Console.WriteLine("Subscribing");
var sub1 = xs.Subscribe();
var sub2 = xs.Subscribe();
Console.WriteLine("Disposing");            
sub1.Dispose();

Gives output:

Subscribing
Created
Created
Disposing
Binned

Since sub2 never finishes and isn't disposed, there is only a single Binned message displayed.

In this example, sub1 completes immediately and there is no cancellation:

var xs = Observable.Using(
    () => {                        
        var resource =  Disposable.Create(() => Console.WriteLine("Binned"));
        Console.WriteLine("Created");
        return resource;
    },
    res => Observable.Return(1));

Console.WriteLine("Subscribing");
var sub1 = xs.Subscribe();

This time the resource is still cleaned up, because the subscription terminated normally:

Subscribing
Created
Binned

The purpose of the overload of Using sporting cancellation tokens is to allow you to cancel asynchronous creation of the resource and the dependent observable. The cancellation tokens are signalled on disposal of subscription handles - of course this scenario is only really going to be useful if you have relatively lengthy creation times and early disposal is likely.

Addendum

To address the corollary to your question:

...a plain disposal is not enough. I need to call a method on the resource first. How can that be [achieved]?

From your resource factory method (the first argument to using), do this:

var xs = Observable.Using(
    () =>
    {                        
        var processHandle = /* code to create process */
        return Disposable.Create(() => /* code to kill process using processHandle */;
    },
    // Rest of code...

Disposable.Create is a helper method you can use that accepts in Action that's invoked upon disposal.

James World
  • 29,019
  • 9
  • 86
  • 120
  • ok. In my case, though, the resource is a running process, and I wan't to kill that process, so some how, some where, I need to add a call to `resource.Kill()`, or the process will continue run long after my application has evaporated. – Vegar Feb 03 '15 at 13:03
  • First of all: Thanks for trying to help me out here. I have to admit I have a hard time understanding these things. So.... Today I return a `Process` from the first parameter, which give me access to this process in the second parameter, where I can hook the std out of the process and turn that into a observable of string. By returning `Disposable.Create(() => ...)` - how can I still access the process in the second parameter? – Vegar Feb 03 '15 at 17:47
  • Sorry Vegar, I probably made the point badly - thinking that you just needed your process running rather than having access to it in the second factory. You probably want to create a class that encapsulates creating your process and provides access to it. Have it implement `IDisposable` and have its `Dispose` method do your clean up. Return a created instance of this class in the first factory (which thus creates the process). This instance will be passed as the argument of the second factory function, and its `Dispose` will ultimately be called by `Using` at the right time. – James World Feb 03 '15 at 18:25
  • No, I'm the one hiding details, believing them irrelevant. Encapsulating the process in a new disposable is what I just tried out. And It looks like it works pretty ok. I have another option as well. The running process will exit if gets signaled through StdIn (key-press), but I have problem with that approach as well. Watch out for yet another observable question :-) – Vegar Feb 03 '15 at 18:33
  • 1
    I ended up with the graceful shutdown through giving the process input. The help you gave me still deserve a green check mark, though :-) – Vegar Feb 10 '15 at 08:18