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

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

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

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

Effective C# 3rd 読書メモ 44 バインドされた変数を書き換えてはいけない

以下のコードで、sequence()デリゲートはindex変数をキャプチャしている。

バインドされた変数を書き換えると、遅延実行との関係で予期せぬエラーを生むことがある。クロージャーにバインドされた変数の書き換えは避けるべきである。

Effective C# 3rd 読書メモ 43 Single()とFirst()によってクエリの意味をわかりやすくする

Single()はただ1つの要素だけを返す。要素が存在しなかったり、複数の要素が存在した場合には例外が投げられる。必ず1つ存在するものを取得するにはSingle()を使うのが良い。

0個または1個の要素が返る場合は、SingleOrDefault()を使うことができる。この場合にも、複数の要素があった場合には例外が投げられる。0個の場合にはnullが返る。

複数の要素の中で、1つだけ取り出したい場合には、First()またはFirstOrDefault()を使うことができる。

はじめのいくつかの要素を飛ばして取得したい場合、Skip()を使うことで飛ばすことができる。

Effective C# 3rd 読書メモ 42 IEnumerableとIQueryableのデータソースを区別する

IQueryableとIEnumerableはとても似たAPIシグネチャをもっている。また、IQueryableはIEnumerableを継承している。この2つのインターフェイスは原則として交換可能である。一方、一連の要素(シーケンス)は交換可能とは限らず、そのふるまいやパフォーマンスも大きく異なる。

以下のコードの最終的な出力はどちらも同じだが、裏側で実行される処理は異なる。

前者では、LINQ to SQLライブラリによって2つのLINQを合成してSQLが生成され、SQLが一度だけ実行される。後者では、はじめのLINQから生成されたSQLの実行後、その結果を使用して2番めのLINQがLINQ to Objectsによって実行される。多くの場合、IQueryableのまま使ったほうが、IEnumerableを使うよりもパフォーマンスが良い。

IEnumerableとIQueryableを透過的に扱いたい場合に便利なのがAsQueryable()メソッドである。

Effective C# 3rd 読書メモ 41 高価なリソースのキャプチャを避ける

クロージャとキャプチャされた変数は、変数のスコープの基本原則の例外である。クロージャは境界づけられた変数を格納したオブジェクトを作り出す。これらの変数の生存期間は驚くほど長いことがある。

この挙動は、変数がメモリを消費しているだけである場合にはさほど気にする必要はないが、IDisposableを実装するような高価なリソース(ファイル、DB接続等)である場合には注意が必要である。