.NET経験者ほどハマる！？UiPathのTryCatch（トライキャッチ）挙動について

# はじめに
過去に Java や VB.Net、C# 等に触れたことがあるのですが、それらに共通する TryCatch 周りの挙動と UiPath の挙動があまりに違っていたことに衝撃を受けたので、そのあたりをまとめてみました。

気づいたきっかけは @masatomix 様の以下 Qiita 記事です。（いつも参考にさせていただいております）

https://qiita.com/masatomix/items/d8839b21cb09513e19ef

<font color="red">**トライキャッチ**アクティビティが、Finally を実行しないケースがある</font>…ですと…!?
というわけで VB.Net と UiPath でまったく同じソースを作成し、挙動の違い等を検証してみました。

# 検証環境
- UiPath
Studio Pro 2021.6.0-beta.4514（Community License）

- 使用パッケージ
UiPath.System.Activities v21.4.1

# Finally が実行されないパターン
1. Exception() 発生
1. Catch節でログ出力
1. Catch節で再スロー
1. Finally節でログ出力

という動作パターンで比較してみます。

### VB.Net で実行

```vb:VB.Net
Module Program
    Sub Main(args As String())
        Call Sample()
    End Sub

    Sub Sample()
        Try
            Throw New Exception()   ' 例外発生

        Catch ex As Exception
            Console.WriteLine("Catch：Exception")
            Throw    ' 再スロー

        Finally
            Console.WriteLine("Finally")
        End Try
    End Sub
End Module
```

```:結果（VB.Net）
Catch：Exception
Unhandled exception. System.Exception: Exception of type 'System.Exception' was thrown.
Finally
```

:point_up: VB.Net では、Catchブロック内での再スロー後に Finally が実行されていることを確認できました。

### UiPath で実行
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/368775/b901d0e3-37c6-e57f-c4ae-9bfbf56a4689.png)

```:結果（UiPath）
[Info] TEST の実行が開始されました。
[Info] Catch：Exception
[Error] スロー: 種類 'System.Exception' の例外がスローされました。
[Info] TEST の実行が終了しました。 in: 00:00:00
```

まったく同じソースを UiPath で再現したところ、なんと**<font color="red"> Finally が実行されていません！</font>**
VB.Net とは違う動きをしました。
**再スロー**アクティビティは、このあたりを抑えて使用しないと危険ですね。

:::note info
Finally は、Tryブロック、もしくはCatchブロックを最後まで実行したときのみ、正常に呼ばれる。
:::

### 再スローアクティビティの対策
では**再スロー**アクティビティは基本使用しないほうがいいのでしょうか？
そうではなく、個人的には上記仕様を理解した上でなら効果的に使えると考えています。

また以下の手法で、**再スロー**アクティビティを使用しつつ Finally も正常に実行できるよう対策可能です。

- Catch節での再スローを、さらに上位の TryCatch で拾う

先ほど UiPath サンプルで使用したトライキャッチ自体を、**さらに外側のトライキャッチで囲んで**みました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/368775/e082db8e-6d6e-a58c-dd2e-799137db11c2.png)

実行結果は以下です。

```:結果（UiPath）
[Info] TEST の実行が開始されました。
[Info] Catch：Exception
[Debug] 再スロー
[Info] Finally
[Info] 【外側】Finally
[Info] TEST の実行が終了しました。 in: 00:00:00
```

今度は<font color="red">再スロー後の Finally が実行されました！</font>
どうやら UiPath は以下の仕様のようです。

:::note info
再スローアクティビティがスローした例外を捕捉する機構が備わっていれば、Finally が正常に実行される。
:::

よって外側をもう一つ**トライキャッチ**で囲わなくても、実は [グローバル例外ハンドラー](https://docs.uipath.com/studio/lang-ja/docs/global-exception-handler) を設定するだけで再スロー後に Finally が実行されることも確認できました。

[グローバル例外ハンドラー](https://docs.uipath.com/studio/lang-ja/docs/global-exception-handler) の有無だけで Finally 実行有無が変わる、というのは Studio 上でワークフローをパッと見ただけではなかなか気づけないポイントなので注意が必要です。

# Catch節の定義順に伴う到達箇所について
検証していくうちに、Finally 実行有無とは別の違いも見えてきたのでまとめます。

検証：**Catch節の定義順によって、VB.Net と UiPath で動作差異がある**

### VB.Net で実行

```vb:VB.Net
Module Program
    Sub Main(args As String())
        Call Sample()
    End Sub

    Sub Sample()
        Try
            Throw New ArgumentNullException()   ' 例外スロー

        Catch ex As Exception
            Console.WriteLine("Catch：Exception")

        Catch ex As SystemException
            Console.WriteLine("Catch SystemException")

        Catch ex As ArgumentException
            Console.WriteLine("Catch：ArgumentException")

        Catch ex As ArgumentNullException
            Console.WriteLine("Catch：ArgumentNullException")
        End Try
    End Sub
End Module
```

実行前からコンパイラが警告を出している糞コード:sweat_smile:ですが、検証用のためご容赦下さい。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/368775/9a8c437a-07f5-d1bd-aa90-518a4018ec59.png)
VB.Net、C#、Java すべてに共通して言えますが、Catch節の定義順というのは意味があります。各例外クラスが親子関係にある場合、親クラスに該当する Catch ブロックが存在するとそこで捕捉されます。

上記例の場合、全ての例外クラスの親クラスである `Exception` が Catch 節で最初に定義されているため、どんな例外が発生しても `Catch ex As Exception` で捕捉されてしまい、それ以外の Catch ブロックに到達することはありません。（だからコンパイラが警告を出している）

もちろん実行結果は以下の通りです。

```:結果（VB.Net）
Catch：Exception
```

### UiPath で実行
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/368775/ead032ac-8db4-3094-ad49-8f548063edbe.png)

```:結果（UiPath）
[Info] TEST の実行が開始されました。
[Info] Catch：ArgumentNullException
[Info] TEST の実行が終了しました。 in: 00:00:01
```

なんと<font color="red"> Exception ではなく、ArgumentNullException に到達</font>しました！
ここも VB.Net とは違う動きをするようです。

:::note info
UiPath のトライキャッチでは、Catch 節の定義順に関係なく、スローされた例外と一致する Catch 節で捕捉される
:::

# 最後に
トライキャッチ周りは UiPath 独特の動きが多いなー、という印象を持ちました。

次回はUiPathを使ったAPI連携の記事を予定しています。