Exception F#未正确捕获异常

Exception F#未正确捕获异常,exception,exception-handling,f#,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 [&

我有一个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
异常配置文件版本不兼容字符串异常
[]
类型配置()=类
让此版本:string=“1.0”
让可变文件版本:字符串=此版本
[]
成员x.FileVersion
使用get()=fileVersion
并设置v=if v此版本
然后引发(ConfigFileVersionInCompatibilityException(String.Format(“预期版本为{0},但读取版本为{1}.”,thisVersion,v)))
结束
模块过滤器文件函数=
让sampleConfigFilename=“sample.filters”
let readConfig(文件:string)=
尝试
在中使用xmlDoc=newstreamreader(文件)
设s=XmlSerializer(typeof)
s、 反序列化(xmlDoc):?>配置|>成功
具有
|ConfigFileVersionInCompatibilityException->
String.Format(“未能读取配置文件:\“{0}\”;\n给出了以下原因:\n{1}”,文件,s)
|>失败
|ex->
Format(“未能读取配置文件:\“{0}\”;\n{1}”,文件,ex)
|>失败
问题是,
ex
catch块捕获了
ConfigFileVersionInCompatibilityException
异常,第一个块应该捕获该异常

我试着使用
:?System.Exception作为ex
而不仅仅是
ex
,它的行为仍然相同

我错过什么了吗


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

当反序列化过程中出现异常时,
反序列化
方法将捕获该异常并将其包装在
InvalidOperationException
中。这意味着您需要聊天
invalidooperationexception
,然后分析
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

当反序列化过程中发生异常时,
反序列化
方法将捕获异常并将其包装在
InvalidOperationException
中。这意味着您需要聊天
invalidooperationexception
,然后分析
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

它起作用了!我真的应该从它显示的消息中发现异常被包装在另一个异常中。好吧。我必须更多地研究活动模式——虽然我在Haskell工作过一段时间,但我对F#还是相当陌生。看来你的39.2k代表是当之无愧的,非常感谢!它起作用了!我真的应该从它显示的消息中发现异常被包装在另一个异常中。好吧。我必须更多地研究活动模式——虽然我在Haskell工作过一段时间,但我对F#还是相当陌生。看来你的39.2k代表是当之无愧的,非常感谢!