BT

最新技術を追い求めるデベロッパのための情報コミュニティ

寄稿

Topics

地域を選ぶ

InfoQ ホームページ ニュース C#機能: Deferredエラー処理

C#機能: Deferredエラー処理

原文(投稿日:2019/04/01)へのリンク

堅牢なソフトウェアを書くときに、再実行可能な操作を実行することがある。システムを堅牢にするために、各操作は以前の操作状況から独立しているようにコード化できる。具体例として、ファイル処理パイプラインを考えてみよう。

パイプラインの最初のステップは、ファイルサーバーをポーリングして、新しく検出されたファイルをダウンロードする。次のステップは、それらのファイルを解析して、より使いやすいフォーマットに変換する。3番目のステップは、その後の処理のために変換されたファイルをデータベースにインポートする。

最初のステップにおいて、いくつかのファイルをダウンロードした後で失敗した場合、アプリケーション全体が中断されるべきではない。代わりに、ダウンロードに成功したファイルを解析する次のステップに進むべきである。失敗したファイルは次のサイクルで拾えばよいので、これは許容できる。

このパターンをC#で実装するには、通常、一連のtry-catchブロックを使用する。

try
{
    DownloadFiles();
}
catch (Exception ex)
{
    //log errors
}
try
{
    ParseAndConvertFiles();
}
catch (Exception ex)
{
    //log errors
}
try
{
    ImportFiles();
}
catch (Exception ex)
{
    //log errors
}

Deferredエラーハンドリング提案では、多くの定型コードを削除できる。

#exception mode deferred
DownloadFiles();
ParseAndConvertFiles();
ImportFiles();
if (Exception.LastException != null)
{
    //log errors
    Exception.ClearLastException();
}
#exception mode structured

deferredエラーハンドリングを使うために、「例外モード(exception mode)」と呼ばれる新しいコンパイラディレクティブが使われる。これにより、現在の関数において、構造化例外処理と新しいdeferredモードの間が切り替わる。

deferredモードでは、エラーが発生したかどうかを判定するためにException.LastExceptionプロパティが使われる。これは最新のエラーのみを格納するため、複数のエラーが発生した場合、最後のエラー以外は失われる。

これは各行のあとでLastExceptionをチェックする必要があることを意味するため、必要なコード量を減らすという目標とは逆で、いくつかの懸念が生じる。

これを解決するための修正案として、LastExceptionをスタックで置き換えることが提案されている。これにより、開発者はすべての例外を発生した時系列の逆順に確認できる。

検討されているもう一つのオプションは、ジャンプ先を指定できるものである。

#exception mode deferred error_handler
[...]
return;

error_handler:
//log error
#exception resume next

「next」修飾子を省略すると、アプリケーションは次の行に進むのではなく、失敗したステートメントを再試行する。

構造化とdeferredエラーハンドリングの両方を同じ関数で同時に使った場合、コンパイラの観点から問題が発生する可能性がある。Deferredモードは、CLRサポートを受けることなく、C#がクロージャーとasync/awaitを実装し、コンパイルされたコードを根本的に変更する。コンパイラに必要な変更を単純化するために、他の構文が検討されている。これはunsafeとcheckedブロックで見るものと同じタイプの構文である。

deferred 
{
    DownloadFiles();
    ParseAndConvertFiles();
    ImportFiles();
}

変更の規模が大きいため、この提案がC# 9よりも前に採用される可能性は低い。

この記事に星をつける

おすすめ度
スタイル

BT