意外的行为与异常处理在异步,可能的错误? [英] Unexpected behavior with exception handling in async, possible bug?

查看:293
本文介绍了意外的行为与异常处理在异步,可能的错误?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经在一个问题调用一个嵌套的异步这恰好是空的时候绊倒了。一个例外是提出,但它不能与任何正常的异常处理方法异步工作流程提供被逮住。

I have stumbled upon a problem when calling a nested Async which happens to be null. An exception is raised but it can't be catched with any of the normal exception handling methods Async workflows provide.

下面是一个简单的测试,重新产生此问题:

The following is a simple test which reproduces the problem:

[<Test>]
let ``Nested async is null with try-with``() = 

    let g(): Async<unit> = Unchecked.defaultof<Async<unit>>

    let f = async {
            try
                do! g()
            with e ->  
                printf "%A" e
    }

    f |> Async.RunSynchronously |> ignore

这导致follwing异常:

which results in the follwing exception:

System.NullReferenceException : Object reference not set to an instance of an object.
at Microsoft.FSharp.Control.AsyncBuilderImpl.bindA@714.Invoke(AsyncParams`1 args)
at <StartupCode$FSharp-Core>.$Control.loop@413-40(Trampoline this, FSharpFunc`2 action)
at Microsoft.FSharp.Control.Trampoline.ExecuteAction(FSharpFunc`2 firstAction)
at Microsoft.FSharp.Control.TrampolineHolder.Protect(FSharpFunc`2 firstAction)
at Microsoft.FSharp.Control.AsyncBuilderImpl.startAsync(CancellationToken cancellationToken,     FSharpFunc`2 cont, FSharpFunc`2 econt, FSharpFunc`2 ccont, FSharpAsync`1 p)
at Microsoft.FSharp.Control.CancellationTokenOps.starter@1121-1.Invoke(CancellationToken     cancellationToken, FSharpFunc`2 cont, FSharpFunc`2 econt, FSharpFunc`2 ccont, FSharpAsync`1 p)
at Microsoft.FSharp.Control.CancellationTokenOps.RunSynchronously(CancellationToken token, FSharpAsync`1 computation, FSharpOption`1 timeout)
at Microsoft.FSharp.Control.FSharpAsync.RunSynchronously(FSharpAsync`1 computation, FSharpOption`1 timeout, FSharpOption`1 cancellationToken)
at Prioinfo.Urkund.DocCheck3.Core2.Tests.AsyncTests.Nested async is null with try-with() in SystemTests.fs: line 345 

我真的觉得异常应在这种情况下被捕获,或者这真的是预期的行为? (我使用Visual Studio 2010 SP1备案)

I really think the exception should be caught in this case, or is this really the expected behavior? (I'm using Visual Studio 2010 Sp1 for the record)

此外, Async.Catch Async.StartWithContinuations 表现就证明了这些测试用例同样的问题:

Also, Async.Catch and Async.StartWithContinuations exhibits the same problem as demonstrated by these test cases:

[<Test>]
let ``Nested async is null with Async.Catch``() = 

    let g(): Async<unit> = Unchecked.defaultof<Async<unit>>

    let f = async {
                do! g()
            }

    f |> Async.Catch |> Async.RunSynchronously |> ignore


[<Test>]
let ``Nested async is null with StartWithContinuations``() = 

    let g(): Async<unit> = Unchecked.defaultof<Async<unit>>

    let f = async {
                do! g()
            }

    Async.StartWithContinuations(f
                                , fun _ -> ()
                                , fun e -> printfn "%A" e
                                , fun _ -> ())

这似乎异常在工作流程生成器绑定法中提出,我的猜测是,作为一个结果正常的错误处理code被绕过。它看起来像在异步工作流,以我的实现中的错误,因为我还没有发现的文档或其他地方任何这表明,这是预期的行为。

It seems the exception is raised within the bind-method in the workflow builder and my guess is that as a result the normal error handling code is bypassed. It looks like a bug in the implementation of async workflows to me since I haven't found anything in the documentation or elsewhere which suggest that this is the intended behavior.

这是pretty容易解决在大多数情况下,我认为,因此,至少不是一个大问题,但对我来说这是一个有点不安,因为这意味着你不能完全异步异常处理机制信任能够捕获所有异常。

It is pretty easy to work around in most cases I think so it's not a huge problem for me at least but it is a bit unsettling since it means that you can't completely trust the async exception handling mechanism to be able to capture all exceptions.

编辑:

给它经过一番思考我KVB同意。空异步操作不应该真的存在正常code和可能真的只有生产,如果你做一些你可能不应该(如使用Unchecked.defaultOf)或使用反射来产生值(对我来说,这是一个嘲讽框架涉及)。因此,它不是一个真正的错误,但更边缘的情况下。

After giving it some thought I agree with kvb. Null asyncs should not really exist in normal code and could really only be produced if you do something you probably shouldn't (such as using Unchecked.defaultOf) or use reflection to produce the values (in my case it was a mocking framework involved). Thus it's not really a bug but more of an edge case.

推荐答案

我不认为这是一个错误。正如其名称所示 Unchecked.defaultof&LT; _&GT; 不检查,它产生的值是有效的,而异步&LT;部&gt; 不支持作为一个适当的值(例如看到消息,如果您尝试使用设x:异步&LT;部&gt; = NULL )。 Async.Catch 之类的旨在赶上异步计算之内抛出的异常,没有造成偷偷编译器的背后,创造无效的异步计算例外。

I don't think it's a bug. As the name indicates Unchecked.defaultof<_> does not check that the values it produces are valid, and Async<unit> does not support null as a proper value (e.g. see the message if you try to use let x : Async<unit> = null). Async.Catch and the like are intended to catch exceptions thrown within asynchronous computations, not exceptions caused by sneaking behind the compiler's back and creating invalid asynchronous computations.

这篇关于意外的行为与异常处理在异步,可能的错误?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆