我在調用一個恰好爲null的嵌套異步時偶然發現了一個問題。引發了一個異常,但無法使用Async工作流提供的任何常規異常處理方法。意外的異步處理行爲,異步,可能的錯誤?
下面是一個簡單的測試,重新產生此問題:
[<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例外:
System.NullReferenceException : Object reference not set to an instance of an object.
at [email protected](AsyncParams`1 args)
at <StartupCode$FSharp-Core>[email protected](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 [email protected]oke(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備案)
此外,Async.Catch
和Async.StartWithContinuations
展品同樣的問題,這表現在這些測試用例:
[<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 _ ->())
看來唯一的例外是bind-內提出方法在工作流生成器中,我的猜測是結果是正常的錯誤處理代碼被繞過。它看起來像是在執行異步工作流程時遇到的一個錯誤,因爲我沒有在文檔或其他地方發現任何暗示這是預期行爲的東西。
在大多數情況下,我很容易解決這個問題,至少對我來說這不是一個大問題,但這有點令人不安,因爲這意味着您不能完全信任異步異常處理機制捕捉所有的例外。
編輯:
一番考慮我KVB同意後。空的asyncs不應該真正存在於普通代碼中,只有當你做了你可能不應該做的事情時(例如使用Unchecked.defaultOf)或使用反射來產生值(在我的情況下,它是一個模擬的框架) 。因此它不是一個真正的bug,而更像是一個邊緣案例。
我可以重現它在FSI和控制檯應用程序,無論是在VS調試,並從資源管理器啓動時的時候。所以它看起來是一致的 –
Option.None基本上是空的。所以看起來像Async <'a option>可以有這個問題。 – Hans