一般观察的使用

时间:2013-04-01 22:25:37

标签: observablecollection system.reactive observable

虽然我不时在我的代码中使用Observable和Rx但我仍然在“推模型”及其使用方面存在这个问题。

例如,假设我有这个简单的代码:

  private readonly static List<string> numbers = new List<string>
  {
      "1",
      "2",
      "3",
      "4",
      "5"
  };

  static void Main(string[] args)
  {
      PrintCollection();
      Console.ReadLine();
      numbers.Add("6");
      Console.ReadLine();
  }

  private static void PrintCollection()
  {
      IObservable<string> observable = numbers.ToObservable();
      observable.Subscribe<string>(x => { Console.WriteLine(x); });
  }        

当程序运行时,只打印1-5但不打印6,除非我使用类似ObservableCollection的东西并挂钩“CollectionChanged”事件。然而,这让我想知道“推模型”究竟是什么。我一直认为“推模型”意味着一旦数据(colleciton)订阅了一个事件,所有新添加的数据都会订阅同一个事件。

此外,我使用Observable看到的大多数示例似乎都是WPF,视图模型驱动的implmenentation,我想知道是否有人将它用于任何后端处理,这将是一个典型的例子?

2 个答案:

答案 0 :(得分:4)

我认为你在混淆ToObservable所做的事情 - 基本上,它说“看到这一系列的东西?我想创建一个新的流,将这些价值反馈给我。”它不会以任何有意义的方式“包装”源列表,例如监听未来的更改,更多的是时间快照 - 生成的observable是创建observable时列表的样子。

有许多方法可以模拟集合的“实时视图” - 您已经提到过:创建一个ObservableCollection并创建observable,从写入CollectionChanged事件。你也可以在这里使用一个主题,虽然它将状态的概念注入到rx的“无状态”世界。

实际上,这是一个值得强调的好处:rx流在概念上比传统的命令式/ oo编程更具“功能性”;你随着时间的推移声明了一个潜在值的流,而不是一个状态机(虽然你可以强迫它像状态机一样)...你弄清楚你想要/需要的值随着时间的推移“看”,这就是你如何声明你的流。

然而,在这样的特定情况下,声明随机变化的值流是困难的;通过其他方式(事件,投票等)可以更好地满足。

那就是说,你可以这样写:

var numbers = new List<string>
{
    "1",
    "2",
    "3",
    "4",
    "5"
};
var source = new ObservableCollection<string>(numbers);
var query = Observable.Create<string>((obs) =>
    {
        foreach(var oldItem in source)
        {
            obs.OnNext(oldItem);
        }
        NotifyCollectionChangedEventHandler h;
        h = (o, e) => 
        {
            Console.WriteLine("Collection changed!");
            foreach(var item in e.NewItems)
            {
                obs.OnNext(item as string);
            }
        };
        source.CollectionChanged += h;
        return Disposable.Create (() => source.CollectionChanged -= h);
    });

using(query.Subscribe(Console.WriteLine))
{
    source.Add("6");
    Console.ReadLine();
}

输出:

1
2
3
4
5
Collection changed!
6

答案 1 :(得分:1)

您可以在订阅之前一起使用Concat Observable:

var numbers = new List<string> { "1", "2", "3", "4", "5" }.ToObservable();
numbers = numbers.Concat(new [] { "6" }.ToObservable());
numbers.Subscribe(n => Console.WriteLine(n), ex => Console.WriteLine(ex.ToString()), () => Console.WriteLine("Completed."));

输出:
1 2 3 4 五 6 完成。

您可以使用主题并在订阅后添加项目(这是一个示例,以显示事件发生的时间/地点):

var subject = new ReplaySubject<string>();
subject.OnNext("7");
subject.Subscribe(n => Console.WriteLine(n), ex => Console.WriteLine(ex.ToString()), () => Console.WriteLine("Completed."));
subject.OnNext("8");
numbers.Subscribe(n => subject.OnNext(n));
subject.OnNext("9");
subject.OnNext("10");

输出: 7 8 1 2 3 4 五 6 9 10

您还询问是否有使用Rx进行后端处理的示例。我敢说这是主要使用的地方,但我没有任何确凿的证据支持这一点。它绝对不仅仅是WPF,还有更广泛的应用程序。它是ObservableCollection,我认为它更像是WPF,因为它用于数据绑定,而ObservableCollection不是Rx的一部分。

希望有所帮助。