何为Reactive Extensions(Rx)
Rx是一个遵循函数式编程的类库,它引用观察者以及迭代器设计模式对可观察对象产生的数据进行异步消费。使用Rx,开发人员将使用LINQ运算符操作异步数据流,并使用调度程序参数化异步数据流中的并发性,简单地说,Rx = Observables + LINQ + Schedulers。
使用Rx需要Nuget安装System.Reactive Nuget包
Rx的使用场景
响应式UI
UI界面上,用户对一个绑定数据集合的控件进行关键字查询。常规的流程是我们必须在等待用户键盘按下指定的完成键(如回车)或鼠标点击查询按钮后程序才开始执行相应的查询处理。但假设需求变更:“用户希望在每输入一个关键字后就能及时将关键字相应的查询结果集绑定到控件” 如果面临这个需求,那你会如何实现呢? 你会少不了定义相应的全局状态字段,少不了相应的时间间隔刷新。我相信写出来的代码也会让你很烦恼。 其实你有更好的选择,那就是我们的主角Rx。
Rx 核心
Rx有两个核心接口 IObservable
IObservable
先来看此接口的结构:
public interface IObservable
{
IDisposable Subscribe(IObserver observer);
}
IObservable
我们可以将IObservable
通过可接口签名可以看出被观察者需要输出T类型的对象。需要理解被观察者IObservable
我想我们都使用过Linq,操作过IEnumerable
下面这个表格可以看出两者区别
IEnumerable | 可在方便时列举元素值 |
---|---|
IObservable | 可观察对象变动的值 |
IObserver
IObserver
通俗理解就是被观察者生成数据,观察者消费数据。
来看下IObserver
public interface IObserver
{
void OnNext(T value);
void OnError(Exception error);
void OnCompleted();
}
- OnNext 表示消费新数据
- OnError 表示观察数据流出现异常
- OnCompleted 表示明确关闭观察数据流
代码示例
下面代码定义了一个可观察的队列,该队列会提供给观察者三个int类型的入参 1、2、3 供观察者对象的OnNext方法消费。 MyConsoleObserver(观察者)在得到数据后打印出来。
///
/// 自定义观察者对象
///
///
public class MyConsoleObserver : IObserver
{
public void OnNext(T value)
{
Console.WriteLine("接收到 value {0}", value);
}
public void OnError(Exception error)
{
Console.WriteLine("出现异常! {0}", error);
}
public void OnCompleted()
{
Console.WriteLine("关闭观察行为");
}
}
///
/// 自定义被观察队列
///
public class MySequenceOfNumbers : IObservable
{
public IDisposable Subscribe(IObserver observer)
{
observer.OnNext(1);
observer.OnNext(2);
observer.OnNext(3);
observer.OnCompleted();
return Disposable.Empty;
}
}
////调用
static void Main(string[] args)
{
Test();
}
private static void Test()
{
var numbers = new MySequenceOfNumbers();
var observer = new MyConsoleObserver();
numbers.Subscribe(observer);
Console.ReadLine();
}
通过示例代码我们得知了Rx.Net的数据流订阅、消费流程。
Subject
我们再来认识下Subject
看这继承关系,我们继续看SubjectBase
哎呀,这个类真不得了啊,把IObserver
我们来看看Subject
private static void SubjectTest()
{
//定义一个 类型string的Subject对象
var inputs = new Subject();
//订阅数据流
inputs.Subscribe((p => Console.WriteLine($"得到的值:{p}")));
//循环造数据
for (int i = 0; i < 4; i++)
{
inputs.OnNext($"时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}, 下标:{i}");
}
Console.ReadLine();
}
执行结果如下图:
需要注意的是订阅方法需要在数据生成前声明。
总结
好啦,要睡觉啦,基本上Rx核心的几个点就先讲到这,我们也来总结下Rx.Net的几个核心知识点:
- 可观察(被观察)对象生产数据;
- 观察者总是被动接收数据;
- 需要明确订阅后观察者才得以消费数据;
这里也只是自己的一个学习总结,Rx也不是眼前的几个小示例就可以一目了然,不过核心的知识基本上就是这些。至于还有一些操作符的话相信用过Linq的话上手不难,难点在于需要在实际业务中找到合适的场景使用,只有不断使用才会融会贯通。但是任何技术都不能滥用,每一项新技术都有它最佳使用场景,优秀的开发者需要做好权衡。