0

Just confused about why the flow doesn't reach catch block. I do understand that whenever an exception has occured OnError method will be called, but shouldn't an exception occur when ToObservable is called? It is only when processing the third number(0), an exception occurs. I am totally confued.

        static void Main()
        {
            try
            {
                var numbers = from number in
                                  new int[] { 1, 2, 0, 3 }
                              select 10 / number;
                var observable = numbers.ToObservable();
                observable.Subscribe(OnNext, OnError, OnComplete);
                Console.ReadKey();
            }
            catch (Exception exc)
            {
                Console.WriteLine("Program terminated with the following message - {0}", exc.Message);
            }
        }

        private static void OnNext(int i)
        {
            Console.WriteLine("Output : " + i);
        }

        private static void OnError(Exception exc)
        {
            Console.WriteLine("In oops : {0}", exc.Message);
        }

        private static void OnComplete()
        {
            Console.WriteLine("In done");
        }
Sandbox
  • 7,910
  • 11
  • 53
  • 67

2 Answers2

3

Linq is evaluated lazily, this means nothing is evaluated until you call Subscribe(), this is why your catch block is not hit

thumbmunkeys
  • 20,606
  • 8
  • 62
  • 110
  • Yes, I understand the lazy evaluation of linq. But, when ToObservable is called it will try to convert the IEnumberable to IObservable, the divide by zero exception will occur. But, that isn't happening. Something wrong with my understanding of Linq and Rx I guess – Sandbox Feb 11 '12 at 12:41
  • @Sandbox: The `ToObservable` call itself doesn't try to *evaluate* the sequence, as far as I'm aware - it just create an observable which *remembers* the sequence reference, ready for evaluation when there's a subscriber. – Jon Skeet Feb 11 '12 at 13:38
  • Jon is right, just like nothing happens until you Foreach an array (and every Foreach is a new run through the array), ToObservable() creates an object that, when someone Subscribes to it, it will run through the array OnNext'ing each item. – Ana Betts Feb 11 '12 at 19:36
1

Throwing in a Selector is not the same as OnError'ing. Certain operators like Start will wrap your code in a try/catch and marshal to OnError, but most do not. Imagine if every LINQ Select was wrapped in a try/catch! It'd be quite slow. Same goes for your OnNext subscribe.

If you wanted to create a version of Select that did have this behavior, here's a way to do it:

public static IObservable<TRet> SafeSelect(this IObservable<T> This, Func<T,TRet> selector)
{
    return This.SelectMany(x => {
        try {
            return Observable.Return(selector(x));
        } catch (Exception ex) {
            return Observable.Throw<TRet>(ex);
        }
    });
}
Ana Betts
  • 73,868
  • 16
  • 141
  • 209