开发者

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()
        {
 开发者_C百科           var array = new int[] { 1, 2, 3 };
            var enumerable = array.ToObservable().ToEnumerable();

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


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.


Richard is right here, but I'd also add this from a conceptual view - IEnumerable usually (in practice, but is not required to be) is an abstraction for a finite-sized list. FromEvent is an IObservable that never terminates - does it make sense to create an infinitely-sized list? There's not many practical things I could do with that...

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜