将多个observable合并为单个字典

时间:2015-01-20 23:05:53

标签: c# system.reactive

我想将多个observable(每个都返回一个Update对象)组合成一个字典对象。

以下是我想要实现的目标示例:

private IObservable<IDictionary<string, IUpdate>> CreateUpdateStreams(Product product)
{
  var codeObservables = product.Codes.Select(code => CreateUpdateStream(code)).ToList();

  //??? 
  return pointObs.Merge().Select(update => ...);
}


private IObservable<IUpdate> CreateUpdateStream(string code)
{
  ...
  //return an observable of IUpdate
}
  • 我希望将所有IUpdates组合成一个更新的字典,其中key = Code和Value = IUpdate
  • CreateUpdateStreams的调用者将知道Product并希望根据更新对每个Code对象的某些属性进行更改。例如

产品= Foo

Product.Codes = {Code1,Code2,Code3}

IDictionary = {Code1,“a”},{Code2,“b”},{Code3,“c”}

根据更新的值(在本例中为a / b / c),将对相应的代码进行不同的更改,例如设置类似Code.State =“a”等的属性。

由于每个codeObservable都会以不同的速率更新,Merge似乎是明智的起点。我不确定如何从各个observables更新一个字典对象,它保留了过去的值。

1 个答案:

答案 0 :(得分:2)

以下是您的问题的一个镜头,它利用了匿名类型。它依赖于副作用字典。请注意,由于Rx保证了顺序行为,因此无需在字典上进行同步。

private IObservable<IReadOnlyDictionary<string, IUpdate>> CreateUpdateStreams(Product product)
    {
        var dictionary = new Dictionary<string, IUpdate>();
         return
          product.Codes.Select(
              code => CreateUpdateStream(code).Select(update => new {Update = update, Code = code}))
              .Merge()
              .Do(element => dictionary.Add(element.Code, element.Update))
              .Select(_ => dictionary);
    }

请注意,我已将方法签名更改为返回IObservable<IReadOnlyDictionary<,>>,以防止客户端代码篡改字典。另一种选择是每次都返回字典的新副本。这确保了不可变的行为(但可能会影响性能,具体取决于字典的大小),如下所示:

private IObservable<IDictionary<string, IUpdate>> CreateUpdateStreams(Product product)
    {
        var dictionary = new Dictionary<string, IUpdate>();
        return
            product.Codes.Select(
                code => CreateUpdateStream(code).Select(update => new {Update = update, Code = code}))
                .Merge()
                .Select(element =>
                {
                    dictionary.Add(element.Code, element.Update);
                    return new Dictionary<string, IUpdate>(dictionary);
                });
    }