在c#中实现反应式编程/函数
最近我正在阅读关于游戏引擎设计的书籍,最终终于绊倒了这一点:什么是(功能性)反应式编程?
我想知道如何实现第二个最高评分答案中给出的例子。 在C ++中,将指针传递给存储鼠标坐标的值很容易,只是返回值而不是int。 那么,我们不能在C#中真正做到这一点,所以我们的第一个问题。 我们是否需要调用一些“更新”功能来保持所有值都是最新的?
其次是如何处理语法? 分配值很简单。 但做每次我要求的时候,“从我们这里得到鼠标位置和分钟14”稍微多一点。
最后,我想知道如何让C#中的任何对象直接引用时返回一个值。 例如
int test = 1;
测试会返回1.所以我可以做1 +测试这样会= 2的事情
但如果我有一个实例
public class ReactiveInt {
int myValue
}
当我尝试将int加在一起时,我不能只做我上面做的事情。
对不起,我想这样一个广泛的问题。 如果可以给出一个简单的例子来演示与该答案中讨论的功能类似的功能,那么我认为我的所有问题都将得到解答。
问题
问题1
当我尝试将int加在一起时,我不能只做我上面做的事情。
那么,那其实就是重点。 在反应式编程中,您不希望强制性地将两个数字相加,而是要根据其他数字定义新数字。 因此,即使当a
或b
变化时, c = a + b
,这样的c
总是等于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];
});
问题2
我想知道如何实现第二个最高评分答案中给出的例子。
Haskell中最简单的答案列表和更高级的函数。
你不希望功能反应性编程违背了你在命令式编程中学到的一切,如果你想做纯粹的功能性反应式编程,你将不得不重新学习如何做。 如果你不这样做,你最终会制作各种类型的依赖性跟踪库,比如KnockoutJS,当你可以用RxJS-Splash这样的几百行代码做同样的事情时,如果你用FRP开头的话。 (注意Splash是如何基于Rx的,它是可重用的代码,Knockout是纯粹的实现特定的代码)。
FRP具有事件和时间的概念,而依赖关系跟踪仅具有值和变化的概念。 功能反应式代码一直与命令式代码一样长。 它不是“建立在命令式代码之上”。 (是的,它仍然是汇编......不是重点),它在概念上有着根本性的不同。
例
使用Microsoft的Reactive Extensions for JavaScript(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);
});
简化的端口
由于矩形只能根据一个相关值(或事件)定义,因此可以将其简化为以下内容:
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);
});
使用它
在这一点上,您可以使用它来组合其他可观察序列(随时间变化的值)。
var area = boundingRect.map(function(rect) {
return rect.getSize();
});
或者直接订阅。
boundingRect.subscribe(function (rect) {
// perform some action with the rect each time it changes.
console.log(rect);
});
但只有当它发生变化时!
如果我们在订阅后立即需要最新的价值,而不必等待矩形再次改变,那该怎么办? 那么这就是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));
但那不是最初的可观察的,它不是很实用......
以下是如何使用一些内置的功能将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
})
再次,FRP是不同的。 这很不一样,但这是一个很大的学习任务。 你会知道你已经开始获得它,当它开始打搅你的头脑。
看看微软反应扩展(Rx)
使用Lambdas和Actions作为事件处理程序,您可以在没有指针的情况下离开。
int Offset = 16;
int Size = Offset * 2;
Action<MouseEventArgs> MouseEventArgsHandler = (args) => DrawRectangle(args.x - Offset, args.y - Offset, Size, Size);
链接地址: http://www.djcxy.com/p/47725.html
上一篇: Implementing reactive programming/functions in c#
下一篇: Is Reactive Programming bounded to Functional programming?