【问题标题】:Rx Disposing a subscriptionRx 处理订阅
【发布时间】:2011-05-19 04:39:50
【问题描述】:

处置循环中创建的订阅的推荐方法是什么? 在下面的人为示例中,我在 for 循环中生成订阅并将它们添加到 List 并通过 List 这对我来说似乎有点臭,我认为必须有一种更清洁的方法来清理订阅,除非 GC 在运行时处理它们。我需要明确 Dispose 订阅吗?

class Program
{
    static void Main(string[] args)
    {
        Func<int, IEnumerable<int>> func = x =>
        {
            return Enumerable.Range(0, x);
        };

        List<IDisposable> subsriptions = new List<IDisposable>();
        for (int i = 1; i < 10; i++)
        {
            var observable = func(i).ToObservable().ToList();
            var subscription = observable.Subscribe(x => Console.WriteLine(x.Select(y => y.ToString()).Aggregate((s1, s2) => s1 + "," + s2)));
            subsriptions.Add(subscription);
        }
        Console.ReadLine();
        subsriptions.ForEach(s => s.Dispose());
    }
}

【问题讨论】:

    标签: c# system.reactive


    【解决方案1】:

    如果源完成,则不需要处置订阅。在您的示例中,如果您想在完成之前停止枚举 Range,您只会处置订阅。

    即使在这种情况下,更常见的做法是使用终止订阅的运算符(如 TakeTakeWhileTakeUntil)来处理订阅。

    如果您确实想合并多个 IDisposable 订阅,CompositeDisposable 就是专为做到这一点而设计的:

    CompositeDisposable subsriptions = new CompositeDisposable();
    
    subscriptions.Add(Observable.Interval(TimeSpan.FromSeconds(1)).Subscribe());
    subscriptions.Add(Observable.Interval(TimeSpan.FromSeconds(1)).Subscribe());
    subscriptions.Add(Observable.Interval(TimeSpan.FromSeconds(1)).Subscribe());
    
    subscriptions.Dispose();
    

    【讨论】:

    • @Richard:您能否详细说明“通过使用终止订阅作为其设计的一部分的运算符来处理订阅更为常见”。您是说如果“获取元素”的条件评估为假,则基于谓词(如 Where/TakeWhile 等)的运算符会隐式处理订阅?此外,如果运算符是“选择”而不是基于谓词的过滤器,在这种情况下您是否需要明确处理订阅?
    • 您的理解在这两个方面都是正确的,但如果您在该 Select 上添加了一个 Take*,则拍摄将终止 Select,这将终止源。
    • 优秀。还有一个(不相关的)问题。在我看到的大多数基于控制台应用程序的 Rx 示例中,您通常需要一个 console.readline 来保持进程处于活动状态,直到完全消耗可观察的序列(TPL 中的 Task 也是如此)。 API 中是否有任何机制来注册调用者可以等待的 WaitHandle?
    • 您可以使用AutoResetEvent,但老实说,这将与异步作斗争。在订阅之前,您最好在整个链条中返回 IObservable&lt;T&gt;(或 Task&lt;T&gt; 通过 ToTask() 它仍然存在)。
    • 同意,但是如果您在 for 循环中创建多个订阅,您如何知道所有订阅的处理都已完成?我想您需要在已完成或错误委托中设置一个事件,以指示订阅运行完成,不是吗?此外,Rx 动手实验室指出 IObservable 上的 Run() 运算符会阻塞调用者,直到序列被订阅调用处理,似乎无法在任何地方的 API 中找到它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-09-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-19
    • 1970-01-01
    相关资源
    最近更新 更多