我对Observables有点新意,所以我只是想找一个能让我朝着正确方向前进的例子(教程可能吗?)。所以这就是 - 我想创建异步Observable
并从中提出Exception
。这是我的例子:
protected IObservable<Tuple<DataPart1, DataPart2>> LoadAllDataFunc(string FileName)
{
return Observable.Start<Tuple<DataPart1, DataPart2>>(() =>
{
ConfigReaderWriter readerWriter = new ConfigReaderWriter();
try
{
readerWriter.UnpackFile(fileName, out DataPart1, out DataPart2);
return Tuple.Create(DataPart1, DataPart2);
}
catch (Exception exp_gen)
{
Observable.Throw<Exception>(exp_gen);
return null;
}
});
}
问题是我不认为我没有正确地抛出Exception
。例如 - 任何订阅者:
internal IObservable<DataPart2> GetProject()
{
if (this.GlobalDataPart2 != null)
return Observable.Return(GlobalDataPart2);
IObservable<Project> receivedData = null;
var loadAll = LoadAllDataFunc(this.GlobalFileName).Subscribe(
data => { receivedData = Observable.Return(data.Item1); },
(ex) => { Observable.Throw<Exception>(ex); }
);
return receivedData;
}
不会从Exception
收到LoadAllDataFunc
?即使发生 if 异常,订阅者也会收到null
。
那么 - 从Observable抛出异常的正确方法是什么?
答案 0 :(得分:3)
只是为了清楚地说明Observable.Throw的作用:它返回一个可观察的序列(指定的元素类型),其唯一的作用是通过调用它们的OnError方法告诉所有观察者一个异常:
var err = Observable.Throw<int>(new Exception("Oops!"));
err.Subscribe(_ => {}, ex => { Console.WriteLine(ex.Message); }, () => {});
err.Subscribe(_ => {}, ex => { Console.WriteLine(ex.Message); }, () => {});
上面的代码将打印出来!两次。
正如Gideon所提到的,像Start这样的运算符会将用户异常传播到OnError通道。如果您使用Observable.Create,请直接与观察者讨论错误情况:
var res = Observable.Create<int>(observer =>
{
return scheduler.Schedule(() =>
{
var res = default(int);
try
{
res = ComputationThatMayFail();
}
catch (Exception ex)
{
observer.OnError(ex);
return;
}
observer.OnNext(res);
observer.OnCompleted();
});
});
事实上,上面显示的代码非常接近Start所做的事情。 (一个区别与使用AsyncSubject缓存操作的结果有关。)
答案 1 :(得分:0)
使用Observable.Start
时,最好的方法是不捕获异常。 Observable.Throw
和Observable.Return
只是创建可观察的序列;他们没有像返回IObservable
那样在内部方法做任何特别的事情,就像你期望的那样。这就是为什么你没有从你的顶级代码中获得OnError
电话。对Observable.Throw的调用创建了一个observable,对它没有任何作用,并从函数返回一个空值,然后发送给观察者的OnNext
。
您的第二段代码似乎有相关问题。再次,对Throw的召唤将无所作为。该订户的OnNext操作也可能不是您想要的。通常,您将从该函数返回null,因为LoadAllDataFunc
的第一个结果可能不会在GetProject
返回时出现(订阅通常不会阻止。)我猜你想要什么是否可以使用Select
。
return LoadAllDataFunc(this.GlobalFileName)
.Select(data => data.Item1); //should this be Item2?