Exception 如何捕获使用Async.AwaitTask运行的任务引发的异常
编辑:这是一个F#bug,可以通过使用自定义选项类型而不是Fsharp的“选项”来解决 在F#中,我尝试使用Async.WaitTask调用.net任务。任务正在抛出异常,我似乎无法用try-catch或Async.catch捕获它。我知道没有其他方法可以捕捉异常。解决办法是什么?问题的原因是什么?谢谢你的解释 以下是一些测试代码,显示我未能捕获DownloadStringTaskAsync引发的异常:Exception 如何捕获使用Async.AwaitTask运行的任务引发的异常,exception,asynchronous,exception-handling,f#,task-parallel-library,Exception,Asynchronous,Exception Handling,F#,Task Parallel Library,编辑:这是一个F#bug,可以通过使用自定义选项类型而不是Fsharp的“选项”来解决 在F#中,我尝试使用Async.WaitTask调用.net任务。任务正在抛出异常,我似乎无法用try-catch或Async.catch捕获它。我知道没有其他方法可以捕捉异常。解决办法是什么?问题的原因是什么?谢谢你的解释 以下是一些测试代码,显示我未能捕获DownloadStringTaskAsync引发的异常: open System open System.Net [<EntryPoint&g
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
开放系统
开放系统.Net
[]
让主argv=
试一试=
异步的{
让!exc=Async.Catch(异步{
尝试
设w=new Net.WebClient();
let!str=Async.AwaitTask(w.downloadstringtaskancy“”)//引发ArgumentException
返回一些str
具有
| _ ->
返回无//未捕获
}
)
将exc与
|选择1OF2 r->返回r
|选择2of2 ext->return None//not catch
}
让res=Async.RunSynchronously(测试)
让str=Console.ReadLine();
0//返回整数退出代码
我需要某种方法来捕获“test”异步函数中的异常,防止它“冒泡”
我找到了相关的问题,但我似乎无法调整答案(它处理的是任务,而不是任务TL;DR:异常确实会被捕获,它似乎在异步中返回None,这在这里很混乱-结果是null,而不是None,这会破坏模式匹配,通常是一个麻烦。使用您自己的联合类型而不是选项来处理它 编辑:哦,@takemyoxygen关于为什么你马上看到它的评论是正确的。调试->异常,或者在屏幕截图中可见的弹出窗口中取消勾选“当此异常类型为用户未处理时中断”。看起来VS在抛出时中断,而不是实际上在未处理时中断 首先,在Async.Catch中返回一些/None会使其无效。Async.Catch返回
Choice1Of2(val)
,除非存在未捕获的异常,否则代码原样(如果它工作)将返回Choice1Of2(一些(字符串))
而没有异常,或Choice1Of2(None)
带有异常。请使用try/with并自行处理异常,或者仅使用Async.Catch
实验:
我们正在捕获的证明:将调试输出添加到“with”。代码确实到达了那里(添加断点或查看调试输出以进行证明)。我们得到的是Choice1Of2(null)
,而不是exc中的Choice1Of2(None)
。奇怪。请参见图片:
以下内容在moreTestRes中为null
[<EntryPoint>]
let main argv =
let moreTest = async {
return None
}
let moreTestRes = Async.RunSynchronously moreTest
0
[]
让主argv=
让moreTest=async{
一无所获
}
让moreTestRes=Async.RunSynchronously moreTest
0
我不知道为什么会出现这种情况(仍然发生在F#4.0中),但异常肯定会被捕获,但None->null会把它搞砸。很抱歉让您失望,但这段代码对我来说非常好(在试用中会捕获异常)。使用F#3.1。我不需要。请参见截图:Visual Studio 2013、.net framework 4.5.1、Fsharp 3.1、Fsharp.core.dll 4.3。1@seguso,visual studio调试器中断并不意味着异常未处理。请尝试在不使用调试器的情况下运行应用程序,它是否会崩溃?是否也可以转到
Debug->Windows->exception Settings
并查看是否在那里检查了ArgumentException
?@takemyoxigen:我被Visual Studio说“ArgumentException未经用户代码处理”的事实误导了。请看另一个屏幕截图:但是,如果我按“继续”,难以置信的是,程序会正确终止。因此,您是对的。但是,在Visual Studio 2013中,我没有“调试”>“Windows”>“异常”设置,因此我不明白发生了什么。@seguso抱歉,我的错。在VS 2013中,它是“调试”>“异常”,因此概括起来,1)这是f#中的错误,而不是我的代码中的错误。问题是res=null而不是None。2)如果我使用自定义联合而不是option,那么问题就消失了。Res=MyCustomNone,不为空。3) 但是,即使我使用自定义联合而不是无,调试器中断并错误地说“未处理的异常”的问题仍然存在:正确吗?从技术上讲,您的问题的答案是捕获了异常。您看到异常是因为您总是在该异常上中断。取消选中图像中可见的复选框,单击“确定/继续”,然后再次尝试运行代码–您不应该在vs中引发异常,只是它会被捕获到。我剩下的回答包括为什么exc上的模式匹配不起作用,等等——这似乎是由一个F#bug引起的。你说:“你总是在那个异常上打破”。对不起,我觉得不是这样的。复选框显示“当用户未处理此异常类型时中断”。它并没有说“永远休息”。我正在使用try-catch处理异常,因此在我看来,该对话框不应该出现。如果单击“全部重置”,是否为未处理的用户勾选了参数异常?另外,如果您转到工具->选项,调试->常规并取消选中“仅我的代码”,会发生什么?VS是否在抛出异常后仍会抱怨?DownloadStringTaskAsync是您正在调用的东西,它正在抛出异常,异常将进入Async.AwaitTask(这不是您的代码)。这意味着您的异常被发送到非用户代码-因此您有一个未处理的用户中断,因为您在异常到达非用户代码之前没有处理它。禁用“仅我的代码”意味着它将让异常冒泡通过框架代码,并且只有在真正未处理的情况下才会中断。
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
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
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
[<EntryPoint>]
let main argv =
let moreTest = async {
return None
}
let moreTestRes = Async.RunSynchronously moreTest
0