我无法让 Observable.FromEvent(...).ToEnumerable() 工作

发布于 2024-10-06 02:22:04 字数 1728 浏览 0 评论 0原文

当我尝试从本机 .NET 事件创建的 IObservable 获取 IEnumerable 时,IEnumerable 在查询第一个元素时会阻塞。我做错了什么?

我已经构建了一个小型完整示例。尽管事件由另一个 IObservable 正确推送,但第一个测试方法会阻塞。第二种测试方法适用于普通数组并且不会阻塞。

谢谢!

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());
        }
    }
}

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());
        }
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

神回复 2024-10-13 02:22:04

IEnumerable 在枚举方面是惰性的,而 ToEnumerable 在开始枚举之前不会订阅源。

在您的示例中,您在第一次引发事件之后调用 First() after ,因此您正在订阅源并且不会发出任何值,因此阻塞。基本上,当你在听的时候,价值已经来了又消失了。

如果您想记住该值,可以使用 PruneReplay (记住连接到返回的 IConnectableObservable 来开始监听)。然后您可以使用 ToEnumerable 并且该值将被发出。

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.

最美不过初阳 2024-10-13 02:22:04

Richard 就在这里,但我还要从概念角度添加这一点 - IEnumerable 通常(在实践中,但不是必需的)是有限大小列表的抽象。 FromEvent 是一个永不终止的 IObservable - 创建无限大小的列表有意义吗?我能做的实际事情并不多......

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...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文