PowerShell で try - catch - finally を実現

by よこけん 28. 7月 2008 02:33

# この記事は以前 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 を使用したいという方はぜひこの関数を試してみてください。

最新のブログ

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

PowerShell

コメント

コメントを書く


 

  Country flag

biuquoteredbluegreenyellowPowerShellTextFile
  • コメント
  • プレビュー
Loading



Calendar

<<  3月 2010  >>
月曜火曜水曜木曜金曜土曜日曜
22232425262728
1234567
891011121314
15161718192021
22232425262728
2930311234

View posts in large calendar
Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2010 PowerShell from Japan!!