Решение зависит от того, доступен ли вам Dispatcher / SynchronisationContext. Конечно, предпочтительно использовать один в этом сценарии.
Решение 1: Диспетчер / СинхронизацияКонтент доступен
(т.е. с использованием WPF, Windows Forms или пользовательского цикла Dispatcher)
Вы можете использовать ObserveOn
+ Catch
, чтобы переместить ошибку обратно в поток Dispatcher. Я видел, как это используется в приложении WPF, и оно работало хорошо.
Как вы перемещаете ваш IScheduler
/ DispatcherScheduler
, зависит от вас (мы использовали IoC)
public static IObservable<T> CatchOn<T>(this IObservable<T> source,
IScheduler scheduler)
{
return source.Catch<T,Exception>(ex =>
Observable.Throw<T>(ex).ObserveOn(scheduler));
}
// We didn't use it, but this overload could useful if the dispatcher is
// known at the time of execution, since it's an optimised path
public static IObservable<T> CatchOn<T>(this IObservable<T> source,
DispatcherScheduler scheduler)
{
return source.Catch<T,Exception>(ex =>
Observable.Throw<T>(ex).ObserveOn(scheduler));
}
Решение 2: Диспетчер недоступен
Вместо использования Console.ReadKey()
используйте ManualResetEvent
и дождитесь его, а затем сгенерируйте изменчивую ошибку:
static void Main(string[] args)
{
try
{
Console.WriteLine("Main thread: " + System.Threading.Thread.CurrentThread.ManagedThreadId);
var observable = TestEnumerable().ToObservable(Scheduler.NewThread); //Needs to be on a new thread because it contains long-running blocking operations
// Use subject because we need many subscriptions to a single data source
var subject = new Subject<int>();
Exception exception = null;
ManualResetEvent mre = new ManualResetEvent(false);
using(subject.Subscribe(
x => Console.WriteLine(x),
ex => { exception = ex; mre.Set(); },
() => Console.WriteLine("Subscriber2 Finished")))
using(subject.Subscribe(
x => Console.WriteLine(x),
ex => { exception = ex; mre.Set(); },
() => Console.WriteLine("Subscriber2 Finished")))
using (observable.Subscribe(subject))
{
mre.WaitOne();
}
if (exception != null)
throw exception;
}
catch (Exception ex)
{
Console.WriteLine("Caught exception on main thread");
}
}