F#异常没有被正确抓住

时间:2011-03-25 17:10:30

标签: exception exception-handling f#

我有一个F#异常,它没有被正确的catch块捕获。

以下是相关代码:

exception ConfigFileVersionIncompatabilityException of string

[<XmlType("config")>]
type Configuration() = class

    let thisVersion : string = "1.0"
    let mutable fileVersion : string = thisVersion

    [<XmlAttribute("version")>]
    member x.FileVersion
        with get() = fileVersion
        and set v = if v <> thisVersion
                    then raise (ConfigFileVersionIncompatabilityException(String.Format("Was expecting version {0} but read version {1}.", thisVersion, v)))
end


module FilterFileFunctions =

    let sampleConfigFilename = "sample.filters"

    let readConfig (file : string) =
        try
            use xmlDoc = new StreamReader(file) in
                let s = XmlSerializer(typeof<Configuration>)
                s.Deserialize(xmlDoc) :?> Configuration |> Success
        with
        | ConfigFileVersionIncompatabilityException(s) ->
            String.Format("Failed to read the configuration file: \"{0}\";\nThe following reason was given:\n{1}", file, s)
            |> Failure
        | ex ->
            String.Format("Failed to read the configuration file: \"{0}\";\n{1}", file, ex)
            |> Failure

问题是ex catch块捕获ConfigFileVersionIncompatabilityException异常,它应该被第一个块捕获。

我尝试使用:? System.Exception as ex而不只是ex,但它的行为仍然相同。

我错过了什么吗?

[在首发后1分钟编辑,删除不相关的代码。]

1 个答案:

答案 0 :(得分:6)

在反序列化期间发生异常时,Deserialize方法将捕获它并将其包装在InvalidOperationException中。这意味着您需要聊聊InvalidOperationException,然后分析InnerException属性以获取用户定义的异常。

try // ..
with 
| :? InvalidOperationException as invOp ->
   match inv.InnerException with 
   | :? ConfigFileVersionIncompatabilityException as e -> 
     printfn "%s" e.Data0
   | _ -> // generic handler
| e -> // generic handler

Data0属性公开异常携带的值(我使用它,因为在使用:?时,您无法在模式匹配中轻松访问它)。但是,您可以使用活动模式避免match表达式(以及通用处理程序的重复)的丑陋嵌套:

let (|InnerException|) (e:exn) =
    e.InnerException

try // ..
with 
| InnerException(ConfigFileVersionIncompatabilityException s) -> 
   printfn "%s" s
| _ -> // generic handler