![](/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.