本文发表在 rolia.net 枫下论坛聊聊Rective Extention(Rx)
Rx的出现也是为了简化异步编程,但是初学者会发现至少从写法来看,Rx好像并没有减少多少代码量,这也确实是事实。俺的理解是,Rx的出现所带来的最大好处是使得异步编程LINQ化,也就是说,程序员可以用LINQ语法来操作一系列的异步事件,这个好处是巨大的,LINQ的出现使得以前成百上千行代码变得只是弹指一挥间。这也是为什么在网上一提到Rx,总是会跟着Linq
举个例子,比如,一个WPF Program,一个鼠标在屏幕上乱画,我想在这个鼠标的X坐标超出100的时候在屏幕上显示这个坐标,小于100则不显示,用普通的Event方法:
private void Form1_Load(object sender, EventArgs e)
{
this.MouseMove += (s, args) =>
{
if(args.Location.X > 100)
this.label1.Text = args.Location.ToString();
};
}
用Rx:
private void Form1_Load(object sender, EventArgs e)
{
Observable.FromEventPattern<MouseEventArgs>(this, "MouseMove")
.Where(s => s.EventArgs.X > 100)
.Subscribe(s => this.label1.Text = s.EventArgs.Location.ToString());
}
可以看出Rx把鼠标的”MouseMove”事件当作一连串Events Collection发送出来,然后由一个Where(.. 进行过滤,只把X > 100的Event继续向下发送,最终到了Subscribe(.. 这些Event算是到头了,开始由里面的函数进行实际的处理。逻辑很清晰,虽然写法上不见的比传统的例子省多少代码,但这只是因为我的例子太过渺小,如果其中逻辑比较复杂,能看出Rx的写法会更有效率,也更清晰,便于维护
现在,把这个例子变得复杂一些吧,我想在鼠标停止0.5秒之后再更新label1.Text的内容,而不是每时每刻的更新,用Rx的话:
Observable.FromEventPattern<MouseEventArgs>(this, "MouseMove")
.Where(s => s.EventArgs.X > 100)
.Throttle(TimeSpan.FromSeconds(0.5))
.ObserveOn(this)
.Subscribe(s => this.label1.Text = s.EventArgs.Location.ToString());
就加了2行
.Throttle(TimeSpan.FromSeconds(0.5)) // 用于让系统等待0.5秒,如果这0.5秒之内没有新的MouseMove event coming,则把当前的Event往下传递到 .ObserveOnDispatcher()
.ObserveOn(this) // 是必须的,因为又一次涉及到跨线程操作
同样的功能如果由传统的Event操作来写,不知道要复杂多少,至少要用到一个Timer,还要监测Timer.Internvel event,太可怕了
继续,让事情变得更复杂一些,我想在每次鼠标每停留2次(或者n次,无所谓)以上的时候显示这n次分别停留了哪几个坐标点?
Rx程序如下:
Observable.FromEventPattern<MouseEventArgs>(this, "MouseMove")
.Where(s => s.EventArgs.X > 100)
.Throttle(TimeSpan.FromSeconds(0.5))
.Buffer(2)
.ObserveOn(this)
.Subscribe(s => this.label1.Text = s.Select(x => x.EventArgs.Location.ToString()).Aggregate((a, b) => a + ", " + b));
这功能如果用传统方法写….算了,想也不愿意去想
Rx这个东西,对初学者有些晦涩,类似于理解async await之前需要先了解Task。Rx的核心是两个Interface
IObservable<T>
IObserver<T>
吃饭… 回来再写更多精彩文章及讨论,请光临枫下论坛 rolia.net
Rx的出现也是为了简化异步编程,但是初学者会发现至少从写法来看,Rx好像并没有减少多少代码量,这也确实是事实。俺的理解是,Rx的出现所带来的最大好处是使得异步编程LINQ化,也就是说,程序员可以用LINQ语法来操作一系列的异步事件,这个好处是巨大的,LINQ的出现使得以前成百上千行代码变得只是弹指一挥间。这也是为什么在网上一提到Rx,总是会跟着Linq
举个例子,比如,一个WPF Program,一个鼠标在屏幕上乱画,我想在这个鼠标的X坐标超出100的时候在屏幕上显示这个坐标,小于100则不显示,用普通的Event方法:
private void Form1_Load(object sender, EventArgs e)
{
this.MouseMove += (s, args) =>
{
if(args.Location.X > 100)
this.label1.Text = args.Location.ToString();
};
}
用Rx:
private void Form1_Load(object sender, EventArgs e)
{
Observable.FromEventPattern<MouseEventArgs>(this, "MouseMove")
.Where(s => s.EventArgs.X > 100)
.Subscribe(s => this.label1.Text = s.EventArgs.Location.ToString());
}
可以看出Rx把鼠标的”MouseMove”事件当作一连串Events Collection发送出来,然后由一个Where(.. 进行过滤,只把X > 100的Event继续向下发送,最终到了Subscribe(.. 这些Event算是到头了,开始由里面的函数进行实际的处理。逻辑很清晰,虽然写法上不见的比传统的例子省多少代码,但这只是因为我的例子太过渺小,如果其中逻辑比较复杂,能看出Rx的写法会更有效率,也更清晰,便于维护
现在,把这个例子变得复杂一些吧,我想在鼠标停止0.5秒之后再更新label1.Text的内容,而不是每时每刻的更新,用Rx的话:
Observable.FromEventPattern<MouseEventArgs>(this, "MouseMove")
.Where(s => s.EventArgs.X > 100)
.Throttle(TimeSpan.FromSeconds(0.5))
.ObserveOn(this)
.Subscribe(s => this.label1.Text = s.EventArgs.Location.ToString());
就加了2行
.Throttle(TimeSpan.FromSeconds(0.5)) // 用于让系统等待0.5秒,如果这0.5秒之内没有新的MouseMove event coming,则把当前的Event往下传递到 .ObserveOnDispatcher()
.ObserveOn(this) // 是必须的,因为又一次涉及到跨线程操作
同样的功能如果由传统的Event操作来写,不知道要复杂多少,至少要用到一个Timer,还要监测Timer.Internvel event,太可怕了
继续,让事情变得更复杂一些,我想在每次鼠标每停留2次(或者n次,无所谓)以上的时候显示这n次分别停留了哪几个坐标点?
Rx程序如下:
Observable.FromEventPattern<MouseEventArgs>(this, "MouseMove")
.Where(s => s.EventArgs.X > 100)
.Throttle(TimeSpan.FromSeconds(0.5))
.Buffer(2)
.ObserveOn(this)
.Subscribe(s => this.label1.Text = s.Select(x => x.EventArgs.Location.ToString()).Aggregate((a, b) => a + ", " + b));
这功能如果用传统方法写….算了,想也不愿意去想
Rx这个东西,对初学者有些晦涩,类似于理解async await之前需要先了解Task。Rx的核心是两个Interface
IObservable<T>
IObserver<T>
吃饭… 回来再写更多精彩文章及讨论,请光临枫下论坛 rolia.net