我有这个简单的异常层次结构:
type FirstLevelException(msg) = inherit System.Exception (msg)
type SecondLevelException(msg, inner) = inherit System.Exception (msg, inner)
type ThirdLevelException(msg, inner) = inherit System.Exception (msg, inner)
和这三个(虚拟)功能:
member this.FirstFunction a =
raise (new FirstLevelException("one"))
member this.SecondFunction a =
try
this.FirstFunction a
with
| :? FirstLevelException as ex -> raise (new SecondLevelException("two", ex))
member this.ThirdFunction a =
try
this.SecondFunction 25
with
| :? SecondLevelException as ex -> raise (new ThirdLevelException("three", ex))
当您调用ThirdFunction时很容易看到:
一切都好。现在我按以下方式更改thirdFunction:
member this.ThirdFunction a =
25 |>
try
this.SecondFunction
with
| :? SecondLevelException as ex -> raise (new ThirdLevelException("three", ex))
事情变得很奇怪:看起来ThirdFunction中的模式匹配不再起作用,并且SecondLevelException一直传播到ThirdFunction调用者,而不包含在ThirdLevelException中。
我确信有一个合乎逻辑的解释是我的C#变形的头脑看不到。有人可以解释一下吗?
答案 0 :(得分:7)
您描述的行为是正确的 - 当您编写25 |> expr
时,将评估expr
中的代码,然后使用25
作为参数调用结果(函数)。
在您的情况下,expr
的结果是一个函数,表达式的评估(返回函数)受try
块的保护。但是,一旦返回该函数,它将转义try
块,并在异常处理程序之外进行调用。
要在这个返回的函数中移动异常处理,你必须写这样的东西:
25 |> (fun n ->
try
// You need to call the function (i.e. give it something as an argument)
// inside the try-with block, otherwise it won't be executed here!
this.SecondFunction n
with
| :? SecondLevelException as ex -> raise (new ThirdLevelException("three", ex)))
在实践中没有人会写这种代码,但我希望它能证明这个问题!
顺便说一句:我想这与您之前关于处理管道中异常的SO问题有关。我added answer there,可以帮助您理解问题。 (问题是try .. with
中管道的包装操作不会阻止在流水线函数中发生的异常。)