# この記事は以前 C#と諸々 に書いた記事 (を一部修正したもの) です。
PowerShell V1.0 では、C# の try – catch – finally のような構造化例外処理がサポートされていません。しかし、trap ブロック、throw ステートメント、break ステートメント、continue ステートメント、そしてスコープについて理解すれば、try – catch – finally を擬似的に再現することができます。
というわけで、次のコードのように C# の try – catch – finally に近い例外処理を実現する関数を書きました。
try {
# 処理
} catch ([例外の型]) {
param($ex)
# 例外処理
} finally {
# 後処理
}
使用する際は次の点に気を付けてください。
- 各ブロックの開始の "{" の前と各ブロックの終了の "}" の後ろは、上記のように、改行せずに記述する必要があります。
- 例外の型は、上記のように、必ず "()" で囲む必要があります。
- catch または finally は、省略可能です。例外の型も省略可能です。
- catch ブロック内では、break ステートメントを使用して例外を再スローすることができます。当然、任意の例外を throw ステートメントでスローすることもできます。
で、これらを実現するための関数がこちらです。
function global:try
{
$currentArgIndex = 0;
$tryBlock = $args[$currentArgIndex];
$currentArgIndex++;
if ($tryBlock -isnot [System.Management.Automation.ScriptBlock])
{
throw New-Object "ArgumentException" @("try ブロックの指定が不正です。");
}
if ("catch" -eq $args[$currentArgIndex])
{
$currentArgIndex++;
if ($args[$currentArgIndex] -is [Type])
{
$targetExceptionType = $args[$currentArgIndex];
$currentArgIndex++;
}
$catchBlock = $args[$currentArgIndex];
$currentArgIndex++;
if ($catchBlock -isnot [System.Management.Automation.ScriptBlock])
{
throw New-Object "ArgumentException" @("catch ブロックの指定が不正です。");
}
}
if ("finally" -eq $args[$currentArgIndex])
{
$currentArgIndex++;
$finallyBlock = $args[$currentArgIndex];
$currentArgIndex++;
if ($finallyBlock -isnot [System.Management.Automation.ScriptBlock])
{
throw New-Object "ArgumentException" @("finally ブロックの指定が不正です。");;
}
}
if (($() -eq $catchBlock) -and ($() -eq $finallyBlock))
{
throw New-Object "ArgumentException" @("catch ブロックまたは finally ブロックを指定してください。");
}
&{
$requireFinally = ($() -ne $finallyBlock);
&{
&$tryBlock;
trap
{
if ($() -eq $catchBlock)
{
break;
}
$ex = $_.Exception;
if (($() -ne $targetExceptionType) -and (!$targetExceptionType.IsAssignableFrom($ex.GetType())))
{
break;
}
&$catchBlock $ex;
continue;
}
};
if ($requireFinally)
{
$requireFinally = $False;
&$finallyBlock;
}
trap
{
if ($requireFinally)
{
$requireFinally = $False;
&$finallyBlock;
}
break;
}
};
}
以下のスクリプトを実行すると、動作が確認できます。
try {
"try ブロック実行";
throw New-Object "ArgumentException";
"この文は出力されない";
} catch ([ArgumentException]) {
param ($ex)
"{0} がスローされたから catch ブロック実行" -f $ex.GetType().Name;
} finally {
"finally ブロック実行";
}
出力は以下のようになります。
try ブロック実行
ArgumentException がスローされたから catch ブロック実行
finally ブロック実行
なお、PowerShell V2.0 では、try – catch – finally が標準でサポートされるようです。なので、V2.0 ではこの関数は不要になるのですが、もし V1.0 で try – catch – finally を使用したいという方はぜひこの関数を試してみてください。
コメント
よこけんさんの、このテクニックいいですよね。
PowerShellだと通常、trapを使用しますが、VB.NETやC#を使っている方にとっては、try~catchの方が非常になじみやすいですよね。
非常に勉強になります