开发者

How to get an exception from a task when the task generates events

I have the following scenario. A Task that generates events and might throw an exception:

public event EventHandler<EventArgs> MyEvent;
new Task(() =>
    {
        while (condition)
        {
            // Generate standard .NET event.
            MyEvent(this, new EventArgs());

            // Maybe throw exception.
            if (somethingIsWrong) throw new Exception();
        }
    });

All pretty straightforward. I listen to the events using Observable.FromEvent:

var events =
    Observable.FromEvent<EventArgs>(开发者_StackOverflow中文版h => myClass.MyEvent += h,
                                    h => myClass.MyEvent -= h);
events.Subscribe(
    ev => DoSomethingOnNext(ev),
    ex => DoSomethingOnError(ex),
    () => DoSomethingOnCompleted());

This all works fine when no exception occurs. When an exception is thrown by the task, however, I'd like to know this in my observable. The exception is now 'hidden' inside the task.

Can I only do this by creating another event when the exception takes place, wrapping it inside an IObservable and subscribing to this new observable? Or is there a simpler way?


How about this:

class Program
{
    public event EventHandler<EventArgs> MyEvent;
    static void Main(string[] args)
    {
        var myClass = new Program();            

        var task = new Task(() =>
        {
            for(var i=0; i<5; i++) {
                // Generate standard .NET event. 
                myClass.MyEvent(myClass, new EventArgs());
            }

            throw new Exception();
        });

        var obsTask = task.ToObservable();

        var events = Observable.FromEvent<EventArgs>(h => myClass.MyEvent += h, h => myClass.MyEvent -= h);            

        events.TakeUntil(obsTask).Subscribe(
            ev => DoSomethingOnNext(ev), 
            ex => DoSomethingOnError(ex),
            () => DoSomethingOnCompleted());

        task.Start();

        Console.ReadKey();
    }

    private static void DoSomethingOnCompleted()
    {
        Console.WriteLine("DoSomethingOnCompleted");
    }

    private static void DoSomethingOnError(Exception ex)
    {
        Console.WriteLine("DoSomethingOnError:" + ex.ToString());
    }

    private static void DoSomethingOnNext(IEvent<EventArgs> ev)
    {
        Console.WriteLine("DoSomethingOnNext:" + ev.ToString());
    }

The output is:

DoSomethingOnNext:System.Collections.Generic.Event1[System.EventArgs] DoSomethingOnNext:System.Collections.Generic.Event1[System.EventArgs] DoSomethingOnNext:System.Collections.Generic.Event1[System.EventArgs] DoSomethingOnNext:System.Collections.Generic.Event1[System.EventArgs] DoSomethingOnNext:System.Collections.Generic.Event`1[System.EventArgs] DoSomethingOnError:System.AggregateException: One or more errors occurred. ---> System.Exception: Exception of type 'System.Exception' was thrown. at RxDisposeTests.Program.<>c_DisplayClass9.b_0() in C:\Users\Richard.Hein\Documents\Visual Studio 2010\Projects\RxConsole\RxDisposeTests\Program.cs:line 25 at System.Threading.Tasks.Task.InnerInvoke() at System.Threading.Tasks.Task.Execute() --- End of inner exception stack trace --- ---> (Inner Exception #0) System.Exception: Exception of type 'System.Exception' was thrown. at RxDisposeTests.Program.<>c_DisplayClass9.b_0() in C:\Users\Richard.Hein\Documents\Visual Studio 2010\Projects\RxConsole\RxDisposeTests\Program.cs:line 25 at System.Threading.Tasks.Task.InnerInvoke() at System.Threading.Tasks.Task.Execute()<---

EDIT:

Not sure if TakeUntil is a good solution, because Task might return something other than Exceptions, right? So this could work:

var events = Observable.CreateWithDisposable<IEvent<EventArgs>>(observer =>
{
    var eventObs = Observable.FromEvent<EventArgs>(
        h => myClass.MyEvent += h, h => myClass.MyEvent -= h);
    task.ToObservable().Subscribe(_ => { }, observer.OnError, observer.OnCompleted);
    return eventObs.Subscribe(observer.OnNext, observer.OnError, observer.OnCompleted);
});

events.Subscribe(
    ev => DoSomethingOnNext(ev), 
    ex => DoSomethingOnError(ex),
    () => DoSomethingOnCompleted());
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜