我有一个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分钟编辑,删除不相关的代码。]
答案 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