![](/img/trans.png)
[英]Turn an IObservable<IEnumerable<T>> into an IEnumerable<IObservable<T>>
[英]Switching on IObservable<IEnumerable<IEnumerable<T>>>
我有以下结构:
// source of data
interface IItem
{
IObservable<string> Changed { get; }
}
interface IItemCollection
{
List<IItem> Items { get; }
IObservable<IItem> ItemAdded { get; }
IObservable<IItem> ItemRemoved { get; }
}
interface IItemCollectionManager
{
List<IItemCollection> ItemCollectionCollection { get; }
IObservable<IItemCollection> ItemCollectionAdded { get; }
IObservable<IItemCollection> ItemCollectionRemoved { get; }
}
// desired result
interface IAggregation
{
IObservable<string> Changed { get; }
}
这里的目标是让IAggregation
暴露一个单一的可观察对象。 然而, IItem
s时,可以添加和移除各个IItemCollection
在任何时间,并且,事实上,一个IItemCollection
可以添加或从中删除IItemCollectionManager
随时太。 当然,当添加了这样的IItemCollection
时, Aggregation
应该发出来自该Aggregation
值,如果删除了ItemCollection
,我不再希望发出来自该集合中IItem
的string
s。 此外,当Item
添加到任何IItemCollection
,其Changed
observable 中的值也应该从IAggregation
的Changed
observable 中产生值。
现在,当只有一个IItemCollection
,解决这个问题相当简单,例如:
class AggregationImpl : IAggregation
{
public AggregationImpl(IItemCollection itemCollection)
{
var added = itemCollection.ItemAdded
.Select(_ => itemCollection.Items);
var removed = itemCollection.ItemRemoved
.Select(_ => itemCollection.Items);
Changed = Observable.Merge(added, removed)
.StartWith(itemCollection.Items)
.Select(coll => coll.Select(item => item.Changed).Merge())
.Switch();
}
public IObservable<string> Changed { get; }
}
...这里的关键是我使用Merge()
将所有Item
的Changed
observable 展平为单个 observable 然后,每次添加或删除项目时,我重新创建整个Observable
并使用Switch()
来取消订阅旧的并订阅新的`。
我觉得扩展以包含IItemCollectionManager
应该非常简单,但我不太确定如何处理它。
我希望这有效,或者至少让你走上正确的道路。 由于测试似乎相当复杂,因此我将对其进行测试。 如果你有一些简单的测试代码,那么我很乐意测试。
首先,我不太喜欢你发布的实现。 您正在连接ItemAdded
和ItemRemoved
观察对象,而根本不使用数据; 您正在从Items
属性获取数据。 这可能会在糟糕的实现中导致竞争条件,即在更新属性之前发送事件。 因此,我创建了自己的实现。 我还建议将其放入扩展方法中,因为这会使以后的生活更轻松:
public static IObservable<string> ToAggregatedObservable(this IItemCollection itemCollection)
{
return Observable.Merge(
itemCollection.ItemAdded.Select(item => (op: "+", item)),
itemCollection.ItemRemoved.Select(item => (op: "-", item))
)
.Scan(ImmutableList<IItem>.Empty.AddRange(itemCollection.Items), (list, t) =>
t.op == "+"
? list.Add(t.item)
: list.Remove(t.item)
)
.Select(l => l.Select(item => item.Changed).Merge())
.Switch();
}
原谅魔法字符串,如果你愿意,你可以把它变成一个enum
。 我们在Scan
内的ImmutableList
维护当前项目的状态。 当一个项目被添加/删除时,我们更新列表,然后切换 observable。
同样的逻辑可以应用于集合管理器级别:
public static IObservable<string> ToAggregatedObservable(this IItemCollectionManager itemCollectionManager)
{
return Observable.Merge(
itemCollectionManager.ItemCollectionAdded.Select(itemColl => (op: "+", itemColl)),
itemCollectionManager.ItemCollectionRemoved.Select(itemColl => (op: "-", itemColl))
)
.Scan(ImmutableList<IItemCollection>.Empty.AddRange(itemCollectionManager.ItemCollectionCollection), (list, t) =>
t.op == "+"
? list.Add(t.itemColl)
: list.Remove(t.itemColl)
)
.Select(l => l.Select(itemColl => itemColl.ToAggregatedObservable()).Merge())
.Switch();
}
这里我们只是重新使用第一个扩展方法,并使用与以前相同的添加/删除然后切换逻辑。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.