以正确的方式处理异常

时间:2015-03-05 09:00:39

标签: f#

我是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#中处理异常应该返回一个错误代码,它比异常风格更容易。

2 个答案:

答案 0 :(得分:2)

在类型系统中处理错误的典型方法是使用Either类型。

 type Either<'a,'b> =
     | Left of 'a
     | Right of 'b

传统上,Right值带有成功结果,Left带有错误或异常(作为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

关于错误代码的一点听起来非常错误,想知道你在哪里找到它。

答案 1 :(得分:0)

总的来说,我认为您的解决方案没问题,但可以改进 您在代码中混合了功能和OO样式。对于我来说,使用异常作为唯一可选值感觉有点奇怪。通常,客户应该是包含可选性的值,并且如果客户具有值,则匹配应该是。