编辑:原来这是一个F#错误,可以通过使用自定义选项类型而不是Fsharp的“选项”进行解决。
在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”异步函数中的异常,防止它“冒泡”。
我发现了this相关问题,但我似乎无法调整答案(处理任务,而不是任务&lt;'a&gt;)来满足我的需求。
修改:以下是显示问题的屏幕截图:https://i.gyazo.com/883f546c00255b210e53cd095b876cb0.png
“ArgumentException未被用户代码处理。”
(Visual Studio 2013 ,. NET 4.5.1,Fsharp 3.1,Fsharp.core.dll 4.3.1.0。)
代码是否正确但是某些Fsharp或Visual Studio设置是否阻止异常被捕获?
答案 0 :(得分:2)
TL; DR:异常被捕获,它似乎是从异步中返回None,这里令人困惑 - 结果是null,而不是None,这是搞乱模式匹配,一般都很麻烦。使用您自己的联合类型而不是Option来处理它。
编辑哦,@ takemyoxygen关于你为何直接看到它的评论是正确的。 Debug-&gt; Exceptions,或者只是取消勾选&#34;当这个异常类型是用户未处理的时候中断&#34;在屏幕截图中显示的弹出窗口中。看起来VS正在打破THROW,而不是实际上未处理。
首先,在Async.Catch中返回Some / None会使它无用。 Async.Catch返回Choice1Of2(val)
,除非有未捕获的异常,因此代码原样(如果有效)将返回Choice1Of2(Some(string))
没有异常,或Choice1Of2(None)
异常。使用try / with并自己处理异常,或者只使用Async.Catch。
证明我们正在捕捉:使用&#34;将调试输出添加到&#34;。代码到达那里(添加断点或查看调试输出以进行证明)。我们得到的是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时,它将变为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也适用于新的Union:
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中),但是例外情况肯定会被捕获,但是没有 - >; null正在搞砸它。