How to properly observe non-standard events?
I'm new to Reactive Extensions and I'm dealing with a COM library that has events defined like this:
public delegate void MyDelegate(int requestId, double price, int amount);
public event MyDelegate MyEvent;
How to observe it correctly? I tried to use Observable.FromEvent()
, but since the event parameters are not type-specific EventArgs
, I don't see how FromEvent()
or would work FromEventPattern()
.
My current workaround is to attach a custom delegate to the event, then call Subject.OnNext()
, but I guess that's not how I should be doing it.
Here's an example of my current workaround:
MyEvent += new MyDelegate((int requestId, double price, int amount) =>
{
Task.Run(() =>
{
var args = new MyArgs()
{
requestId = requestId,
price = price,
amount = amount,
};
this.mySubject.OnNext(args);
});
});
source to share
There is a special overload for it FromEvent
. It's a bit dumb to put your head down, but the function signature looks like this:
IObservable<TEventArgs> FromEvent<TDelegate, TEventArgs>(Func<Action<TEventArgs>, TDelegate> conversion, Action<TDelegate> addHandler, Action<TDelegate> removeHandler);
The conversion function is the important part here, basically you are telling Rx how your delegate maps to a specific type.
In your script, it looks something like this:
Observable.FromEvent<MyDelegate, MyArgs>(
converter => new MyDelegate(
(id, price, amount) => converter(new MyArgs {
RequestId = id,
Price = price,
Amount = amount
})
),
handler => MyEvent += handler,
handler => MyEvent -= handler);
So what does it all do? Internally, it is similar to what you are doing (I will paraphrase what it does conceptually, since the implementation is a little more complicated). When a new subscription is made, the conversion function will be called with observer.OnNext
passed as an argument converter
. This lambda will return a new instance MyDelegate
that wraps the transform function we provided ( (id, price, amount) => ...
). This is what is then passed to the method handler => MyEvent += handler
.
After that, every time the event fires, it will call our lambda method and convert the passed arguments into an instance MyArgs
, which is then delivered to converter
/ observer.OnNext
.
On top of all this magic, it also takes care of clearing the event handlers when you're done with it, gracefully handing exceptions downstream and managing memory overhead by sharing a single event handler across multiple observers.
source to share