首页 > 解决方案 > 如何为遗留相机系统创建 Observable?

问题描述

我有一个旧的相机客户端来与相机通信。它的工作方式在当时有点尴尬。作为我自己的“反应式”东西的粉丝,我想以反应式的方式与相机交流。

它是这样运作的

每当您想开始捕获帧时,您调用Start并开始每 0.5 秒捕获一个帧,并且您会在订阅“on capture”事件的每个帧上收到通知。该事件一直在引发,直到您调用Stop为止。

因此,相机具有:

这就是我要的

我想将相机封装成一个更方便的抽象,其中 Start 和 Stop 方法被替换为 anIObservable<bool>并且生成的 observable 应该发出批量捕获(Frames)。

更多细节

这是传统的相机类:

class Camera 
{
    void StartRecording();
    void StopRecording();
    public event CaptureEventHandler OnCapture;
    public delegate void CaptureEventHandler(Camera sender, Frame capture);
}

我想要的是创建将相机包装成这样的类(我只创建了骨架):

public class ObservableCamera 
{
      public ObservableCamera(Camera camera, IObservable<bool> enableCapture)
      { 
          // TODO: Define the 'Captures' observable using the parameters above
      }

      IObservable<Frame[]> Captures { get; }
}

当 enableCapture 可观察对象发出 a 时,相机应该开始捕捉帧,true并且在它按下时应该停止捕捉false

为了澄清一点,这是显示交互的大理石图:

在此处输入图像描述

除此之外,无论何时启动 Start操作,也应在可观察对象终止或失败StopRecording时调用。enableCapture

那么,我要问什么?

我收到评论说我的目标不明确。为了澄清它,这是我的问题:

我应该如何实现 observable 来处理旧相机?我不知道如何开始。

标签: c#.netreactive-programmingsystem.reactive

解决方案


这是一种方法,它使用Window运算符来定义启用相机时的窗口(周期)。该Camera.OnCapture事件在每个窗口开始时被订阅,在窗口结束时被取消订阅。

Camera camera;
IObservable<bool> enableCapture;

IObservable<Frame[]> observableCamera = enableCapture
    .DistinctUntilChanged()
    .Publish(published => published
        .Window(published.Where(enabled => enabled), _ => published.Where(enabled => !enabled))
        .Select(w =>
            Observable
                .FromEvent<Camera.CaptureEventHandler, Frame>(
                    h => (sender, capture) => h(capture),
                    h =>
                    {
                        camera.OnCapture += h;
                        camera.StartRecording();
                    },
                    h =>
                    {
                        camera.StopRecording();
                        camera.OnCapture -= h;
                    })
                .TakeUntil(w.LastOrDefaultAsync())
                .ToArray()
        )
        .Concat()
    );

DistinctUntilChanged运算符用于忽略连续的真或假。使用Publish运算符是为了避免多次订阅该enableCapture序列。这个序列很可能是一个Subject<bool>,所以已经很热了,这使得它Publish本质上是多余的,但原则上避免多个订阅是好的。

没有注意该方法StartRecording或该StopRecording方法失败的情况。在这种情况下,对该事件的订阅OnCapture将被泄露。


推荐阅读