【问题标题】:Rx.Net: Chaining subscribers - alternative approach?Rx.Net:链接订阅者 - 替代方法?
【发布时间】:2018-05-06 11:26:01
【问题描述】:

我怎样才能重新编写这段代码,这样我就不必像下面那样链接订阅者了?询问的原因是,由于代码的风格,这种风格将限制在一个可观察对象中,这取决于另一个可观察对象,它可能会让人感到困惑。

var results = myService
          .GetData(accountId)    // returns IObservable
          .Subscribe(data =>
          {
              new MyWork().Execute(data)  // returns IObservable
                  .Subscribe(result =>
                  {
                      myResults.Add(result);
                      WriteLine($"Result Id: {result.Id}");
                      WriteLine($"Result Status: {result.Pass}");
                  });
          }); 

在 Peter Bons 的第一次回复后添加

下面是具有执行方法的 MyWork 类的代码

public class MyWork 
{
    public virtual IObservable<MyResult> Execute(MyData data)
    {
        MyResult result = null;

        return IsMatch(data)
            .Do(isMatch =>
            {
                if (isMatch)
                {
                    result = new MyResult(1, true);
                }
            })
            .Select(_ => result);
    }


    public IObservable<bool> IsMatch(MyData data)
    {
        return true;
    }
}

【问题讨论】:

  • 您的 MyWork 类无法编译。这不是你的真实代码,对吧?
  • 由于我无法发布我的原始代码,我进行了更改以传达我在做什么的想法。对此我很抱歉,我应该在发布之前检查一下 sn-p 代码。

标签: system.reactive rx.net


【解决方案1】:

其实很简单。

var results =
    myService
      .GetData(accountId)
      .SelectMany(data => new MyWork().Execute(data))
      .Subscribe(result =>
      {
          myResults.Add(result);
          Console.WriteLine($"Result Id: {result.Id}");
          Console.WriteLine($"Result Status: {result.Pass}");
      });

如果您曾经在订阅中订阅,那么您做错了什么。记在脑子里。几乎总有一种方法可以通过单一订阅使其成为纯查询。

只是为了帮助进行测试,这里是使其成为Minimal, Complete, and Verifiable example 所需的代码。

public static class myService
{
    public static IObservable<MyData> GetData(int x)
        => Observable.Return(new MyData());
}

public class MyWork 
{
    public virtual IObservable<MyResult> Execute(MyData data)
    {
        MyResult result = null;

        return IsMatch(data)
            .Do(isMatch =>
            {
                if (isMatch)
                {
                    result = new MyResult() { Id = 1, Pass = true};
                }
            })
            .Select(_ => result);
    }


    public IObservable<bool> IsMatch(MyData data)
    {
        return Observable.Return(true);
    }
}

public class MyResult
{
    public int Id;
    public bool Pass;
}

public class MyData { }

【讨论】:

  • 这行得通,感谢您的回复和回答。您能否让我知道为什么“SelectMany”有效,为什么“Select”在执行“Do code block”方面不有效?另外,“SelectMany”如何取代我在我的 OP 中拥有的多个订阅者的角色?
  • @GautamTGoudar - 使用.Select 将返回IObservable&lt;IObservable&lt;MyData&gt;&gt;,因此您的订阅只会订阅外部可观察对象,因此内部对象永远不会被订阅,因此.Do 不会运行。 .SelectManyIObservable&lt;IObservable&lt;MyData&gt;&gt; 扁平化为 IObservable&lt;MyData&gt;,然后自动创建对内部 observables 的订阅,然后 .Do 就可以工作了。
  • 非常感谢您的回复。如果可能的话,只是延长我的运气以寻求更多答案。如果我必须调用 10 个类似于 My Work() 类的不同对象(比如 MyWork1()、MyWorks2() 等),该怎么做?
  • @GautamTGoudar - 您将创建一个代表数组并在这些代表上使用 .ToObservable(),然后在 .SelectMany 中调用每个代表 - 这是假设您需要使用每个 MyData 对象调用每个代表。如果您需要更多详细信息,我建议您提出一个新问题。
  • 针对多个 IObservable 调用 here 发布了一个新问题。我在代表数组中缺少一些东西以及如何调用 SelectMany。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多