0

尽管我不时在我的代码中使用 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”事件。然而,这让我想知道“推送模型”到底是什么。我一直认为“推送模型”意味着一旦数据(集合)订阅了一个事件,所有新添加到该集合的数据也将订阅同一个事件。

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

4

2 回答 2

4

我认为您对 ToObservable 的作用感到困惑 - 基本上,它说“看到这组东西?我想创建一个新的流,将这些值反馈给我。” 它不会以任何有意义的方式“包装”源列表,例如监听未来的变化,它更多的是及时的快照 - 生成的 observable 就是创建 observable 时该列表的样子。

有很多方法可以对集合的“实时视图”进行建模 - 您已经提到过:创建一个 ObservableCollection 并通过写入 CollectionChanged 事件来创建可观察对象。您也可以在此处使用 Subject,尽管它将状态的概念注入 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
于 2013-04-01T22:55:17.733 回答
1

在订阅之前,您可以将 Observables 连接在一起:

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 5 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 5 6 9 10

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

希望有帮助。

于 2013-04-02T13:34:51.533 回答