尽管我在代码中不时地使用Observable和Rx,但我仍然有这个关于"push model"及其使用的问题。
例如,假设我有这样一个简单的代码: 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,视图模型驱动的实现,我想知道是否有人将它用于任何后端处理,典型的例子是什么?
我想你是混淆了ToObservable做什么-基本上,它说"看到这组东西吗?我想创造一种新的流,将这些价值反馈给我。"它不会以任何有意义的方式"包装"源列表,比如监听未来的变化,它更像是一个及时的快照——生成的可观察对象是可观察对象创建时列表的样子。
有很多方法可以为一个集合的"实时视图"建模——你提到过的一种:创建一个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
您可以在订阅之前将可观察对象连接在一起:
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."));
输出:123.456完成。
你可以使用Subject并在Subscription后面添加条目(这里有一个示例来显示事情发生的时间/地点):
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");
输出:78123.456910
您还询问是否有使用Rx进行后端处理的示例。我敢说这是它的主要用途,但我没有任何确凿的证据来支持这一点。它绝对不仅仅是WPF,还有更广泛的应用。它是ObservableCollection,这更多的是WPF的事情,我相信,因为它用于数据绑定和ObservableCollection不是Rx的一部分。
希望对你有帮助。