如何解决如何在不将结果传递给 F# 中的调用者的情况下捕获特定类型的异常?
我正在尝试捕获特定异常以获取用于日志记录的基础消息,但我不希望将异常传递回调用方法。我知道如何在 C#、F# 中执行此操作?嗯。
这是不针对特定异常类型工作的代码。我只是记录方法中发生了问题
match remoteapiResponse.StatusCode with
| HttpStatusCode.OK ->
let! resp = remoteapiResponse.Content.ReadAsstringAsync() |> Async.AwaitTask
try
let IsSuccess = JObject.Parse(resp).["IsSuccess"].ToString().Trim().ToLower()
match IsSuccess with
| "true" -> ()
| "false" -> remoteapiResponse.StatusCode <- HttpStatusCode.BadRequest
| _ -> ()
with
| _ -> logger.LogError("Error Occurred during IsSuccess flag validation.")
| _ -> ()
在下面的代码中,我的目标是评估 NullReferenceException 类型,但它实际上可能是任何类型的错误
match remoteapiResponse.StatusCode with
| HttpStatusCode.OK ->
let! resp = remoteapiResponse.Content.ReadAsstringAsync() |> Async.AwaitTask
try
let IsSuccess = JObject.Parse(resp).["IsSuccess"].ToString().Trim().ToLower()
match IsSuccess with
| "true" -> ()
| "false" -> remoteapiResponse.StatusCode <- HttpStatusCode.BadRequest
| _ -> ()
with
| :? NullReferenceException as ne -> logger.LogError("Error Occurred during IsSuccess flag validation." + ne.Message)
| _ -> ()
我看到的问题是,当我指定一个异常类型时,异常会通过链向上传递到调用方法。第一种方法按原样工作,但它没有收集非常有用的信息。
第二种方法是捕获错误的更多细节的方法,但它总是将异常带入链中。
如何最小程度地修改我的第二版代码(如果可能)以防止错误传递回调用者? 很确定有一个简单的方法可以解决这个问题,但我不是 100% 在 F# 中如何
解决方法
就像在 C# 中一样,您可以在 with
块中使用多个模式。它们将按顺序匹配。使用第一个捕获您想要记录的异常,然后使用捕获所有模式来吞下所有其他异常:
try
...
with
| ?: NullReferenceException as ne -> logger.LogError ...
| _ -> ()
编辑以回应评论。
If ?: 是什么是 _ -> () 以及为什么需要它?
:?
和 _ ->
都是“收获”。
在 F# 中,就像在 C# 中一样,一个可以有多个 catch
块 - 几个用于不同类型的异常,并且可选地,一个 catch-all 块用于其他块中未明确提及的所有异常类型。
例如,在 C# 中:
try { throw ... }
catch (NullReferenceException e) { Console.WriteLine("Null"); }
catch (NotImplementedException e) { Console.WriteLine("Not impl"); }
catch (InvalidOperationException e) { Console.WriteLine("Invalid op"); }
catch { Console.WriteLine("No idea what happened"); }
F# 中的等效代码:
try
...
with
| ?: NullReferenceException as e -> printfn "Null"
| ?: NotImplementedException as e -> printfn "Not impl"
| ?: InvalidOperationException as e -> printfn "Invalid op"
| _ -> printfn "No idea what happened"
F# 版本确实有更多的灵活性 - 例如您可以在 F#-defined exception types 上使用 when
守卫或深度模式匹配。但想法是一样的:多个接球手,连续测试,直到匹配一次。
另一件需要注意的事情是语法 :?
并不是异常处理所特有的。它是在类层次结构上进行模式匹配的语法。例如,您可以在常规函数中使用它:
let isString (o: obj) =
match o with
| :? string -> true
| _ -> false
我认为这有点像是在陈述“最终”结束行动
“相当”和“有点”这两个词属于自然语言。另一方面,编程语言结构具有非常具体、严格定义的含义,在任何给定时刻可能符合也可能不符合您的直觉。
特别是,C#/F# 中的 finally
块与“捕获所有其他异常”不同。虽然异常捕获器仅在异常发生时执行,但 finally
块会执行不管是否发生异常。
当没有异常发生时,finally
块照常在 try
之后执行。当异常发生时,finally
块在引发异常之前 执行,并且至关重要的是,在 finally
块执行完毕后,异常飞行会继续进行。再一次开车回家:finally
块不会阻止异常。
finally
块的想法是允许您清理资源并确保无论是否发生异常都会进行清理。
在 C# 中:
try { Console.WriteLine("Working"); }
finally { Console.WriteLine("Done"); }
在 F# 中:
try
printfn "Working"
finally
printfn "Done"
另一件需要注意的事情是,与 C# 不同,由于复杂的原因,F# 不允许在同一块中同时包含 with
和 finally
。因此,如果两者都需要,则必须将它们相互嵌套。
在 C# 中:
try { Console.WriteLine("Working"); }
catch (NullReferenceException e) { Console.WriteLine("Null"); }
finally { Console.WriteLine("Cleanup"); }
在 F# 中:
try
try
printfn "Working"
with :? NullReferenceException ->
printfn "Null"
finally
printfn "Done"
有关详细信息,请参阅 the docs。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。