F # Исключение неправильно поймано - PullRequest
0 голосов
/ 25 марта 2011

У меня есть исключение F #, что он не перехватывается в правильном блоке перехвата.

Вот соответствующий код:

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ловит исключение ConfigFileVersionIncompatabilityException, где оно должно быть перехвачено первым блоком.

Я пытался использовать :? System.Exception as ex вместо ex, и он по-прежнему вел себя так же.

AmЯ что-то пропустил?

[Отредактировано через 1 минуту после первоначального сообщения для удаления неактуального кода.]

1 Ответ

6 голосов
/ 25 марта 2011

Если во время десериализации возникает исключение, метод 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...