使用Reactive Extensions,通常建议将Select
保留为纯函数,即没有任何副作用。然后,当需要副作用时,要么使用Subscribe
将其放在管道的末尾,要么使用Do
作为管道中间的最后手段。
理想情况下,我会选择最后一个选项(Do),但在我目前的情况下,类似于下面的代码块,我有一个带有副作用的Select
,因为我需要知道结果来自操作以便稍后执行某些逻辑。结果的例子可能是:
操作是否成功完成或失败,以便向用户显示错误;
通过该操作碾压的一些数字,这是在另一个可观察的管道中需要的。
无论如何,这是一个代码示例:
IObservable<Unit> inputStream = /* generate stream... */;
IObservable<OperationResult> operationOneStream = inputStream.Select(_ =>
{
try
{
/* side effect: do something, that can also throw... */
return OperationResult.Success; // use a simple Enum
}
catch (Exception ex)
{
/* compensate error: do something ... */
return OperationResult.ErrorInOperationOne;
}
});
// operationOneStream is used to build further streams down the chain, it's not "final".
IObservable<OperationResult> operationTwoStream = operationOneStream
.Where(result => result == OperationResult.Success)
// here in between some more operations: delay, select returning a stream, switch, ...
.Select(_ =>
{
try
{
/* side effect: do something, that can also throw... */
return OperationResult.Success;
}
catch (Exception ex)
{
/* compensate error: do something ... */
return OperationResult.ErrorInOperationTwo;
}
});
// then a third operation, running when nr. 2 is successful
/* ... */
/* Then, operationOne could be merged with other similar operations,
* so to grab their error streams and treat them in a single block.
*/
IObservable<SomeType> allOperationsStream = Observable.Merge(
operationOneStream, operationTwoStream /*, ... */);
IDisposable subscription = allOperationsStream
.Where(result => result != OperationResult.Success)
.Subscribe(result => /* do something with error */);
现在我想了解是否有办法从Do
切换到Subscribe
,以便更明确地了解这些副作用。在这种情况下,订阅会停止链,以便从操作中获取输出并在以后使用它,我会求助于主题并在操作完成或失败时提供。但话说回来,除非真的需要,否则通常不鼓励受试者。
是否有更具表现力的代码?谢谢大家
编辑:在各种评论之后,我添加了更多代码,以便展示更完整的示例。此外,我修正了暴露当前情况的一些错误,我认为这令人困惑。
答案 0 :(得分:0)
不确定我是否完全遵循了您之后所做的事情,但您可能只是尝试使用selectmany将多个可观察量链接在一起?
(from a in Observable.Return(1)
from b in Observable.Return(2)
select b
).Subscribe(x => {}, ex => {})
你也可以像这样构建错误处理:
(from a in Observable.Return(1)
from result in Observable.Return(2)
.Select(x => OperationResult.Success)
.Catch<OperationResult, Exception>(ex => { return Observable.Return(OperationResult.Error);})
select result)
.Subscribe(x => {}, ex => {});