IObservable .Cast<>()和协方差

时间:2013-01-30 20:26:14

标签: c# system.reactive covariance

我有两种不同的事件类型实现相同的接口:

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规范的疏忽?一个刻意的设计决定?

2 个答案:

答案 0 :(得分:1)

作为警告,即使这似乎已经解决了,IObservable / IObserver在所有平台上都不是协变的 - 具体来说,WP7和Silverlight决定从接口声明中删除协方差。

答案 1 :(得分:1)

这里的问题是我的事件类型是struct,因此不会自动装箱到Object。将类型更改为class就可以了。