5

I have an delegate that looks like this:

public delegate void MyDelegate(int arg1, int arg2);

And an event that looks like this:

public event MyDelegate SomethingHappened;

Is there some easy way to create an IObservable sequence for this event? I'd like to do something like this (but it doesn't compile):

var obs = Observable.FromEventPattern<int, int>(this, "SomethingHappened");
var subscription = obs.Subscribe(x,y => DoSomething(x, y));

....

private void DoSomething(int value1, int value2)
{
...
}
James World
  • 29,019
  • 9
  • 86
  • 120
pete757
  • 319
  • 4
  • 12
  • I am wondering if this Article would benefit you in your current situation http://www.dofactory.com/net/observer-design-pattern also `Jon Skeet` has an SO posting on what looks to be similar as well http://stackoverflow.com/questions/3274815/how-to-use-observable-fromevent-with-static-events – MethodMan Sep 10 '14 at 14:45

2 Answers2

9

There is a way to do this using Observable.FromEvent as follows.

Lets create a class Test to encapsulate the delegate and event definition:

public class Test
{   
    public delegate void MyDelegate(int arg1, int arg2);

    public event MyDelegate SomethingHappened;

    public void RaiseEvent(int a, int b)
    {
        var temp = SomethingHappened;
        if(temp != null)
        {
            temp(a, b);
        }
    }    
}

Now, because the delegate has two arguments which are not neatly packaged into a subclass of EventArgs, we must use a conversion function to package them into a suitable containing type. If you recall the signature of the OnNext method of IObservable it should be clear why we have to do this - we can only supply a single argument here.

You can create your own type for this, but I will be lazy and use a Tuple<int,int>. We can then use the overload of Observable.FromEvent with the conversion function as follows:

var test = new Test();

var obs = Observable.FromEvent<Test.MyDelegate, Tuple<int,int>>(
    handler => (a, b) => handler(Tuple.Create(a,b)),
    h => test.SomethingHappened += h,
    h => test.SomethingHappened -= h
);

To be clear, what we are supplying in that first parameter is a function that accepts an OnNext handler (in this case of type Action<Tuple<int,int>>) and returns a delegate that can be subscribed to the event (of type MyDelegate). This delegate will be invoked for each event and will in turn invoke the OnNext handler passed in from the Subscribe call. Thus we will end up with a stream of type IObservable<Tuple<int,int>>.

With obs in place, we can subscribe like so:

var subscription = obs.Subscribe(x => Console.WriteLine(x.Item1 + " " + x.Item2));

And test with this:

test.RaiseEvent(1, 2);
James World
  • 29,019
  • 9
  • 86
  • 120
  • Thanks all for the suggestions, especially James! It does exactly what I need. – pete757 Sep 10 '14 at 16:47
  • 1
    The first parameter to `FromEvent` can be simplified to just `handler => (a, b) => handler(Tuple.Create(a, b))`. There's no need for the statement expression, assigning the delegate to a variable, explicitly stating the delegate, or any of that. It'll be inferred by the lambda. – Servy Sep 10 '14 at 16:51
  • @Servy Yes, quite right - just a result of how I hashed out the answer. I've put that in. – James World Sep 10 '14 at 17:37
1

I haven't used Observable before, but it looks like the Observable.FromEvent method does what you want: http://msdn.microsoft.com/en-us/library/hh229271(v=vs.103).aspx

Chris Pitman
  • 12,990
  • 3
  • 41
  • 56