IEnumerable の遅延実行ではまる例

先ほど軽くはまったのでメモです。

次のコードは、正しく動作しません。

IEnumerable GetItems(){
    using (var db = CreateDataContext()) {
        return db.Table;
    }
}

void Main(){
    var items = GetItems();
    foreach(var x in items) {
        Console.WriteLine(x.Title);
    }
}

理由です。
db.Table に実際にアクセスされるのは、Main メソッドの foreach で items を使用した時点ですが、この時すでに DataContext インスタンスが破棄されているためデータベースにアクセスできずにエラーが発生します。

もう少し詳しく説明すると、GetItems メソッドが return している db.Table は IQueryable型です。
これは、データベースへのアクセスに関する定義を返すだけで、実際に取得したコレクションインスタンスを格納している訳ではありません。
一方 IQueryable 型は IEnumerable 型を継承しているため、GetItems メソッドのように暗黙の型変換が実行されています。
ここに気づかないとはまる訳です。
GetItems メソッドを以下のようにすると、正しく動作するようになります。

using (var db = CreateDataContext()) {
    return db.Table.ToList(); // ←変更
}

理由は、ToList メソッドで取得したデータからコレクションインスタンスを生成したものを返すためです。
簡単な理由ですが、実際の開発コードでは、複雑にメソッドが絡み合っていたりするので、軽くはまるのでメモしておきます。