Effective C# 3rd 読書メモ 48 例外:強い保証を使用する

例外が投げられると、処理の流れは中断される。不適切な方法で例外を投げると、それをハンドリングすることは困難である。例外の投げ方にはベストプラクティスがある。

  1. 基本的な保証
  2. 強い保証
  3. no-throw保証

基本的な保証は、例外が投げられた後でも、そのメソッドにおいて全てのオブジェクトがリークせず、有効な状態であることを意味する。強い保証は、基本的な保証に加えて、例外が発生した場合でも、プログラムの状態が変わらないことを意味する。no-throw保証は、処理が絶対に失敗せず、例外が投げられないことをいう。

このうち、強い保証を採用することが、安全性とシンプルさの点からバランスがよい。強い保証のもとでは、メソッドの結果は、処理が完了するか、何も変わらないかのいずれかである。中間点はない。強い保証の利点は、例外をキャッチした後でも処理を継続しやすいことだ。

強い保証のためには以下のような(今までに紹介してきた)テクニックが使用できる。

  • プログラムが使用するデータはイミュータブルな値型に入れる
  • LINQクエリのような関数型プログラミングのスタイルを使用する

データの書き換えは以下の様式に沿って行うべきである。

  1. 変更されるデータのコピーを作成する
  2. コピーに対して変更を行う
  3. コピーをオリジナルと置き換える

しかし、強い保証を使用するとパフォーマンスの問題が発生することもある。たとえば、ループで大量のオブジェクトを書き換える場合には、コピーを作って差し替える方式は効率が悪い。

また、差し替え方式は、参照型では使用することができない。コピーとオリジナルと差し替えても、オリジナルを参照しているオブジェクトが残っている場合があるからだ。

実用的な対処法は、以下のように新しくデータを作り直すことである。

上の方法は絶対確実な方法とはいえない。絶対確実にするためには、以下のように、データを包含するクラス(Envelope)を作成し、そのクラスに置き換えを行わせる必要がある。

このクラスは以下のように使用する。

所感

「強い保証」の考え方はRDBMSのトランザクションっぽくて面白い。1メソッドを1トランザクションと考えて、そのメソッド内で処理が完了すればコミット、何かうまくいかないことがあればロールバック。

Effective C# 3rd 読書メモ 47 アプリケーション固有の例外クラスを作る

例外は、発生した場所から遠く離れた場所で処理されることがある。例外オブジェクトには、エラーの発生原因に関する情報が全て含まれていなければならない。アプリケーション固有の例外を作りたくなるかもしれないが、そのためには様々な事項を考慮する必要がある。

はじめに、新しい例外を作る場合とその理由、作成方法について理解する必要がある。独自の例外クラスは、あなたのライブラリの利用者が、その例外をキャッチして特別な処理を行いたいと考えられる場合にのみ追加すべきである(たとえば、引数がnullの場合に例外を投げるだけなら、ArgumentExceptionで十分かもしれない)。

例外クラスの名前の末尾は「Exception」でなければならない。System.Exceptionか、あるいはそれ以外の適切な例外クラスを継承すべきである。また、ベースクラスの全てのコンストラクタを引き継ぐべきである。System.Exceptionをベースにした例外クラスは以下のように定義できる。

モダンJavaScriptの練習に:『Electronではじめるアプリ開発』

Electronは、Webの技術(HTML+CSS+JavaScript)を使用してデスクトップアプリケーションを構築するためのフレームワークです。Atom、Visual Studio Codeといったモダンなエディタや、Slackのデスクトップ版などに利用されています。ChromiumというChromeのベースとなっているブラウザを使用することで、Windows/macOS/Linuxといった様々なOS上で動作する、クロスプラットフォームなデスクトップアプリケーションを構築することができます。

本書では、ES2015 + Reactという組み合わせでアプリケーションを構築していきます。ES2015やReactについての詳しい解説は無いので、あらかじめES2015のクラス構文やアロー関数式、Reactの基本的な使い方を身に着けておいたほうが読みやすいでしょう。

ES2015については『改訂新版JavaScript本格入門』がおすすめです。Reactについては、公式チュートリアルをやっておけば大丈夫でしょう。
以下のようなソースを見て、だいたい何をやっているかわかればOKです。

本書には、様々なライブラリを活用して、手早く高機能なアプリケーションを構築する方法が記載されています。また、各章はチュートリアル形式になっているので、実際に手を動かしながら学ぶことができます。Electronに興味がある人だけでなく、モダンなJavaScriptアプリケーションの組み方について理解を深めたい人にもおすすめできる内容です。

Effective C# 3rd 読書メモ 46 リソースの後始末にusingとtry/finallyを利用する

.NET Frameworkの管理下にない(アンマネージド)リソースを使用する型は、Dispose()メソッドによって明示的に解放すべきである。Dispose()メソッドをもつ型を使うときに、Dispose()を実行するのは あなたの 責任である。Dispose()が必ず呼ばれるようにする最良の方法は、using文を使うか、try/finallyブロックを使うかである。

同様の処理をtry/finallyで書くと以下のようになる。

usingはコンパイル時の型がIDisposableを実装している場合にのみ利用可能で、任意の型に対して利用できるわけではない。

以下のように、usingをキャストと共に使うと、(1) objがIDisposableを実装している場合は、using文が実行される (2) objがIDisposableを実装していない場合は、using文は実行されない という結果になる。

Effective C# 3rd 読書メモ 45 メソッドの契約が満たされない場合に例外を使用する

メソッドが定められた振る舞いを行うことができない場合、例外によって失敗を報告すべきである。エラーコードの戻り値はたやすく無視されるし、エラーコードのチェックや伝播は正常系のコードを汚染し、中核となるロジックをわかりづらくする。

しかし、例外を通常の制御構造として使用してはいけない。このことは、publicメソッドを提供する際には、通常の使用で例外が投げられる確率をできるだけ減らさなければならない、ということでもある。

そのため、メソッドの事前条件が満たされるかテストするメソッドを別に提供し、例外を避けられるようにするのがよい(プログラマーが事前条件のテストを忘れれば例外が飛ぶが、これは正しい挙動である)。