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...
精彩评论