Rx:1-Observable
.net的IEnumerable接口是返回IEnumerator,而IEnumerator实现了MoveNext()和获取当前对象等方法。
Observable利用该思想,使用IObservable<T>和IObserver<T>实现Push-Style(推模式),我们常用的IEnumerble可以理解为拉模式或主动模式,那么就需要返回IEnumerator来操作。而推模式正好相反,所以IObserver<T>是作为IObserverable<T>的参数传进去的:
1: public interface IObservable<T>
2: {
3: // Methods
4: IDisposable Subscribe(IObserver<T> observer);
5: }
1: public interface IObserver<T>
2: {
3: // Methods
4: void OnCompleted();
5: void OnError(Exception exception);
6: void OnNext(T value);
7: }
System.Observable.dll里就只有这两个接口的定义。这个接口是定义在System命名空间下的。
Inactive和Reactive是两种思想,前者是基于状态的,后者是基于事件的。基于事件通知的好处就在于线程不用blocking去wait,所以程序的吞吐量会大大增加。换个角度,可以理解为Inactive就是主动的,Reactive就是被动的。
Reactive这种被动模式常被称作Push模式。这么看到,IObservable就是Push的“来源”(外界推力),IObserver就是“要被推到的目标”。两者通过“目标”的主动订阅(Subscribe方法)来结合,当然,“目标”是可以订阅多个“外界作用力的”。
拿一个从1加到100的例子:
1: class Program
2: {
3: /// <summary>
4: /// 该方式直接使用Extension method创建匿名的Observer
5: /// </summary>
6: /// <param name="args"></param>
7: static void Main(string[] args)
8: {
9: var ob1 = new Ob1();
10: ob1.Subscribe(str=>Console.WriteLine(str), ()=>Console.WriteLine("DONE!"));
11:
12: Console.WriteLine("has subscribed...");
13: ThreadPool.QueueUserWorkItem(obj => ob1.DoJob(obj));
14: Console.WriteLine("has started DoJob()\n");
15:
16: Console.ReadLine();
17: }
18:
19: /// <summary>
20: /// 这种方式需要一个Observer来相应
21: /// </summary>
22: private static void Main1()
23: {
24: var theObserver = new TheObserver();
25:
26: var ob1 = new Ob1();
27: var unsubscribeHandler = ob1.Subscribe(theObserver);
28:
29: Console.WriteLine("has subscribed...");
30: ThreadPool.QueueUserWorkItem(obj => ob1.DoJob(obj));
31: Console.WriteLine("has started DoJob()\n");
32:
33: Console.ReadLine();
34: }
35: }
36:
37: public class TheObserver : IObserver<string>
38: {
39: public void OnCompleted()
40: {
41: Console.WriteLine("Completed");
42: }
43:
44: public void OnError(Exception exception)
45: {
46: Console.WriteLine(exception.Message);
47: }
48:
49: public void OnNext(string str)
50: {
51: Console.WriteLine(str);
52: }
53: }
54:
55: public class Ob1 : IObservable<string>
56: {
57: private List<IObserver<string>> observers = new List<IObserver<string>>();
58:
59: public IDisposable Subscribe(IObserver<string> observer)
60: {
61: observers.Add(observer);
62: return new Unsubscribe(observer, p => observers.Remove(p));
63: }
64:
65: public void DoJob(object obj)
66: {
67: var sum = 0;
68: try
69: {
70: for (int i = 0; i < 100; i++)
71: {
72: observers.ForEach(p => p.OnNext((++sum).ToString()));
73: Thread.Sleep(30);
74: }
75: }
76: catch (Exception ex)
77: {
78: observers.ForEach(p=>p.OnError(ex));
79: }
80:
81: observers.ForEach(p=>p.OnCompleted());
82: }
83: }
84:
85: public class Unsubscribe : IDisposable
86: {
87: public IObserver<string> Source { get; set; }
88: public Action<IObserver<string>> DisposeAction { get; set; }
89:
90: public Unsubscribe(IObserver<string> source, Action<IObserver<string>> disposeAction)
91: {
92: this.Source = source;
93: this.DisposeAction = disposeAction;
94: }
95:
96: public void Dispose()
97: {
98: DisposeAction(Source);
99: }
100: }
在System.Reactive.dll里为IObservable<T>提供了如下的扩展方法:
1: public static class ObservableExtensions
2: {
3: // Methods
4: public static IDisposable Subscribe<TSource>(this IObservable<TSource> source);
5: public static IDisposable Subscribe<TSource>(this IObservable<TSource> source, Action<TSource> onNext);
6: public static IDisposable Subscribe<TSource>(this IObservable<TSource> source, Action<TSource> onNext, Action<Exception> onError);
7: public static IDisposable Subscribe<TSource>(this IObservable<TSource> source, Action<TSource> onNext, Action onCompleted);
8: public static IDisposable Subscribe<TSource>(this IObservable<TSource> source, Action<TSource> onNext, Action<Exception> onError, Action onCompleted);
9: }
10:
11:
所以我们更简单的写了:
1: static void Main(string[] args)
2: {
3: var observables = Observable.Interval(TimeSpan.FromMilliseconds(30)).TakeWhile(p => p <= 100);
4: var newObservable = observables.Select(p => --p);
5: observables.Subscribe(p => Console.WriteLine(p));
6: newObservable.Subscribe(c => Console.WriteLine("\t" + c));
7: Thread.Sleep(3000);
8: Console.WriteLine("start");
9: Console.ReadLine();
10: }
这里Line 5的Select方法会在每次生成observables的OnNext的时候调用一次。