代码之家  ›  专栏  ›  技术社区  ›  MgSam Brad M

主题.错误投掷

  •  0
  • MgSam Brad M  · 技术社区  · 7 年前

    我用的是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 回复  |  直到 7 年前
        1
  •  2
  •   Shlomo    7 年前

    下面是一个简单的例子:

    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 打电话,而不是 订阅 .