简体   繁体   English

使用 Rx 订阅进度事件并在完成时仍然获得结果

[英]Using Rx to subscribe to progress event and still get result on completion

I have to call a method belonging to an external component.我必须调用属于外部组件的方法。 The signature of the method looks something like this:该方法的签名如下所示:

IImportedData Import(string fileName, Action<int> progress);

This operation can take a long time to execute, so I need to call it asynchronously and report progress to the user.这个操作可能需要很长时间才能执行,所以我需要异步调用它并向用户报告进度。 I'm looking at different approaches to calling it (Rx, TPL, ThreadPool) to find something expressive and clear, however I'm struggling to come up with a way to do it in Rx.我正在寻找不同的方法来调用它(Rx、TPL、ThreadPool)以找到一些富有表现力和清晰的东西,但是我正在努力想出一种在 Rx 中做到这一点的方法。

At first glance, the idea of reporting progress using Rx seems like a perfect fit - it's a stream of incoming ints relating to progress.乍一看,使用 Rx 报告进度的想法似乎非常合适——它是与进度相关的传入整数流。 The only catch is that when the operation completes, I need to inspect IImportedData to display a result to the user.唯一的问题是,当操作完成时,我需要检查IImportedData以向用户显示结果。 OnCompleted isn't intended for that purpose, which leads me down a path of having a class that exposes two IObservable streams, and then a method to "Start" the operation. OnCompleted 不是为此目的而设计的,这使我走上了一条公开两个 IObservable 流的类的道路,然后是“启动”操作的方法。

private class Importer : IObservable<int>, IObservable<IImportedData>

Feels clunky and I'm sure there's a better way that I don't know of.感觉很笨重,我相信有一种我不知道的更好的方法。

Two things come to mind up front:前面想到了两件事:

  1. Task<T> and IProgress<T> seem like a better fit for this task Task<T>IProgress<T>似乎更适合这项任务
  2. Implementing IObservable<T> is generally frowned upon.实现IObservable<T>通常是不受欢迎的。 Creating composite instances using static methods on Observable is the recommended approach.Observable上使用静态方法创建复合实例是推荐的方法。

If you stick with Rx, I'd recommend having a look at this discussion I had with the Rx guys a few years back.如果您坚持使用 Rx,我建议您查看几年前我与 Rx 人员的讨论 Jeffrey van Gogh ended up recommending an Either<TLeft, TRight> response that you would automatically route callbacks depending on whether the message was a "progress" event or a "result" event. Jeffrey van Gogh 最终推荐了Either<TLeft, TRight>响应,您将根据消息是“进度”事件还是“结果”事件自动路由回调。 If I was in that position again, that's certainly the direction I would take.如果我再次处于那个位置,那肯定是我会采取的方向。

You could try something like this:你可以尝试这样的事情:

Func<string, Action<int>, IObservable<IImportedData>> create =
    (fileName, progress) =>
        Observable.Create<IImportedData>(o =>
        {
            var foo = new Foo();
            var subject = new BehaviorSubject<int>(0);

            var d1 = subject.Subscribe(progress);

            var result = foo.Import(fileName, n => subject.OnNext(n));

            var d2 = subject
                .Where(x => x == 100)
                .Select(x => result)
                .Subscribe(o);

            return new CompositeDisposable(d1, d2);
        });

I haven't tested it, but something like this should give you a relatively clean Rx way of doing what you're after.我还没有测试过它,但是这样的事情应该会给你一个相对干净的 Rx 方式来做你所追求的事情。 You may need to add in your synchonization context.您可能需要添加同步上下文。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM