如何使用 Async.AwaitTask 捕获任务 运行 抛出的异常
How to catch exception thrown by Task run with Async.AwaitTask
编辑:这原来是一个 F# 错误,可以通过使用自定义选项类型而不是 Fsharp 的 "Option".
在 F# 中,我试图用 Async.AwaitTask 调用 .net 任务。该任务抛出异常,我似乎无法使用 try-catch 或 Async.Catch 捕获它。而且我知道没有其他方法可以捕获异常。解决办法是什么?问题的原因是什么?感谢您的任何解释。
这是一些测试代码,显示我未能捕获 DownloadStringTaskAsync 抛出的异常:
open System
open System.Net
[<EntryPoint>]
let main argv =
let test =
async{
let! exc = Async.Catch( async{
try
let w = new Net.WebClient();
let! str = Async.AwaitTask (w.DownloadStringTaskAsync "") // throws ArgumentException
return Some str
with
| _ ->
return None // not caught
}
)
match exc with
| Choice1Of2 r -> return r
| Choice2Of2 ext -> return None // not caught
}
let res = Async.RunSynchronously(test)
let str = Console.ReadLine();
0 // return an integer exit code
我需要一些方法来捕获 "test" 异步函数中的异常,防止它进入 "bubble up".
我找到了 this 相关问题,但我似乎无法根据我的需要调整答案(涉及任务,而不是任务<'a>)。
编辑:这是显示问题的屏幕截图:https://i.gyazo.com/883f546c00255b210e53cd095b876cb0.png
"ArgumentException was unhandled by user code."
(Visual Studio 2013,.NET 4.5.1,Fsharp 3.1,Fsharp.core.dll 4.3.1.0。)
会不会是代码是正确的,但某些 Fsharp 或 Visual Studio 设置阻止了异常被捕获?
TL;DR: 确实捕获了异常,它似乎是 returning None 异步,这在这里令人困惑 - 结果是null,而不是 None,它搞砸了模式匹配并且通常很麻烦。使用您自己的联合类型而不是 Option 来处理它。
编辑: 哦,@takemyoxygen 关于您为何立即看到它的评论是正确的。 Debug->Exceptions,或者在屏幕截图中可见的弹出窗口中取消勾选“当此异常类型为用户未处理时中断”。看起来 VS 在 THROW 上中断,而不是在未处理时中断。
首先,在 Async.Catch 中 returning Some/None 使其无用。 Async.Catch returns Choice1Of2(val)
除非有未捕获的异常,所以代码原样(如果有效)将 return Choice1Of2(Some(string))
无一例外,或者 Choice1Of2(None)
有例外。要么使用 try/with 并自己处理异常,要么只使用 Async.Catch.
实验:
证明我们正在捕获: 将调试输出添加到“with”。代码确实到达那里(添加断点或查看调试输出以获取证据)。我们在 exc 中得到 Choice1Of2(null)
,而不是 Choice1Of2(None)
。诡异的。见图:http://i.imgur.com/e8Knx5a.png
open System
open System.Net
[<EntryPoint>]
let main argv =
let test =
async{
let! exc = Async.Catch( async{
try
let w = new Net.WebClient();
let! str = Async.AwaitTask (w.DownloadStringTaskAsync "") // throws ArgumentException
return Some str
with
| _ ->
System.Diagnostics.Debug.WriteLine "in with" // We get here.
return None // not caught
}
)
match exc with
| Choice1Of2 r -> return r
| Choice2Of2 ext -> return None // not caught
}
let res = Async.RunSynchronously(test)
let str = Console.ReadLine();
0 // return an integer exit code
删除 Async.Catch: 不要使用 Async.Catch(尽管保留调试输出)。同样,我们得到了调试输出,所以我们捕获了异常,并且由于我们没有包装在来自 Async.Catch 的 Choice 中,我们得到的是 null 而不是 None。仍然很奇怪。
open System
open System.Net
[<EntryPoint>]
let main argv =
let test = async {
try
let w = new Net.WebClient();
let! str = Async.AwaitTask (w.DownloadStringTaskAsync "") // throws ArgumentException
return Some str
with
| _ ->
System.Diagnostics.Debug.WriteLine "in with"
return None }
let res = Async.RunSynchronously(test)
let str = Console.ReadLine();
0 // return an integer exit code
只使用Async.Catch:不要使用try/with,只使用Async.Catch。这样效果好一些。在 exc 的模式匹配中,我有一个包含异常的 Choice2Of2。但是,当 None 被 return 从最外面的异步中编辑出来时,它变为 null。
open System
open System.Net
[<EntryPoint>]
let main argv =
let test = async {
let! exc = Async.Catch(async {
let w = new Net.WebClient();
let! str = Async.AwaitTask (w.DownloadStringTaskAsync "") // throws ArgumentException
return str })
match exc with
| Choice1Of2 v -> return Some v
| Choice2Of2 ex -> return None
}
let res = Async.RunSynchronously(test)
let str = Console.ReadLine();
0 // return an integer exit code
不要使用选项: 有趣的是,如果您使用自定义联合类型,它会完美地工作:
open System
open System.Net
type UnionDemo =
| StringValue of string
| ExceptionValue of Exception
[<EntryPoint>]
let main argv =
let test = async {
let! exc = Async.Catch(async {
let w = new Net.WebClient();
let! str = Async.AwaitTask (w.DownloadStringTaskAsync "") // throws ArgumentException
return str })
match exc with
| Choice1Of2 v -> return StringValue v
| Choice2Of2 ex -> return ExceptionValue ex
}
let res = Async.RunSynchronously(test)
let str = Console.ReadLine();
0 // return an integer exit code
使用 try/with 而没有 Async.Catch 也适用于新联盟:
open System
open System.Net
type UnionDemo =
| StringValue of string
| ExceptionValue of Exception
[<EntryPoint>]
let main argv =
let test = async {
try
let w = new Net.WebClient();
let! str = Async.AwaitTask (w.DownloadStringTaskAsync "") // throws ArgumentException
return StringValue str
with
| ex -> return ExceptionValue ex }
let res = Async.RunSynchronously(test)
let str = Console.ReadLine();
0 // return an integer exit code
即使联合定义如下:
type UnionDemo =
| StringValue of string
| ExceptionValue
以下在 moreTestRes 中为 null。
[<EntryPoint>]
let main argv =
let moreTest = async {
return None
}
let moreTestRes = Async.RunSynchronously moreTest
0
我不知道为什么会这样(在 F# 4.0 中仍然会发生),但肯定会捕获异常,但 None->null 搞砸了。
编辑:这原来是一个 F# 错误,可以通过使用自定义选项类型而不是 Fsharp 的 "Option".
在 F# 中,我试图用 Async.AwaitTask 调用 .net 任务。该任务抛出异常,我似乎无法使用 try-catch 或 Async.Catch 捕获它。而且我知道没有其他方法可以捕获异常。解决办法是什么?问题的原因是什么?感谢您的任何解释。
这是一些测试代码,显示我未能捕获 DownloadStringTaskAsync 抛出的异常:
open System
open System.Net
[<EntryPoint>]
let main argv =
let test =
async{
let! exc = Async.Catch( async{
try
let w = new Net.WebClient();
let! str = Async.AwaitTask (w.DownloadStringTaskAsync "") // throws ArgumentException
return Some str
with
| _ ->
return None // not caught
}
)
match exc with
| Choice1Of2 r -> return r
| Choice2Of2 ext -> return None // not caught
}
let res = Async.RunSynchronously(test)
let str = Console.ReadLine();
0 // return an integer exit code
我需要一些方法来捕获 "test" 异步函数中的异常,防止它进入 "bubble up".
我找到了 this 相关问题,但我似乎无法根据我的需要调整答案(涉及任务,而不是任务<'a>)。
编辑:这是显示问题的屏幕截图:https://i.gyazo.com/883f546c00255b210e53cd095b876cb0.png
"ArgumentException was unhandled by user code."
(Visual Studio 2013,.NET 4.5.1,Fsharp 3.1,Fsharp.core.dll 4.3.1.0。)
会不会是代码是正确的,但某些 Fsharp 或 Visual Studio 设置阻止了异常被捕获?
TL;DR: 确实捕获了异常,它似乎是 returning None 异步,这在这里令人困惑 - 结果是null,而不是 None,它搞砸了模式匹配并且通常很麻烦。使用您自己的联合类型而不是 Option 来处理它。
编辑: 哦,@takemyoxygen 关于您为何立即看到它的评论是正确的。 Debug->Exceptions,或者在屏幕截图中可见的弹出窗口中取消勾选“当此异常类型为用户未处理时中断”。看起来 VS 在 THROW 上中断,而不是在未处理时中断。
首先,在 Async.Catch 中 returning Some/None 使其无用。 Async.Catch returns Choice1Of2(val)
除非有未捕获的异常,所以代码原样(如果有效)将 return Choice1Of2(Some(string))
无一例外,或者 Choice1Of2(None)
有例外。要么使用 try/with 并自己处理异常,要么只使用 Async.Catch.
实验:
证明我们正在捕获: 将调试输出添加到“with”。代码确实到达那里(添加断点或查看调试输出以获取证据)。我们在 exc 中得到 Choice1Of2(null)
,而不是 Choice1Of2(None)
。诡异的。见图:http://i.imgur.com/e8Knx5a.png
open System
open System.Net
[<EntryPoint>]
let main argv =
let test =
async{
let! exc = Async.Catch( async{
try
let w = new Net.WebClient();
let! str = Async.AwaitTask (w.DownloadStringTaskAsync "") // throws ArgumentException
return Some str
with
| _ ->
System.Diagnostics.Debug.WriteLine "in with" // We get here.
return None // not caught
}
)
match exc with
| Choice1Of2 r -> return r
| Choice2Of2 ext -> return None // not caught
}
let res = Async.RunSynchronously(test)
let str = Console.ReadLine();
0 // return an integer exit code
删除 Async.Catch: 不要使用 Async.Catch(尽管保留调试输出)。同样,我们得到了调试输出,所以我们捕获了异常,并且由于我们没有包装在来自 Async.Catch 的 Choice 中,我们得到的是 null 而不是 None。仍然很奇怪。
open System
open System.Net
[<EntryPoint>]
let main argv =
let test = async {
try
let w = new Net.WebClient();
let! str = Async.AwaitTask (w.DownloadStringTaskAsync "") // throws ArgumentException
return Some str
with
| _ ->
System.Diagnostics.Debug.WriteLine "in with"
return None }
let res = Async.RunSynchronously(test)
let str = Console.ReadLine();
0 // return an integer exit code
只使用Async.Catch:不要使用try/with,只使用Async.Catch。这样效果好一些。在 exc 的模式匹配中,我有一个包含异常的 Choice2Of2。但是,当 None 被 return 从最外面的异步中编辑出来时,它变为 null。
open System
open System.Net
[<EntryPoint>]
let main argv =
let test = async {
let! exc = Async.Catch(async {
let w = new Net.WebClient();
let! str = Async.AwaitTask (w.DownloadStringTaskAsync "") // throws ArgumentException
return str })
match exc with
| Choice1Of2 v -> return Some v
| Choice2Of2 ex -> return None
}
let res = Async.RunSynchronously(test)
let str = Console.ReadLine();
0 // return an integer exit code
不要使用选项: 有趣的是,如果您使用自定义联合类型,它会完美地工作:
open System
open System.Net
type UnionDemo =
| StringValue of string
| ExceptionValue of Exception
[<EntryPoint>]
let main argv =
let test = async {
let! exc = Async.Catch(async {
let w = new Net.WebClient();
let! str = Async.AwaitTask (w.DownloadStringTaskAsync "") // throws ArgumentException
return str })
match exc with
| Choice1Of2 v -> return StringValue v
| Choice2Of2 ex -> return ExceptionValue ex
}
let res = Async.RunSynchronously(test)
let str = Console.ReadLine();
0 // return an integer exit code
使用 try/with 而没有 Async.Catch 也适用于新联盟:
open System
open System.Net
type UnionDemo =
| StringValue of string
| ExceptionValue of Exception
[<EntryPoint>]
let main argv =
let test = async {
try
let w = new Net.WebClient();
let! str = Async.AwaitTask (w.DownloadStringTaskAsync "") // throws ArgumentException
return StringValue str
with
| ex -> return ExceptionValue ex }
let res = Async.RunSynchronously(test)
let str = Console.ReadLine();
0 // return an integer exit code
即使联合定义如下:
type UnionDemo =
| StringValue of string
| ExceptionValue
以下在 moreTestRes 中为 null。
[<EntryPoint>]
let main argv =
let moreTest = async {
return None
}
let moreTestRes = Async.RunSynchronously moreTest
0
我不知道为什么会这样(在 F# 4.0 中仍然会发生),但肯定会捕获异常,但 None->null 搞砸了。