Recently I encountered a situation where having an asynchronous operation represented both as a Task<T>
and as an IObservable<T>
would be advantageous. The task representation maintains the state of the operation (IsCompleted
, IsFaulted
etc), while the observable representation enables the composition of multiple operations in interesting ways (Concat
, Merge
, Switch
etc), handling automatically the cancellation of any operation that has been unsubscribed along the way, solving this way the problem of fire-and-forgotten asynchronous operations. So I've become interested about ways to combine these two representations.
The easy, and probably correct, way to combine them would be through composition: creating a type that stores internally a Task<T>
and an IObservable<T>
, and exposes them as two of its properties. But in this question I am interested about the challenging, and probably impractical, possibility of a type that is a Task<T>
and is an IObservable<T>
at the same time. A type that can be passed directly to APIs that accept either tasks or observables, and do the right thing in either case. So it can't be just a task-like object. It must inherit from the real thing, the Task<T>
class itself. Something like this:
public class AsyncOperation<TResult> : Task<TResult>, IObservable<TResult>
{
public AsyncOperation(Func<CancellationToken, Task<TResult>> action)
{
//...
}
}
Creating an AsyncOperation
instance should invoke immediately the supplied action. In other words an AsyncOperation
should represent a hot task/observable combo.
Is it possible to create such a type?
Btw here is a thread in the ReactiveX/RxJava library that proves that others have thought about this problem before: No "isCompleted" or "isErrored" methods on Observable
Task<T>
doesn't look problematic (it's notsealed
), but maybe you can write what the problem is (preferable with a MCVE). – ScepterTask<T>
constructors create delegate tasks, while an asynchronous method creates a promise-style task. The constructors associated with promise-style tasks are private or internal. – SpoonbillIObservable<T>
interface, for example the return value of theObservable.StartAsync
method, do not inherit from theTask<T>
class. So I can't use the functionality of a task for an observable that represents a single asynchronous operation. And this functionality is needed in some scenarios. For example the execution flow may depend on whether the operation has completed successfully or not. – SpoonbillObservable.StartAsync
operator calls internally theTask.ToObservable
extension method, that returns a wrapped instance of an internalSlowTaskObservable
class. This class stores the underlying task created when theObservable.StartAsync
was invoked, but there is no way to get my hands on this task (except by using reflection tricks). My problem would be nonexistent if this task was accessible! – Spoonbill