带引号的块文本在很大程度上解释了为什么不应该使用Subject<T>
,但是为了简化起见,您将观察者和可观察的功能结合在一起,同时在两者之间注入某种状态(无论是封装还是扩展)。
这是您遇到麻烦的地方;这些责任应该是分开的并且彼此不同。
也就是说,在您的特定情况下,我建议您将您的担忧分解为较小的部分。
首先,您的线程很热,并且始终监视硬件是否有信号来发出通知。您通常会如何做? 大事记。因此,让我们开始吧。
让我们定义EventArgs
您的事件将触发。
// The event args that has the information.
public class BaseFrameEventArgs : EventArgs
{
public BaseFrameEventArgs(IBaseFrame baseFrame)
{
// Validate parameters.
if (baseFrame == null) throw new ArgumentNullException("IBaseFrame");
// Set values.
BaseFrame = baseFrame;
}
// Poor man's immutability.
public IBaseFrame BaseFrame { get; private set; }
}
现在,将触发事件的类。请注意,这可能是一个静态类(因为你总是有一个线程中运行监控硬件缓存),或调用的按需订用的东西说。您必须对此进行适当的修改。
public class BaseFrameMonitor
{
// You want to make this access thread safe
public event EventHandler<BaseFrameEventArgs> HardwareEvent;
public BaseFrameMonitor()
{
// Create/subscribe to your thread that
// drains hardware signals.
}
}
因此,现在您有了一个公开事件的类。观察值与事件配合良好。如此之多,以至于IObservable<T>
如果您遵循标准事件模式,通过类上的静态FromEventPattern
方法,将一流的支持将事件流(将事件流视为一个事件的多次触发)转换为实现Observable
。
使用事件的源和FromEventPattern
方法,我们可以IObservable<EventPattern<BaseFrameEventArgs>>
轻松地创建一个EventPattern<TEventArgs>
类(该类体现了您在.NET事件中看到的内容,尤其是从NET派生的实例EventArgs
和代表发送者的对象),如下所示:
// The event source.
// Or you might not need this if your class is static and exposes
// the event as a static event.
var source = new BaseFrameMonitor();
// Create the observable. It's going to be hot
// as the events are hot.
IObservable<EventPattern<BaseFrameEventArgs>> observable = Observable.
FromEventPattern<BaseFrameEventArgs>(
h => source.HardwareEvent += h,
h => source.HardwareEvent -= h);
当然,您想要一个IObservable<IBaseFrame>
,但这很简单,使用类上的Select
扩展方法Observable
来创建投影(就像您在LINQ中一样,我们可以将所有这些包装在一个易于使用的方法中):
public IObservable<IBaseFrame> CreateHardwareObservable()
{
// The event source.
// Or you might not need this if your class is static and exposes
// the event as a static event.
var source = new BaseFrameMonitor();
// Create the observable. It's going to be hot
// as the events are hot.
IObservable<EventPattern<BaseFrameEventArgs>> observable = Observable.
FromEventPattern<BaseFrameEventArgs>(
h => source.HardwareEvent += h,
h => source.HardwareEvent -= h);
// Return the observable, but projected.
return observable.Select(i => i.EventArgs.BaseFrame);
}