I have an observable MyObservable<Object>
which can throw CustomExceptions
where
private class CustomException : Exception
What I want to do is convert the CustomExceptions
into objects and emit those in a new observable.
This is my solution so far but I was wondering if this could be done without having to directly call the Subject's onNext, onCompleted or onError methods.
var MySubject = new Subject<NewObject>();
MyObservable.Catch<Object, CustomException>(
ex =>
{
NewObject o = new NewObject(ex.Message);
MySubject.OnNext(o);
return Observable.Empty<Object>();
});
IObservable<IList<NewObject>> listObservable = MySubject.ToList();
Edit: Thanks ibebbs! Worked like a charm!
You can catch and map exceptions without a subject by using the Materialize() function as shown here:
The
Materialize
function takes anIObservable<T>
and maps it to aIObservable<Notification<T>>
where each Notification has aKind
ofOnNext
,OnError
orOnComplete
. The above observable simply looks for Notifications with aKind`` of OnError and with the Exception being an instance of CustomException then projects these exceptions into an
IObservable```.Here is a unit test showing this working:
However, as you can see with the construed catch mechanisms employed above, exception handling in Rx can be tricky to get right and even more difficult to do elegantly. Instead, consider that Exceptions should be Exceptional and, if you expect an class of error such that you've written a custom exception for it, then the error is not really exceptional but part of a process flow that must handle these errors.
In this instance, I would recommend projecting the observable into a class which embodies the "try this operation and record the result, be it a value or an exception" and using this further along the execution chain.
In the example below, I use a "Fallible" class to capture the result or exception of an operation and then subscribe to a stream of "Fallible" instances, separating the errors from values. As you will see, the code is both neater and better performing as both the errors and values share a single subscription to the underlying source:
Hope it helps.