この場合、例外でパターンマッチングが失敗するのはなぜですか?

私はこの単純な例外階層を持っています:

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)

これらの3つの(ダミー)関数:

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を呼び出すと、簡単に確認できます。

  • firstFunctionはFirstLevelExceptionを発生させます。
  • secondFunctionはそれをキャッチし、SecondLevelExceptionにラップしてスローします。
  • thirdFunctionはそれをキャッチし、ThirdLevelExceptionにラップしてスローします。
  • 呼び出し側がThirdLevelExceptionをキャッチすることができます。

すべての良い。今度は、次のようにthirdFunctionを変更します:

member this.ThirdFunction a =
    25 |>
    try
        this.SecondFunction
    with
    | :? SecondLevelException as ex -> raise (new ThirdLevelException("three", ex))

物事が奇妙になります:ThirdFunction内のパターンマッチングがもう機能しないように見えて、SecondLevelExceptionはThirdLevelExceptionにラップされずにThirdFunction呼び出し元まで完全に伝播します。

私は、C#の変更された心が見ることができないという論理的な説明があると確信しています。誰かが光を放つことができますか?

2
あなたが例外を過度に使いすぎているように見えます...代わりにこれを差別化された組合としてモデリングしてみましたか?
追加された 著者 Mauricio Scheffer,
あなたが正しいですが、これは問題を示すダミーサンプルです。
追加された 著者 Francesco De Vittori,

1 答え

The behavior you described is correct - when you write 25 |> expr, the code in expr is evaluated and the result (a function) is then called with 25 as the argument.

あなたの場合、 expr の結果は関数であり、(functionを返す)式の評価は 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)))

実際にこの種のコードを書く人は誰もいませんが、問題を示すことを願っています!

BTW:これは、パイプラインで例外を処理するための以前のSOの質問に関連していると思います。 そこに回答が追加されました。これは問題の理解に役立ちます。 (問題は、パイプライン関数を try .. with でラップしても、パイプライン関数 inside で発生する例外を防ぐことができないということです)。

7
追加された
クリック!私はそれが論理的であることを知っていた!ありがとう!
追加された 著者 Francesco De Vittori,