Streamの罠

MSDNのサンプルプログラムでは、ファイルの最後まで読み込んだかどうかを確認するのにPeek() < 0 を使ってる事がある。こんな感じ。

    while(sr.Peek() > -1){
        string line = sr.ReadLine();
    }

でも、この使い方にはワナがある。そのStreamがファイルではなく、何かのリダイレクトとか非同期に入力があるものを読み込んでいるときに使ってはいけない。仕事でreadelfを子プロセスとして起動して標準出力を解析して・・・ってプログラムを書いたら、readelfの出力に親プロセスの読み込みが追いついたところでPeek()が-1を返して止まってしまった。
じゃぁどうすれば良いんや?ってなると・・・とりあえず無限ループにして、EOFかどうかはあとでチェックする。無限ループカコ悪いけど、どうしたらカコイイのか判らん。

    while(true){
        string line = sr.ReadLine();
        if(line == null) break;
    }

ちなみに、↓は条件式が副作用を持つ書き方で好ましくない。lineのスコープが不必要にループの外に出てしまうという弊害もある。古いCプログラマは簡単にコレを使うけど、ダメダメだね。こんな書き方するヤツがいるから「定数は左」なんて汚いルールができるんだ。

    while((line = sr.ReadLine()) != null){
    }

しかし、なぜMSはこの書き方を用意しなかったのだろう?

    while(!sr.Eos()){  // EOS := End Of Stream
        string line = sr.ReadLine();
    }


ついでに、BinaryReaderでPeek()するとこういう罠もあるらしい。普通のファイルでも使っちゃダメ。
http://d.hatena.ne.jp/akiramei/20060308/p1

このブログに乗せているコードは引用を除き CC0 1.0 で提供します。