我正在尝试使用IObservable
包装设备类。没有Rx就像这样使用:
device.IncomingData += data => { /* do something with float[] data */ };
device.Start(500);
// Something...
device.Stop();
到目前为止,我有一个类似下面的包装器类,它跟踪有多少观察者正在使用流并停止并相应地启动它。
是否没有内置的方法来跟踪Rx的观察者?
private class ObservableWrapper
{
private int _observers;
public ObservableStreamer(IDevice device)
{
Stream = Observable.FromEvent<float[]>(
e =>
{
device.IncomingData += e;
int obs = Interlocked.Increment(ref _observers);
if (obs < 2)
device.Start();
},
e =>
{
device.IncomingData -= e;
int obs = Interlocked.Decrement(ref _observers);
if (obs < 1)
device.Stop();
});
}
public IObservable<float[]> Stream { get; private set; }
}
var wrap = new ObservableWrapper(device);
wrap.Stream.Subscribe(data => { /* do something with float[] data */ });
答案 0 :(得分:3)
构建自定义observable时,不要费心添加引用计数或连接共享。如果您需要这些功能,可以分别使用RefCount
和Publish
添加这些功能。您自己也应该几乎没有理由自己实施I(Connectable)Observable
。
至于您的具体用例,它可能是一个相当简单的扩展方法:
public static DeviceExtensions
{
public static IObservable<float[]> AsObservable(this Device device)
{
return Observable.CreateWithDisposable<float[]>(obs =>
{
IDisposable disposable = Observable.FromEvent<float[]>(
e => device.IncomingData += e,
e => device.IncomingData -= e
)
.Finally(device.Stop)
.Subscribe(obs);
device.Start();
return disposable;
});
}
}
现在你可以像这样使用它:
IObservable<float[]> observableData = device.AsObservable()
.RefCount(); // If you need ref counting
observableData.Subscribe(data => {});
observableData.Subscribe(data => {});
答案 1 :(得分:2)
听起来你实际上映射的更好地使用较少的IConnectableObservable。 Connect方法将调用Start并返回一个调用Stop的一次性用法。 Subscribe方法将转发到Observable.FromEvent(没有所有引用计数)。然后,您可以使用RefCount将其重新转换为常规IObservable。与您当前的实现一样,您必须对所有订阅使用相同的实例,否则计数将无法正常工作。
例如(未编译的代码传入):
class ObservableDevice : IConnectableObservable
{
public ObservableDevice(IDevice device)
{
_device = device;
//not strictly necessary to cache this, but this way you only
//create it once
_stream = Observable.FromEvent<...>(...);
}
private IDevice _device;
private IObservable _stream;
public IDisposable Connect()
{
//it's up to you if you want/need to guard against multiple starts
_device.Start();
return Disposable.Create(() => { _device.Stop(); });
}
public IDisposable Subscribe(IObserver observer)
{
//error checking if you want, or just defer to
//_stream.Subscribe's error checking
return _stream.Subscribe(observer);
}
}