以正确的方式处理异常
Handling exception in the right way
我是 f# 世界的新手。我写了一个非常小的应用程序,它从 sap 查询数据并将结果显示为输出。当应用程序尝试连接 sap 时,它可能会抛出一些异常,以防出现问题。
看下面的代码:
type Customer() =
let mutable _lastName = String.Empty
member self.LastName with get () = _lastName
member self.QueryData () =
//Some CODES here
let bapi = SapBapi()
let bapiFunc = bapi.GetBapiFunc(dest, "BAPI_CUSTOMER_GETDETAIL1")
match bapiFunc with
| Success bp ->
//Some CODES here
let addressData = bp.GetStructure("PE_PERSONALDATA")
_lastName <- addressData.GetString("LASTNAME")
None
| RfcCommunication ex ->
Some(ex :> Exception)
| RfcLogon ex ->
Some(ex :> Exception)
| RfcAbapRuntime ex ->
Some(ex :> Exception)
如您所见,我使用选项类型处理错误,并将抛出的异常向下转换为基本异常类型。
在主函数中
open CustomerBapi
open System
[<EntryPoint>]
let main argv =
let customer = CustomerBapi.Customer()
let ex = customer.QueryData()
match ex with
| Some ex ->
printfn "%s" ex.Message
| None ->
printfn "%s" customer.LastName
Console.ReadLine() |> ignore
0 // return an integer exit code
此代码有效,但我是否以正确的方式处理异常?
我在网上看过一篇文章,说在 f# 中处理异常应该 return 一个错误代码,它比异常样式更容易。
总的来说,我认为你的解决方案还可以,但可以改进。
您在代码中混合了一些功能和 OO 风格。我觉得你把异常作为唯一的可选值来工作有点奇怪。通常客户应该是包含可选性的值,匹配应该是客户是否有值。
在类型系统中处理错误的典型方法是使用 Either
类型。
type Either<'a,'b> =
| Left of 'a
| Right of 'b
通常右值携带成功结果,左值携带错误或异常(作为 string
或 exc
类型)。一种简单的思考方法是将其视为 option
,其中 Right
对应于 Some
情况,而不是 None
您有错误信息。
所以你的代码可以变成:
// QueryData no longer needs to depend on side effects to work,
//so you can make it a regular function instead of a method
let result = queryData()
match result with
| Left ex ->
// handle exception
printfn "%s" ex.Message
| Right result ->
// either set the property, or make customer a record
// and set the name field here
customer.LastName <- result
printfn "%s" customer.LastName
关于错误代码的一点听起来很不对劲,想知道你在哪里找到的。
我是 f# 世界的新手。我写了一个非常小的应用程序,它从 sap 查询数据并将结果显示为输出。当应用程序尝试连接 sap 时,它可能会抛出一些异常,以防出现问题。
看下面的代码:
type Customer() =
let mutable _lastName = String.Empty
member self.LastName with get () = _lastName
member self.QueryData () =
//Some CODES here
let bapi = SapBapi()
let bapiFunc = bapi.GetBapiFunc(dest, "BAPI_CUSTOMER_GETDETAIL1")
match bapiFunc with
| Success bp ->
//Some CODES here
let addressData = bp.GetStructure("PE_PERSONALDATA")
_lastName <- addressData.GetString("LASTNAME")
None
| RfcCommunication ex ->
Some(ex :> Exception)
| RfcLogon ex ->
Some(ex :> Exception)
| RfcAbapRuntime ex ->
Some(ex :> Exception)
如您所见,我使用选项类型处理错误,并将抛出的异常向下转换为基本异常类型。
在主函数中
open CustomerBapi
open System
[<EntryPoint>]
let main argv =
let customer = CustomerBapi.Customer()
let ex = customer.QueryData()
match ex with
| Some ex ->
printfn "%s" ex.Message
| None ->
printfn "%s" customer.LastName
Console.ReadLine() |> ignore
0 // return an integer exit code
此代码有效,但我是否以正确的方式处理异常?
我在网上看过一篇文章,说在 f# 中处理异常应该 return 一个错误代码,它比异常样式更容易。
总的来说,我认为你的解决方案还可以,但可以改进。
您在代码中混合了一些功能和 OO 风格。我觉得你把异常作为唯一的可选值来工作有点奇怪。通常客户应该是包含可选性的值,匹配应该是客户是否有值。
在类型系统中处理错误的典型方法是使用 Either
类型。
type Either<'a,'b> =
| Left of 'a
| Right of 'b
通常右值携带成功结果,左值携带错误或异常(作为 string
或 exc
类型)。一种简单的思考方法是将其视为 option
,其中 Right
对应于 Some
情况,而不是 None
您有错误信息。
所以你的代码可以变成:
// QueryData no longer needs to depend on side effects to work,
//so you can make it a regular function instead of a method
let result = queryData()
match result with
| Left ex ->
// handle exception
printfn "%s" ex.Message
| Right result ->
// either set the property, or make customer a record
// and set the name field here
customer.LastName <- result
printfn "%s" customer.LastName
关于错误代码的一点听起来很不对劲,想知道你在哪里找到的。