繁体   English   中英

开启 IObservable <IEnumerable<IEnumerable<T> &gt;&gt;

[英]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 ,我不再希望发出来自该集合中IItemstring s。 此外,当Item添加到任何IItemCollection ,其Changed observable 中的值也应该从IAggregationChanged 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()将所有ItemChanged observable 展平为单个 observable 然后,每次添加或删除项目时,我重新创建整个Observable并使用Switch()来取消订阅旧的并订阅新的`。

我觉得扩展以包含IItemCollectionManager应该非常简单,但我不太确定如何处理它。

我希望这有效,或者至少让你走上正确的道路。 由于测试似乎相当复杂,因此我将对其进行测试。 如果你有一些简单的测试代码,那么我很乐意测试。

首先,我不太喜欢你发布的实现。 您正在连接ItemAddedItemRemoved观察对象,而根本不使用数据; 您正在从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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM