F# Exception Not Being Caught Correctly
I have an F# exception that it is not being caught in the correct catch block.
Here's the relevant code:
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.Fo开发者_如何学运维rmat("Failed to read the configuration file: \"{0}\";\n{1}", file, ex)
|> Failure
The problem is that the ex
catch block catches the ConfigFileVersionIncompatabilityException
exception, where it should be caught by the first block.
I tried to use :? System.Exception as ex
instead of just ex
and it still behaved the same.
Am I missing something?
[Edited 1 minute after initial post to remove irrelevant code.]
When an exception occurs during the deserialization, the Deserialize
method will catch it and wrap it inside InvalidOperationException
. This means that you need to chatch InvalidOperationException
and then analyze the InnerException
property to get to your user-defined exception.
try // ..
with
| :? InvalidOperationException as invOp ->
match inv.InnerException with
| :? ConfigFileVersionIncompatabilityException as e ->
printfn "%s" e.Data0
| _ -> // generic handler
| e -> // generic handler
The Data0
property exposes the value carried by the exception (I used it, because you cannot access it easily in the pattern matching when using :?
). However, you can avoid the ugly nesting of match
expressions (and the duplication of generic handlers) using active patterns:
let (|InnerException|) (e:exn) =
e.InnerException
try // ..
with
| InnerException(ConfigFileVersionIncompatabilityException s) ->
printfn "%s" s
| _ -> // generic handler
精彩评论