powershell(ver1.0) で try-catch
2.0 は実装されたらしい。
でもなんか 1.0 使うらしい。
ネタ元
http://csharper.blog57.fc2.com/blog-entry-177.html
必要に迫られて catch の複数対応。
つかんだ例外の $Error は削除してる。
function CatchStatements ( $catchBlocks, $ex, [ref]$isCatched ) { for( $i = 0; $i -lt $catchBlocks.Count; $i++ ) { $targetExceptionType = $catchBlocks[$i][0]; $catchBlock = $catchBlocks[$i][1]; if (($() -eq $targetExceptionType) -or ( $targetExceptionType.IsAssignableFrom($ex.GetType())) ) { &$catchBlock $ex; $Error.RemoveAt($Error.Count-1); $isCatched.Value = $true; return; } } $isCatched.Value = $false; return; } function global:try { $currentArgIndex = 0; $tryBlock = $args[$currentArgIndex]; $currentArgIndex++; $catchBlocks = New-Object Collections.ArrayList; if ($tryBlock -isnot [Management.Automation.ScriptBlock]) { throw New-Object "ArgumentException" @("try ブロックの指定が不正です。"); } for( $i = $currentArgIndex; $i -lt $args.Length; $i++ ) { if ("catch" -eq $args[$currentArgIndex]) { $currentArgIndex++; if ($args[$currentArgIndex] -is [Type]) { $targetExceptionType = $args[$currentArgIndex]; $currentArgIndex++; } else { $targetExceptionType = [Object] } $catchBlock = $args[$currentArgIndex]; $currentArgIndex++; if ($catchBlock -isnot [Management.Automation.ScriptBlock]) { throw New-Object "ArgumentException" @("catch ブロックの指定が不正です。"); } $null = $catchBlocks.Add( @( $targetExceptionType, $catchBlock ) ); } elseif ("finally" -eq $args[$currentArgIndex]) { $currentArgIndex++; $finallyBlock = $args[$currentArgIndex]; $currentArgIndex++; if ($finallyBlock -isnot [Management.Automation.ScriptBlock]) { throw New-Object "ArgumentException" @("finally ブロックの指定が不正です。"); } break; } } if (($() -eq $catchBlock) -and ($() -eq $finallyBlock)) { throw New-Object "ArgumentException" @("catch ブロックまたは finally ブロックを指定してください。"); } & { $requireFinally = ($() -ne $finallyBlock); & { &$tryBlock; trap { if ($() -eq $catchBlock) { break; } $ex = $_.Exception; $isCatched = $false; CatchStatements $catchBlocks $ex ([ref]$isCatched); if( !$isCatched ) { break; } else { continue; } } }; if ($requireFinally) { $requireFinally = $False; &$finallyBlock; } trap { if ($requireFinally) { $requireFinally = $False; &$finallyBlock; } break; } }; }
try { throw New-Object ArgumentException; throw New-Object ApplicationException; throw New-Object Exception; } catch([ArgumentException]) { "ArgumentException"; } catch([ApplicationException]) { "ApplicationException"; } catch { "others"; } finally { "finally block"; }
問題となるパターン
function TestA() { try { # なんか処理 "process 1"; throw New-Object Exception; } catch { "error"; return; } "process 2"; } TestA;
出力
process 1 error process 2
return したところで function の return まではできないってこと。
もともとない言語仕様を無理に拡張するやりかただし。
「わかって」使えば問題ない。知らないと罠にはまるわけだが。
でも他にもワナがありそうな…!?