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?

+3


source share


2 answers


The problem was that my event types were struct

and therefore were not automatically bound to the object. Changing types class

didn't do the trick.



+1


source


As a warning, although this seems to be resolved, IObservable / IObserver is not covariant on all platforms - in particular, WP7 and Silverlight decided to strip covariance from the interface declaration.



+1


source







All Articles