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接続等)である場合には注意が必要である。

Effective C# 3rd 読書メモ 40 即時実行と遅延実行を区別する

宣言的コードは何をすべき(what)かを定義する。命令的コードはやり方(how)を説明する。どちらも必要だが、両者をごちゃ混ぜにすると予期せぬ振る舞いが発生する。

命令的コードは即時実行される。以下ではMethod1〜3が順番に即時実行される。

これに対して、宣言的コードは、遅延実行されることがある。

上記コードでMethod1〜3のそれぞれが実行されるか、またそれらの実行順序がどうなるかは、DoStuff()の実装次第である。

データをパラメーターとして使うか、関数をパラメーターとして使うかによって、振る舞いは大きく異なる。入力されるデータが小さい場合はデータを渡すほうが良い場合が多い。一方、入出力のサイズが非常に大きく、かつ、全体をメモリに置く必要がない場合は、関数を使ったほうがリソースの節約になる可能性がある。