以正确的方式处理异常

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

通常右值携带成功结果,左值携带错误或异常(作为 stringexc 类型)。一种简单的思考方法是将其视为 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

关于错误代码的一点听起来很不对劲,想知道你在哪里找到的。