Pro*_*gga 7 c# reactive-programming
我最近正在阅读有关游戏引擎设计的内容,并最终绊倒了这个:什么是(功能)反应式编程?
我想知道如何实现第二个最高评级答案中给出的例子.在C++中,很容易将指针传递给存储鼠标坐标的值,只返回值而不是int.好吧,我们不能在C#中真正做到这一点,所以这是我们的第一个问题.我们是否需要调用一些"更新"功能来保持所有值都是最新的?
其次,如何处理语法?分配值是直截了当的.但是,每当我要求它时,做"让鼠标定位并从中获取14分钟"的事情稍微复杂一点......
最后,我想知道如何直接引用C#中的任何对象返回一个值.例如
int test = 1;
Run Code Online (Sandbox Code Playgroud)
测试将返回1.所以我可以做1 + test这样的事情= 2
但如果我有一个实例
public class ReactiveInt {
int myValue
}
Run Code Online (Sandbox Code Playgroud)
在尝试将int添加到一起时,我不能只做我上面做的事情.
对不起,我想这是一个广泛的问题.如果可以给出一个简单的例子来演示类似于答案中讨论的功能,我想我的所有问题都会得到解答.
问题1
在尝试将int添加到一起时,我不能只做我上面做的事情.
嗯,这实际上就是重点.在反应式编程中,您不希望强制性地将两个数字相加,而是希望根据其他数字定义新数字.因此,c = a + b例如c是始终等于a + b,即使当a或b改变:c在相对于反应性是a和b.
var a = new BehaviorSubject(3);
var b = new BehaviorSubject(1);
var c = Rx.Observable.combineLatest(a, b, function(vals) {
return vals[0] + vals[1];
});
Run Code Online (Sandbox Code Playgroud)
问题2
我想知道如何实现第二个最高评级答案中给出的例子.
haskell中最简单的答案列表和高阶函数.
答你不想功能反应编程违背你的命令式编程学到的一切,而你将不得不重新学习如何做,如果你想要做的纯功能型反应式编程的东西.如果你不这样做,你最终会制作各种依赖性跟踪库,比如KnockoutJS,如果你用RxJS-Splash之类的东西在几百行中做同样的事情,如果你用FRP开始.(注意Splash是如何基于Rx的,它是可重用的代码,而Knockout是纯粹的特定于实现的代码).
FRP具有事件和时间的概念,而依赖性跟踪仅具有值和变化的概念.功能反应代码与命令式代码一样长.它不是"建立在命令式代码之上".(是的,它仍然汇编到汇编......而不是重点),它在概念上有根本的不同.
使用Microsoft的JavaScript Reactive Extensions(RxJS)
请记住,Rx现在有很多种语言版本,包括原生C++.
直接端口示例
var moves = $(document).onAsObservable('mousemove')
.map(function(e) {
return {
x: e.pageX,
y: e.pageY
};
});
var xs = moves.map(function(move) { return move.x; });
var ys = moves.map(function(move) { return move.y; });
var minXs = xs.map(function(x) { return x - 16; });
var minYs = ys.map(function(y) { return y - 16; });
var maxYs = xs.map(function(x) { return x + 16; });
var maxYs = ys.map(function(y) { return y + 16; });
var boundingRect = Rx.Observable.combineLatest(minXs, minYs, maxXs, maxYs)
.map(function(vals) {
var minX = vals[0];
var minY = vals[1];
var maxX = vals[2];
var maxY = vals[3];
return new Rectangle(minX, minY, maxX, maxY);
});
Run Code Online (Sandbox Code Playgroud)
简化端口
由于矩形仅根据一个相关值(或事件)定义,因此您可以将其简化为以下内容:
var boundingRect = $(document).onAsObservable('mousemove')
.map(function(e) {
var x = e.pageX;
var y = e.pageY;
return new Rectangle(x - 16, y - 16, x + 16, y + 16);
});
Run Code Online (Sandbox Code Playgroud)
使用它
此时,您可以使用它来组成其他可观察序列(随时间变化的值).
var area = boundingRect.map(function(rect) {
return rect.getSize();
});
Run Code Online (Sandbox Code Playgroud)
或直接订阅.
boundingRect.subscribe(function (rect) {
// perform some action with the rect each time it changes.
console.log(rect);
});
Run Code Online (Sandbox Code Playgroud)
但那只是在它改变的时候!
如果我们在订阅时想要获得最新值,而不是等待矩形再次更改,该怎么办?嗯,这就是BehaviorSubject进来的地方.
var rects = new Rx.BehaviorSubject(new Rectangle(-1, -1, 1, 1));
rects.subscribe(function(rect) {
// this would happen twice in this example.
// Once for the initial value (above), and once when it is changed later (below).
console.log(rect);
});
rects.onNext(new Rectangle(-1, -1, 1, 1));
Run Code Online (Sandbox Code Playgroud)
但这不是原始的可观察性,而且它不是很实用......
以下是如何使用原始的observable使用一些内置功能将Observable更改为像BehaviorSubject这样的行为...
var rectsAndDefault = rects.startWith(new Rectangle()); // just give it an initial value
rectsAndDefault.subscribe(function(rect) {
console.log(rect); // happens once for the "startWith" rectangle, and then again for all subsequent changes
})
Run Code Online (Sandbox Code Playgroud)
再次,FRP是不同的.它有很大的不同,但这是一项值得学习的大事.当你开始思考时,你会知道你已经开始得到它了.
使用 Lambda 和 Actions 作为事件处理程序,您无需指针即可摆脱困境。
int Offset = 16;
int Size = Offset * 2;
Action<MouseEventArgs> MouseEventArgsHandler = (args) => DrawRectangle(args.x - Offset, args.y - Offset, Size, Size);
Run Code Online (Sandbox Code Playgroud)