Subject.OnError抛出

时间:2019-01-11 17:36:51

标签: c# .net system.reactive

我正在使用Rx .NET的Subject.OnError,它似乎是抛出而不是传播异常。我的情况是,主题是在单独的线程上馈送数据的,返回该数据时,调用线程需要做一些事情,还需要等待可观察对象中的所有数据完成,以及传播发生的任何异常。

这是一个简化的示例:

class Program
{
    static async Task Main(string[] args)
    {
        var subject = new Subject<bool>();

        Task.Run(async () =>
        {
            await Task.Delay(5000);
            subject.OnError(new Exception()); //This call is throwing!
        });

        subject.Subscribe(e =>
        {
            //Do some data processing here
        });

        try
        {
            //Need to wait for observable to complete before returning to the caller
            await subject.LastOrDefaultAsync();
        }
        catch
        {
            //Do some logging, clean up resources
            throw;
        }
    }
}

如果我删除对subject.Subscribe()的调用,代码将按您期望的方式工作,并且异常将在subject.LastOrDefaultAsync()处抛出。但是,在Subscribe存在的情况下,对subject.OnError()的调用会立即将异常重新放置到位(而不是将异常传递给可观察到的异常),这对我来说似乎很奇怪。

如何解决此问题?

(仅供参考,已经使用Subject编写了大量代码,因此建议我完全不使用它是不可接受的解决方案)

1 个答案:

答案 0 :(得分:2)

这是一个更简单的示例:

void Main()
{
    var subject = new Subject<bool>();
    subject.Subscribe(b => {/* bool handling code */});
    subject.OnError(new Exception()); //This call is throwing!
}

Subscribe重载会重新引发它收到的异常。如果要忽略异常,请执行以下操作:

void Main()
{
    var subject = new Subject<bool>();
    // subject.Subscribe();
    subject.Subscribe(b => {/* bool handling code */}, e => { });
    subject.OnError(new Exception()); //This call is throwing!

}

如果您想查看此资源,请看这里:https://github.com/dotnet/reactive/blob/master/Rx.NET/Source/src/System.Reactive/Observable.Extensions.cs(第63行)。它会引发任何捕获的异常。


编辑

如果您想钻进兔子洞,这是(有效的)异常处理代码,该代码最终因.Subscribe(onNextHandlerOnly)重载而被调用:

void Main()
{
    var subject = new Subject<bool>();
    subject.Subscribe(b => b.Dump(), e => { e.Throw(); }, () => {});
    subject.OnError(new Exception()); //This call is throwing!

}

public static class X
{
    public static void Throw(this Exception exception)
    {
         System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(exception).Throw();
    }
}

EDI.Capture调用使它看起来像是异常的“源”是OnError调用,而不是Subscribe