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的时候调用一次。
posted @ 2010-05-29 19:59  new 维生素C.net()  阅读(1759)  评论(1编辑  收藏  举报