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.Event
1[System.EventArgs]
DoSomethingOnNext:System.Collections.Generic.Event1[System.EventArgs]
DoSomethingOnNext:System.Collections.Generic.Event
1[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());
精彩评论