簡體   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