Rx.Net : Calling multiple IObservable in SelectMany

烂漫一生 提交于 2019-12-25 02:34:14

问题


Please Note: This is continuation of the question posted earlier but the solution of interest is of a different situation.

I am trying to make multiple calls to the methods that each return IObservable but the values being returned back in the SelectMany statement is a Task and hence the following Subscribe statement does not compile.

This is the code snippet

 var myWorkList = new List<MyWork>
                {
                    new MyWork(),// MyWork.Execute(data) returns IObservable
                    new MyWork()
                }.ToObservable();

 var results =
   myService
    .GetData(accountId)
    .SelectMany(data => myWorkList.ForEachAsync(r => r.Execute(data))
    .Subscribe(result =>
    {
        Console.WriteLine($"Result Id: {result.Id}");
        Console.WriteLine($"Result Status: {result.Pass}");
    });

回答1:


You just want to use .SelectMany. Try this:

var myWorkList = new List<MyWork>()
{
    new MyWork(),
    new MyWork()
}.ToObservable();

var query =
    from data in myService.GetData(accountId)
    from myWork in myWorkList
    from result in myWork.Execute(data)
    select result;

var results =
    query
        .Subscribe(result =>
        {
            Console.WriteLine($"Result Id: {result.Id}");
            Console.WriteLine($"Result Status: {result.Pass}");
        });

Here's my testing code:

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)
    {
        return
            from isMatch in IsMatch(data)
            where isMatch
            select new MyResult() { Id = 1, Pass = true };
    }

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

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

public class MyData { }

When I execute I get this:

Result Id: 1
Result Status: True
Result Id: 1
Result Status: True

In the comments on your previous question I suggested doing this as a list of delegates. Here's how:

var myWorkList = new Func<MyData, IObservable<MyResult>>[]
{
    md => new MyWork().Execute(md),
    md => new MyWork().Execute(md),
}.ToObservable();

var query =
    from data in myService.GetData(accountId)
    from myWork in myWorkList
    from result in myWork(data)
    select result;

You get the same result.




回答2:


The list can be declared just as list of MyWork-s - using no ToObservable here.

var myWorkList = new List<MyWork>
            {
                new MyWork(),// MyWork.Execute(data) returns IObservable
                new MyWork()
            };

then, we map the objects, returned by myService.GetData onto the elements of myWorkList and take them as IObservable-s.

var observables = myService
         .GetData(accountId)
         .SelectMany(data => myWorkList.Select(r => r.Execute(data)));

And now you can observe them.

Either together - merged:

var subscription =
          observables
           .Merge()
           .Subscribe(result =>
           {
               ...
           });

Or separately:

var subscriptions=
          observables
           .Select(obs => 
               obs.Subscribe(result =>
               {
                   ...
               }))
           .ToArray();

Update: the latter case must be immediately materialized in order to prevent side effects (.ToArray()).



来源:https://stackoverflow.com/questions/50196955/rx-net-calling-multiple-iobservable-in-selectmany

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!