I cannot get Observable.FromEvent(…).ToEnumerable() to work

When I try to get an IEnumerable from an IObservable that was created from a native .NET event, the IEnumerable blocks when querying the first element. What am I doing wrong?

I have built a small complete example. The first test method blocks, though the event is correctly pushed by another IObservable. The second test method works on a plain array and doesn't block.

Thanks!

using System;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace TestGTI.Reactive
{

    class ItHappenedEventArgs : EventArgs
    {
    }

    class A
    {
        public event EventHandler<ItHappenedEventArgs> ItHappened;

        public void RaiseItHappened(ItHappenedEventArgs e)
        {
            if (ItHappened != null)
            {
                ItHappened(this, e);
            }
        }
    }

    [TestClass]
    public class ReactiveTest
    {
        [TestMethod]
        public void EnumerateEventTest()
        {
            var a = new A();

            ItHappenedEventArgs pushed = null;
            Observable.FromEvent<ItHappenedEventArgs>(a, "ItHappened").Subscribe(e =>
                {
                    pushed = e.EventArgs;
                });

            var itHappenedEnum = Observable.FromEvent<ItHappenedEventArgs>(a, "ItHappened").ToEnumerable();

            var itHappenedEventArgs = new ItHappenedEventArgs();
            a.RaiseItHappened(itHappenedEventArgs);

            Assert.AreSame(itHappenedEventArgs, pushed);

            // blocks!!!
            Assert.AreSame(itHappenedEventArgs, itHappenedEnum.First());        
        }

        [TestMethod]
        public void ObservableToEnumerableTest()
        {
            var array = new int[] { 1, 2, 3 };
            var enumerable = array.ToObservable().ToEnumerable();

            // works
            Assert.AreEqual(1, enumerable.First());
        }
    }
}

Answers


The IEnumerable is lazy when it comes to enumeration, and ToEnumerable doesn't subscribe to the source until you start enumerating.

In your example, you are calling First() after you have raised the event for the first time, so you are subscribing to the source and no value is being emitted, hence the blocking. Basically by the time you are listening, the value has already come and gone.

If you want to remember the value, you can use Prune or Replay (remember to connect to the returned IConnectableObservable to start listening). You can then use ToEnumerable and the value will be emitted.


Need Your Help

Passing two class to meteorjs click event?

javascript jquery templates meteor meteor-helper

Passing two class to meteorjs click event. I have two buttons save and close which have same functionality and i want to target them using meteor events. I know i can assign them same class or crea...

How to access $parent or $parents in knockout viewmodel click event?

knockout.js

I've got a situation where I'd like to notify a grandparent or $parents[1] of a click event that occurs in a sub viewmodel. So basically I'd like to be able to do this

About UNIX Resources Network

Original, collect and organize Developers related documents, information and materials, contains jQuery, Html, CSS, MySQL, .NET, ASP.NET, SQL, objective-c, iPhone, Ruby on Rails, C, SQL Server, Ruby, Arrays, Regex, ASP.NET MVC, WPF, XML, Ajax, DataBase, and so on.