结合相关的可观察量

时间:2016-02-17 11:42:52

标签: c# system.reactive

我有一个容器类Project,里面有很多IItem个。项目可以在项目启动之前添加项目。然后不能再添加任何项目,除非它被停止。

每个项目都可以通过其IsActive属性激活和停用。

public interface IItem 
{
    bool IsActive { get; set;}
}

public interface IFoo : IItem
{
}

public class Foo : IFoo
{
    public bool IsActive { get; set;}
}

public interface IBar : IItem
{ }

public class Bar : IBar
{ 
    public bool IsActive { get; set;}
}

public class Project
{
    public Project(params IItem [] items)
    {
        Items = new List<IItem>(items);
    }

    public List<IItem> Items { get;}
}

我还有两个可观察项目,一个用于项目状态,另一个用于更改任何项目。为了这个例子的目的,我已经用主题模拟了这些

var projectIsRunningObservable = new Subject<bool>();
var projectItemChangedObservable = new Subject<IItem>();

我正在尝试创建一个IObservable<bool>,它发送一个值,指示是否(至少有一个项目处于活动状态且项目已启动)。如果存在活动项目并且项目已停止,则应该推送false值。

这是我到目前为止所做的:

void Main()
{
    var bar1 = new Bar();   
    var bar2 = new Bar();   

    var foo1 = new Foo();
    var foo2 = new Foo();

    var projectIsRunningObservable = new Subject<bool>();
    var projectItemChangedObservable = new Subject<IItem>();

    var project = new Project(
        bar1, bar2, foo1, foo2);


    var observable = Observable.Create<bool>(obs =>
                {
                   IList<IItem> items = null;

                    var stateObservable = projectIsRunningObservable.StartWith(false).Subscribe(
                    (state) =>
                    {
                        if (!state)
                        {
                            items = null;
                            obs.OnNext(false);
                        }
                        else
                        {
                            items = project.Items.ToList();
                            obs.OnNext(items != null && items.Any(i => i.IsActive));
                        }
                    },
                    ex => obs.OnError(ex),
                    () => obs.OnCompleted());

                    var itemChangedObservable = projectItemChangedObservable.Subscribe(
                    x =>
                    {
                        obs.OnNext(items != null && items.Any(i => i.IsActive));
                    }
                    ,
                    ex => obs.OnError(ex),
                    () => obs.OnCompleted());

                    return new CompositeDisposable(stateObservable, itemChangedObservable);
                });


    var subscr = observable.Subscribe(Console.WriteLine);

    Console.WriteLine("Change bar1");
    bar1.IsActive = true;
    projectItemChangedObservable.OnNext(bar1);

    Console.WriteLine("Change bar2");
    bar2.IsActive = true;
    projectItemChangedObservable.OnNext(bar2);

    Console.WriteLine("Change foo1");
    foo1.IsActive = true;
    projectItemChangedObservable.OnNext(foo1);

    Console.WriteLine("Change foo2");
    foo2.IsActive = true;
    projectItemChangedObservable.OnNext(foo2);

    // Start project

    Console.WriteLine("Starting project");
    projectIsRunningObservable.OnNext(true);

    Console.WriteLine("Change bar1");
    bar1.IsActive = false;
    projectItemChangedObservable.OnNext(bar1);

    Console.WriteLine("Change bar2");
    bar2.IsActive = false;
    projectItemChangedObservable.OnNext(bar2);

    Console.WriteLine("Change foo1");
    foo1.IsActive = false;
    projectItemChangedObservable.OnNext(foo1);

    Console.WriteLine("Change foo2");
    foo2.IsActive = false;
    projectItemChangedObservable.OnNext(foo2);

    Console.WriteLine("Change foo2 back to true");
    foo2.IsActive = true;
    projectItemChangedObservable.OnNext(foo2);

    // Stop project
    Console.WriteLine("Stopping project");
    projectIsRunningObservable.OnNext(false);

    Console.WriteLine("Change bar1");
    bar1.IsActive = true;
    projectItemChangedObservable.OnNext(bar1);

    Console.WriteLine("Change bar2");
    bar2.IsActive = true;
    projectItemChangedObservable.OnNext(bar2);

    Console.WriteLine("Change foo1");
    foo1.IsActive = true;
    projectItemChangedObservable.OnNext(foo1);

    Console.WriteLine("Change foo2");
    foo2.IsActive = true;
    projectItemChangedObservable.OnNext(foo2);
}

这有效,但我不确定这是否是最佳方式,以及是否可以发送多个OnErrorOnCompleted通知。

1 个答案:

答案 0 :(得分:1)

这是component的一个很好的用例。您应该将Observable.Create重构为Subject,并使用Observable类进行测试。

您可以在Rx Design Guidelines (PDF)中找到后一个问题的答案。第6.2章指出TestScheduler提供了一些保护措施,使序列遵循Rx契约。

  

当可观察序列完成时(通过触发OnError或Oncompleted),任何订阅都将自动取消订阅。    任何订阅的观察者实例只会看到一条OnError或OnCompleted消息。不再发送任何消息。这确保了OnNext *(OnError | OnCompleted)的Rx语法?

注意:在指南示例中,它们使用Observable.Create。在最新的Rx版本中,它已被重构为Observable.CreateWithDisposable的重载,您可能知道:)