3

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

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 做的事情,使用.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>()运算符在我的嘴里留下了非常糟糕的味道。所以我的问题是:为什么我不能在任何 observable 上使用内置.Cast<T>()扩展,除了Object它几乎是多余的?这是协方差问题吗?Rx 规范中的疏忽?一个深思熟虑的设计决定?

4

2 回答 2

1

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

于 2013-01-31T00:55:18.827 回答
1

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

于 2013-01-31T19:41:37.537 回答