我有两种不同的事件类型实现相同的接口:
interface InputEvent { }
struct KeyboardEvent : InputEvent { }
struct MouseEvent : InputEvent { }
我有两个流,每个事件类型之一:
IObservable<KeyboardEvent> KeyboardStream;
IObservable<MouseEvent> MouseStream;
我想介绍两者的合并IObservable<InputEvent>
流。起初我希望编译器会自动检测基类:
IObservable<InputEvent> Merged = Observable.Merge(KeyboardStream, MouseStream);
那里没有运气,所以我试着明确:
IObservable<InputEvent> Merged = Observable.Merge<InputEvent>(KeyboardStream, MouseStream);
不,编译器仍然没有得到提示。所以我明确地演绎了每一个:
IObservable<InputEvent> Merged = Observable.Merge<InputEvent>((IObservable<InputEvent>)KeyboardStream, (IObservable<InputEvent>)MouseStream);
呸。并且它在运行时仍然因失败而失败。我想这与协方差有关(我仍然没有完全在第一次尝试时得到它...)所以我会做我将用IEnumerable做的事情,使用{{1} }:
.Cast<T>()
现在编译器告诉我IObservable<InputEvent> Merged = Observable.Merge<InputEvent>(KeyboardStream.Cast<InputEvent>(), MouseStream.Cast<InputEvent>());
仅定义为.Cast<T>()
... 什么?这似乎是一个非常不方便和不必要的限制。
最后我尝试一个简单的选择:
IObservable<Object>
终于成功了!它工作,我可以从它创建自己的简单扩展方法。但是,内置的IObservable<InputEvent> Merged = Observable.Merge(KeyboardStream.Select(i => (InputEvent)i), MouseStream.Select(i => (InputEvent)i));
和.Cast<T>()
运算符在我的嘴里留下了非常糟糕的味道。所以我的问题是:为什么我不能在除.OfType<T>()
之外的任何可观察对象上使用内置.Cast<T>()
扩展名,这几乎是多余的?这是一个协方差问题吗? Rx规范的疏忽?一个刻意的设计决定?
答案 0 :(得分:1)
作为警告,即使这似乎已经解决了,IObservable / IObserver在所有平台上都不是协变的 - 具体来说,WP7和Silverlight决定从接口声明中删除协方差。
答案 1 :(得分:1)
这里的问题是我的事件类型是struct
,因此不会自动装箱到Object。将类型更改为class
就可以了。