C# 从流中去除嵌套的可观测数据

C# 从流中去除嵌套的可观测数据,c#,system.reactive,reactive-programming,C#,System.reactive,Reactive Programming,我有一个类ObservableCollection,它表示一个不断变化的集合: public interface IObservableCollection<T> : IObservable<IEnumerable<T>> { void Add(T item); void Remove(T item); } var peoplePositions = (from people in peopleCollectionStream

我有一个类
ObservableCollection
,它表示一个不断变化的集合:

public interface IObservableCollection<T> : IObservable<IEnumerable<T>>
{
    void Add(T item);
    void Remove(T item);
}
var peoplePositions = (from people in peopleCollectionStream
                       select
                           (from person in people
                            select person.Position
                                .Select(pos => Tuple.Create(person.Name, pos))
                            ).CombineLatest()
                       ).Switch();
我想做的是生成一个
IEnumerable
流,表示每个人在集合中的位置。这似乎相对简单:

var peopleCollectionStream = new ObservableCollection<IPerson>();

var peoplePositions = from people in peopleCollectionStream
                      from updateList in
                          (from person in people
                           select person.Position.Select(pos => Tuple.Create(person.Name, pos)))
                           .CombineLatest()
                      select updateList;
我得到了期望的输出:

var alice = new Person() { Name = "Alice" };
peopleCollectionStream.Add(alice);        // Alice -> 0
alice.Move(2);                            // Alice -> 2
var bob = new Person() { Name = "Bob" };
peopleCollectionStream.Add(bob);          // Alice -> 2, Bob -> 0
bob.Move(3);                              // Alice -> 2, Bob -> 3
当我希望从集合中删除一个人,从而从流中排除他们的更新时,会出现问题:

peopleCollectionStream.Remove(bob);       // Alice -> 2
bob.Move(4);                              // Alice -> 2, Bob -> 4

我想阻止鲍勃的位置更新被包括,如果他从集合中删除。我怎样才能做到这一点呢?

我发现,如果您想做这些功能性的事情,尝试使用添加和删除事件是一个坏主意。匹配删除和添加,并确保底层代码也这样做,这是一项艰巨的工作

我所做的是使用易腐物品/收藏品。我将每个项与一个生存期(取消令牌)配对,当其生存期结束时,该项被视为已删除。然后我用这些生命来连接其他东西。我使用了一种称为
易腐收集
的收集类型,它将项目与生命周期配对,并允许您将其内容作为
IObservable
进行查看

我,并发表了一篇论文

下面的代码应该将易腐集合中的易腐集合展平:

public static PerishableCollection<T> Flattened<T>(this PerishableCollection<PerishableCollection<T>> collectionOfCollections, Lifetime lifetimeOfResult) {
    if (collectionOfCollections == null) throw new ArgumentNullException("collectionOfCollections");

    var flattenedCollection = new PerishableCollection<T>();
    collectionOfCollections.CurrentAndFutureItems().Subscribe(
        c => c.Value.CurrentAndFutureItems().Subscribe(

            // OnItem: include in result, but prevent lifetimes from exceeding source's lifetime
            e => flattenedCollection.Add(
                item: e.Value,
                lifetime: e.Lifetime.Min(c.Lifetime)),

            // subscription to c ends when the c's lifetime ends or result is no longer needed
            c.Lifetime.Min(lifetimeOfResult)),

        // subscription ends when result is no longer needed
        lifetimeOfResult);

    return flattenedCollection;
}

希望这足以让您开始一条更简单的道路。

我发现,如果您想做这些功能性的事情,尝试使用添加和删除事件是一个坏主意。匹配删除和添加,并确保底层代码也这样做,这是一项艰巨的工作

我所做的是使用易腐物品/收藏品。我将每个项与一个生存期(取消令牌)配对,当其生存期结束时,该项被视为已删除。然后我用这些生命来连接其他东西。我使用了一种称为
易腐收集
的收集类型,它将项目与生命周期配对,并允许您将其内容作为
IObservable
进行查看

我,并发表了一篇论文

下面的代码应该将易腐集合中的易腐集合展平:

public static PerishableCollection<T> Flattened<T>(this PerishableCollection<PerishableCollection<T>> collectionOfCollections, Lifetime lifetimeOfResult) {
    if (collectionOfCollections == null) throw new ArgumentNullException("collectionOfCollections");

    var flattenedCollection = new PerishableCollection<T>();
    collectionOfCollections.CurrentAndFutureItems().Subscribe(
        c => c.Value.CurrentAndFutureItems().Subscribe(

            // OnItem: include in result, but prevent lifetimes from exceeding source's lifetime
            e => flattenedCollection.Add(
                item: e.Value,
                lifetime: e.Lifetime.Min(c.Lifetime)),

            // subscription to c ends when the c's lifetime ends or result is no longer needed
            c.Lifetime.Min(lifetimeOfResult)),

        // subscription ends when result is no longer needed
        lifetimeOfResult);

    return flattenedCollection;
}

希望这足以让您从一条更容易的道路开始。

答案是
.Switch
操作符。通过仅选择要订阅的最新观测值列表,流将排除最新版本集合中不存在的任何观测值:

public interface IObservableCollection<T> : IObservable<IEnumerable<T>>
{
    void Add(T item);
    void Remove(T item);
}
var peoplePositions = (from people in peopleCollectionStream
                       select
                           (from person in people
                            select person.Position
                                .Select(pos => Tuple.Create(person.Name, pos))
                            ).CombineLatest()
                       ).Switch();

(顺便说一句,如果有人对使用括号/嵌套linq查询语法时的格式有什么好的建议,请告诉我,因为上面看起来很糟糕!)

答案是
.Switch
运算符。通过仅选择要订阅的最新观测值列表,流将排除最新版本集合中不存在的任何观测值:

public interface IObservableCollection<T> : IObservable<IEnumerable<T>>
{
    void Add(T item);
    void Remove(T item);
}
var peoplePositions = (from people in peopleCollectionStream
                       select
                           (from person in people
                            select person.Position
                                .Select(pos => Tuple.Create(person.Name, pos))
                            ).CombineLatest()
                       ).Switch();

(顺便说一句,如果有人对使用括号/嵌套linq查询语法时的格式有什么好的建议,请告诉我,因为上面的内容看起来非常糟糕!)

这是一个非常有趣的概念,谢谢-我必须进一步研究它,看看它是否适用于我的情况。尼斯博客牙齿是一个非常有趣的概念,谢谢你-我将进一步研究它,看看它是否适用于我的情况。很好的博客评论你的推荐请求。两件事:1)我会使用来自。。。从语法(对于SelectMany)而不是最里面的。选择。第二,当嵌套变得过于复杂时,考虑将其重构成单独的方法。如果您使用匿名类型,这会变得很困难,但至少在本例中您看起来是安全的。谢谢,可靠的建议。我不经常使用查询语法,但我发现嵌套时更容易编写。在我的演示项目中,我实际上使用的是匿名类型,但在实际场景中,我肯定会将这些块分割成方法,并使用专用的结构。对您的建议请求进行评论。两件事:1)我会使用来自。。。从语法(对于SelectMany)而不是最里面的。选择。第二,当嵌套变得过于复杂时,考虑将其重构成单独的方法。如果您使用匿名类型,这会变得很困难,但至少在本例中您看起来是安全的。谢谢,可靠的建议。我不经常使用查询语法,但我发现嵌套时更容易编写。在我的演示项目中,我实际上使用的是匿名类型,但在实际场景中,我肯定会将这些块分割成方法,并使用专用结构。