IObservable.Cast <> () and covariance
I have two different types of events that implement the same interface:
interface InputEvent { } struct KeyboardEvent : InputEvent { } struct MouseEvent : InputEvent { }
I have two streams, one of each type of event:
IObservable<KeyboardEvent> KeyboardStream; IObservable<MouseEvent> MouseStream;
I would like to introduce a merged stream IObservable<InputEvent>
for both. At first I was hoping that the compiler would automatically detect the base class:
IObservable<InputEvent> Merged = Observable.Merge(KeyboardStream, MouseStream);
No luck, so I tried to be explicit:
IObservable<InputEvent> Merged = Observable.Merge<InputEvent>(KeyboardStream, MouseStream);
No, the compiler doesn't get hints anyway. So I throw each one explicitly:
IObservable<InputEvent> Merged = Observable.Merge<InputEvent>((IObservable<InputEvent>)KeyboardStream, (IObservable<InputEvent>)MouseStream);
Ugh. And it still fails at runtime with a failure. I'm guessing it has to do with covariance (I still haven't fully figured it out on my first try ...), so I'll do what I would do with IEnumerable, use .Cast<T>()
:
IObservable<InputEvent> Merged = Observable.Merge<InputEvent>(KeyboardStream.Cast<InputEvent>(), MouseStream.Cast<InputEvent>());
Now the compiler tells me what .Cast<T>()
is defined only for IObservable<Object>
... What? This seems like a rather awkward and unnecessary restraint.
Finally, I'll try a simple choice:
IObservable<InputEvent> Merged = Observable.Merge(KeyboardStream.Select(i => (InputEvent)i), MouseStream.Select(i => (InputEvent)i));
Success finally! It works and I can create my own simple extension method. However, the built-in operators .Cast<T>()
and .OfType<T>()
left in my mouth a rather unpleasant taste. So my question is , why can't I use inline extension .Cast<T>()
for any observable other thanObject
which is pretty much redundant? Is it a question of covariance? Rx specification oversight? An intentional design decision?
source share