从Do块中的副作用创建Observable

时间:2015-06-17 19:04:05

标签: c# system.reactive reactive-programming

使用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,以便更明确地了解这些副作用。在这种情况下,订阅会停止链,以便从操作中获取输出并在以后使用它,我会求助于主题并在操作完成或失败时提供。但话说回来,除非真的需要,否则通常不鼓励受试者。

是否有更具表现力的代码?谢谢大家

编辑:在各种评论之后,我添加了更多代码,以便展示更完整的示例。此外,我修正了暴露当前情况的一些错误,我认为这令人困惑。

1 个答案:

答案 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 => {});