引用块文本已经解释了为什么你不应该使用
Subject<T>
,简单来说,你正在将观察者和可观察者的功能结合在一起,并在它们之间注入某种状态(无论是封装还是扩展)。
这就是你遇到麻烦的地方;这些职责应该是彼此分离和明确的。
话虽如此,在你的
具体情况下,我建议你将你的关注点分成更小的部分。
首先,你有一个始终监视硬件信号以引发通知的热线程。你通常会如何做呢?
Events。所以让我们从那里开始。
让我们定义你的事件将触发的
EventArgs
。
public class BaseFrameEventArgs : EventArgs
{
public BaseFrameEventArgs(IBaseFrame baseFrame)
{
if (baseFrame == null) throw new ArgumentNullException("IBaseFrame");
BaseFrame = baseFrame;
}
public IBaseFrame BaseFrame { get; private set; }
}
现在,将触发事件的类。请注意,这可以是静态类(因为始终有一个线程运行以监视硬件缓冲区),或者是您按需调用并订阅的东西。您需要根据需要进行修改。
public class BaseFrameMonitor
{
public event EventHandler<BaseFrameEventArgs> HardwareEvent;
public BaseFrameMonitor()
{
}
}
现在您有一个公开事件的类。可观察对象与事件配合得很好。如果您遵循标准事件模式,通过
Observable类上的
静态FromEventPattern
方法将事件流(将事件流视为多次触发事件)转换为
IObservable<T>
实现,就可以轻松完成。有了事件源和
FromEventPattern
方法,我们可以轻松创建
IObservable<EventPattern<BaseFrameEventArgs>>
(
EventPattern<TEventArgs>
类体现了.NET事件中所见到的内容,特别是从
EventArgs
派生的实例和表示发送方的对象),如下所示:
var source = new BaseFrameMonitor();
IObservable<EventPattern<BaseFrameEventArgs>> observable = Observable.
FromEventPattern<BaseFrameEventArgs>(
h => source.HardwareEvent += h,
h => source.HardwareEvent -= h);
当然,您希望有一个
IObservable<IBaseFrame>
,但这很容易,使用
Observable
类上的
Select
扩展方法 创建一个投影(就像在 LINQ 中一样),我们可以将所有这些包装在一个易于使用的方法中:
public IObservable<IBaseFrame> CreateHardwareObservable()
{
var source = new BaseFrameMonitor();
IObservable<EventPattern<BaseFrameEventArgs>> observable = Observable.
FromEventPattern<BaseFrameEventArgs>(
h => source.HardwareEvent += h,
h => source.HardwareEvent -= h);
return observable.Select(i => i.EventArgs.BaseFrame);
}