Emacs における日本語文字コードの設定
今回は Emacs における日本語の文字コードおよび改行コードの設定についての記事です。
文字コードの設定は基本的なものであれば、簡単なのですが、
Windows でデフォルトを UTF-8 にしようとしたりすると少し複雑になります。
ただし、逆に言えば Emacs では細かな設定まで可能ということでもあります。
その細かな設定までできるように解説してみたいと思います。
言語環境の設定
まず、文字コードの設定で最初に行うのは、言語環境を日本語(Japanese)に設定することです。 「何故、文字コードの設定で言語環境を設定するか」というと、 言語環境を設定すれば最低限の文字コードの設定が行われるからです。言語環境の設定は init.el などの設定ファイルに set-language-environment で指定します。
(set-language-environment "Japanese")言語環境は [Options(オプション)] メニューからも設定できます。 オプションの設定を変えた場合は [Save Options(オプションの保存)]を忘れないようにして下さい。
[Options] → [Multilingual Environment] → [Set Language Environment] → [Javanese] ([オプション] → [言語] → [言語環境の設定] → [日本語])言語環境を日本語に設定すれば、環境に合わせた日本語文字コードが設定されます。 Windows では Shift-JIS 、 Unix 系では EUC-JP などユーザーが環境として選んでいる文字コードです。
その設定で良ければ、これで文字コードの設定は完了です。
しかし、 より細かな設定をするためにはこの後に文字コードの設定を追加していくことになります。
なお、文字コードも変わるため、必ず 言語環境の設定した後に文字コードの設定を記述しなければなりません。
オプションのメニューでの設定はカスタマイズの場合と同じでデフォルトでは設定ファイルの最後に追加されます。 set-language-environment 関数を使うかカスタマイズ用の別ファイルにしてロードするようにして下さい。
文字コードのシンボル
文字コードはシンボルを使って指定します。よく使うものを以下の表にまとめました。これ以外にもありますが、そちらは M-x list-coding-systems で確認してください。
シンボル | 文字コード |
---|---|
shift_jis | Shift-JIS |
cp932 | コードページ932 (Windows では正確にはこちら) |
euc-jp | EUC-JP |
utf-8 | UTF-8 (BOM なし) |
utf-8-with-signature | BOM 付き UTF-8 |
また、改行コードは指定がなければシステムに合わせたものになります。 これを変えたい場合は shift_jis-unix のように以下のキーワードと合わせたシンボルを指定します。
キーワード | 説明 |
---|---|
dos | CR + NL |
mac | CR |
unix | NL |
対象別の文字コード指定
デフォルトの文字コードを設定する場合には prefer-coding-system を使います。(prefer-coding-system 'utf-8)同じような関数に set-default-coding-systems というのもあります。 ただし、ヘルプによれば prefer-coding-system の方は改行コードとのセットのシンボルも使えるようですので、 こちらを覚えておいた方がいいでしょう。
この設定によって指定される文字コードは以下の項目です。
- ファイルを新規作成した場合のデフォルト
- サブプロセスでの IO
- 他の項目が指定されていない場合のデフォルト値
設定関数 | 対象 |
---|---|
set-file-name-coding-system | ファイル名 |
set-keyboard-coding-system | キーボード |
set-terminal-coding-system | ターミナル(コンソール) |
例えば、 Windows ではファイル名やキーボードは Shift-JIS(cp932) ですので、 prefer-coding-system で Shift-JIS 以外を指定した場合はこれらの変更は必須となります。
ターミナルの設定は Windows ではあまり使うことはないと思いますが、 GUI ではなく、ターミナルで Emacs を使う場合に必要となります。
(prefer-coding-system 'utf-8) (set-file-name-coding-system 'cp932) (set-keyboard-coding-system 'cp932) (set-terminal-coding-system 'cp932)ここで注意点は prefer-coding-system では BOM 付きの UTF-8 (utf-8-with-signature) を指定してはいけないということです。
サブプロセスでの文字コードも変わってしまうため、 grep やコンパイルなどで外部プログラムをちゃんと呼び出せなくなります。
この対応としては default-process-coding-system 変数でプロセスの文字コードを変えればいいのですが、 それよりもデフォルトをシフトJISにしてファイルのデフォルトを変えた方が早いでしょう。
ファイルのデフォルトの文字コード指定
開いているバッファーのファイルの文字コードを変更する場合には set-buffer-file-coding-system (C-x RET f)を使います。しかし、これを設定で書いても意味がありません。 バッファーごとの文字コード(buffer-file-coding-system) はバッファーローカルな値なので、 ロードしているバッファーの文字コードが変わるだけです。
新規作成時のファイルのデフォルトを変える場合には set-default 関数を使って buffer-file-coding-system のデフォルト値を変更します。
(set-default 'buffer-file-coding-system 'utf-8-with-signature)以前はファイルのデフォルトの文字コード指定には default-buffer-file-coding-system 変数を使う方法もありました。 しかし、 Ver. 23.2 にから非推奨(obsolete)になったため、 buffer-file-coding-system を
set-default
で変更した方がよいでしょう。
ファイルの種別ごとの文字コード指定
文字コードは最近では UTF-8 が使われるのが主流になってきました。 UTF-8 は日本語が冷遇されているので不満はありますが、 文字コードが統一されるのはいいことだと思います。しかし、残念ながら文字コードは統一されていません。 UTF-8 でも 「BOM 付き派」と 「BOM なし派」とがあるためです。 状況はよりやっかいになったとも言えます。
Microsoft 製品では BOM 付きでなければちゃんと動かないことがあります。 一方、 Unix や Java 系のツールや言語では BOM なし派です。
VS 用には BOM 付きがいいですが、 Java など JVM 言語では BOM なしでなければなりません。
そんな中 Emacs ではファイル種別ごとに文字コードを指定することができます。
ただし、この設定は Emacs の文字コード判定よりも優先されるため、 JVM 言語のように BOM なし UTF-8 以外はうけつけないようなソースに限った方がいいと思います。
ファイル種別ごとの文字コードを指定する場合は modify-coding-system-alist で設定します。
(modify-coding-system-alist 'file "\\.java\\'" 'utf-8) ;; Java (modify-coding-system-alist 'file "\\.clj\\'" 'utf-8) ;; Clojure (modify-coding-system-alist 'file "\\.\\(scala\\|sbt\\)\\'" 'utf-8) ;; Scala (modify-coding-system-alist 'file "\\.[eh]rl\\'" 'utf-8) ;; Erlang (modify-coding-system-alist 'file "\\.exs?\\'" 'utf-8) ;; Elixirなお、 Scala の scala-mode2 の場合はパッケージをインストールすると自動的にこの設定が追加されます。 この設定をカスタマイズで行う場合には file-coding-system-alist の変数を変更します。
- M-x customize-option [RET] file-coding-system-alist

ペアでの指定はエンコード、デコードをそれぞれ指定しているものです。 一つだけ指定すれば、両方共に同じものが使われます。
Windows での設定
最後に参考として Windows での私の設定をあげておきます。;; ベースは Shift-JIS のまま (set-language-environment "Japanese") ;; ファイルのデフォルトを HTML や C++ 用に BOM 付き UTF-8 (set-default 'buffer-file-coding-system 'utf-8-with-signature) ;; BOM なし UTF-8 でなければならない言語 (modify-coding-system-alist 'file "\\.clj\\'" 'utf-8) ;; Clojure (modify-coding-system-alist 'file "\\.exs?\\'" 'utf-8) ;; Elixir ; ...ただし、実際には私はカスタマイズやオプションの方を使って設定するので、 これはコピペしやすいようにコードに直したものです。
C# やるなら LINQ を使おう
C# では Ver. 3.0 から LINQ という機能が追加されました。
LINQ の処理は C, C++, Java などから移ってきた人には馴染みにくいらしいです。
実際、 LINQ がなくてもアプリは作れないこともないですし、
C# を使っているけど、 LINQ は使っていないという人もいるのではないでしょうか。
しかし、それは非常にもったいないです。
私も C, C++ を使ってきた人間ですが、同時に Ruby や Lisp 好きでもあるので、
LINQ は素晴らしい機能だと思います。
今回はそんな LINQ の魅力の紹介と
LINQ を使っていくための入門的な記事を書いてみました。
LINQ の魅力
標準クエリー演算子とクエリー式
LINQ には SQL のようなクエリー式と 通常のメソッド形式の標準クエリー演算子の 2 つの書き方ができます。その特異さのため、 LINQ というとクエリー式に目が行きがちです。 しかし、 私の思う LINQ の魅力はそんなところにはありません。
SQL に馴染みがある人はクエリー式で書くのもいいとは思いますが、 私はほとんどクエリー式は使ったことがなく、この説明でも標準クエリー演算子の方で説明していきます。
OOP より関数型のコードが短くなるという誤解
まれに "オブジェクト指向プログラミング(OOP)よりも関数型プログラミングの方がコードが短くなる" といわれることがあります。しかし、これは誤解です。
Scala, Clojure など最近よく使われる関数型言語は C++ や Java に比べたら、 短いコードで書けることは間違いありません。
ただ、その要因の大部分は、最近の関数型言語が 配列などのコレクションを高階関数を使って処理できる機能を持っているところにあります。 この機能は関数型言語にとって大事な機能ですが、 参照透過性などのパラダイムのポイントとは直接は関係ありません。
これは言い換えると、パラダイムに関係なく言語がこの機能を持っていれば、コードを短くすることができるということです。また、短いだけでなく、書きやすくかつわかりやすいコードにもなります。
そのため、 Ruby を始めとする多くの言語で使われるようになってきています。
- 特集:人気言語でのデータ処理の比較: C#/ Scala / Python / Ruby / F#でデータ処理はどう違うのか? (1/3) - @ IT
- Dart における高階関数を使ったデータ処理 | プログラマーズ雑記帳
- lodash を使った JavaScript における関数型のデータ処理 | プログラマーズ雑記帳
C# が出た当初は、言語仕様としては Java に毛が生えた程度のしょぼいものだったのですが、 この LINQ の登場により、 Java を大きく突き放したと思ったものでした。
ただ Java も Java 8 からは似たような機能が追加され、追いついてきています。 C++ でも C++14 からは同様なことができるようになるらしいです。 それだけこの機能が多くの人に便利だと思われてる証とも言えるでしょう。
高階関数を使ったデータ処理
私が思う LINQ の魅力は Ruby や関数型プログラミングでよく使われる 高階関数を使ったデータ処理です。前節で書いたように LINQ を使えばいろいろなデータ処理を楽に書けますし、 LINQ ではそのための多くのメソッド(標準クエリー演算子)が用意されています。
しかし、逆にメソッドが多すぎてどれから覚えればいいのか分からないこともあるかもしれません。 今回は LINQ のメソッドの中で最初に覚えておいた方がいいなというメソッドを紹介します。
LINQ の対象
これまで処理の対象をデータと表記していますが、 これは LINQ が配列やリストのようなコンテナーだけでなく、 様々なものに対しても LINQ の操作メソッドを使うことができるためです。- あらかじめ用意されたコンテナーだけでなく、自作のコンテナークラスにも使える
- XML 、 データベースなどあらかじめいろいろと用意されている
- 用意されているだけでなく、 yield で対象を簡単に自作できる
これは Ruby の Mix-in の魅力と同じで、キーとなるメソッドを実装するだけで、 自作のコンテナーがあらかじめ用意されたコンテナーばりに高機能になることを意味します。 ただ、 IEnumerable<T> の実装は若干クセがあります。 それについては以前の記事で書いているので、そちらを見てください。 今回は自作コンテナー以外の対象について説明していきたいと思います。
LINQ の主要メソッド
それでは、ここから LINQ のメソッドでまず最初に覚えておいた方がよいと思われる機能について説明していきます。高階関数を用いたデータ処理における主要な機能は次の 5 つです。
- 逐次処理(each)
- 写像(map)
- フィルター(filter)
- 並び替え(sort)
- 畳み込み(fold)
ただし、 LINQ では SQL に寄せているため、 他の言語で使われている名前と違う名前になっています。
Select : 写像(map)
写像というのは map, mapping と呼ばれる処理で、 配列などのコレクションのメンバーに一つずつ関数を適用して 戻り値で新しいコレクションを作ります。
他言語では map という名前になっていることが多いですが、 LINQ では Select() です。
var src = new[] {3, 2, 9, 6}; var mapped = src.Select(elem => elem * 2); // {6, 4, 18, 12}Select に渡す関数は要素の型を引数にとる関数で、その戻り値が新しいコレクションの要素となります。 Select は渡す関数の戻り値の型を変えれば、 値を変えるだけでなく、型を変えた新しいコレクションも作ることができ、 用途の広いメソッドです。
渡す関数は、通常の関数でもいいですし、匿名メソッドやラムダ式のような無名関数でも構いません。
static int foo(int elem) { return elem * 2; } // : src.Select(foo);
src.Select(delegate(int elem) {return elem * 2;});通常の関数などの場合には、渡す関数の型にあったものしか渡せませんが、そういった場合にはカリー化と呼ばれる手法を使うこともできます。 以降のサンプルでは、一番短く書けるラムダ式を使っていくことにします。
Where : フィルター(filter)
フィルターは他言語では filter, find_all, select などメソッド名が使われます。 これはコレクションの中から条件にあう要素を取り出す処理です。
LINQ では Where() という名前になっています。
var src = new[] {3, 2, 9, 6}; var filtered = src.Where(elem => elem % 2 == 1); // {3, 9}データ処理で重要なメソッドをさらに絞るとすると、前節のマップとこのフィルターが、 特に重要度が高いです。
OrderBy, ThenBy : 並び替え(sort)
並び替えは通常 sort という名前のメソッドで、 コレクションの要素の並び替えを行います。他言語の sort では比較用のメソッドを渡すものなのですが、 LINQ の OrderBy() では比較に使う値を指定する関数を渡します。 OrderBy で指定した値で同じ値になる場合には ThenBy() で順列をつけることができます。
var possrc = new [] { new { x = 1, y = 2 }, new { x = 3, y = 4 }, new { x = 1, y = 1 } }; var sorted = possrc.OrderBy(elem => elem.x).ThenBy(elem => elem.y); // {{ x = 1, y = 1 }, { x = 1, y = 2 }, { x = 3, y = 4 }}OrderBy, ThenBy は昇順で並び替えを行います。 降順にしたい場合はそれぞれ OrderByDescending, ThenByDescending を使います。
Aggregate : 畳み込み(fold)
畳み込みは他言語では fold, reduce, inject などの名前ですが、 LINQ では Aggregate() (集める)という名前です。これは他の処理に比べると、利用頻度は低い上に難易度も少し高いです。 ただ、わりと応用も効きますし、使いこなせているとちょっと通っぽいです。
この処理は先に使用例を見てもらった方がわかりやすいでしょう。
var src = new[] {3, 2, 9, 6}; src.Aggregate((sum, elem) => sum + elem); // 20 src.Aggregate((max, elem) => (max < elem) ? elem : max); // 9 src.Aggregate(0, (count, elem) => count+1); // 4渡された関数を各メンバーに適用していき、その結果を重ねたものが Aggregate の戻り値として得られます。
渡す関数は 2 つの引数を取り、 1 つ目がそれまでの計算の結果で、2 つ目が各要素です。 関数の戻り値として返したものが、次の 1 つ目の引数に入るという繰り返しになります。 合計の例を順に記述すると次のようになります。
{3, 2, 9, 6} (3, 2) => 3 + 2 ↓ (5, 9) => 5 + 9 ↓ (14, 6) => 14 + 6 ↓ 201 番最初は 1 つ目の引数が最初の要素で、2 番目の要素から始めることになります。 また、 count の例のように初期値を与え、最初の要素から始めることもできます。
このように畳み込みは要素を順に取得し、新しい値を返す処理です。

ここで挙げた例は実はどれも Sum, Max, Count とすでに LINQ のメソッドは用意されています。 よく使われるからこそ用意されているのであり、広く応用できるのがわかると思います。
その他のメソット
データ処理の定番のメソッド以外で、 LINQ のメソッドとして抑えておいた方がいいかなと思うものも挙げて置きます。- Count
-
要素数(サイズ)の取得。
var src = new[] {3, 2, 9, 6}; src.Count(); // 4
- Take
-
指定した要素数の取り出し。
var src = new[] {3, 2, 9, 6}; src.Take(2); // {3, 2}
- First, Last
-
指定した条件に最初(最後)にマッチする要素の検索。
検索もデータ処理ではよく行う処理ですが、 条件にあうすべての要素を取得するのがフィルター(Where)で、 最初の要素を取得するのが First です。var src = new[] {3, 2, 9, 6}; src.First(elem => elem % 2 == 1); // 3 src.Last( elem => elem % 2 == 1); // 9
- Max, Min
-
要素の最大(最小)値の取得
var src = new[] {3, 2, 9, 6}; src.Min(); // 2 src.Max(); // 9
- Contains
-
要素を含んでいるかの判定。
var src = new[] {3, 2, 9, 6}; src.Contains(9); // True src.Contains(1); // False
- All, Any
-
要素すべて(どれか一つ)が条件を満たすかどうかの判定。
var src = new[] {3, 2, 9, 6}; src.All(elem => elem % 3 == 0); // False src.Any(elem => elem % 3 == 0); // True
- Distinct
-
重複する要素の除去。(2 つ目以降がなくなる)
var src = new[] {3, 3, 2, 9, 2, 6, 2}; src.Distinct(); // {3, 2, 9, 6 }
サンプルコード
説明で使用したサンプルのコードは以下のリンクからダウンロード(リンク先を保存)できます。 コンパイルする場合は以下のコマンドを実行します。> csc StdQueryOperators.cscsc.exe を使用したコンパイル方法については以前の記事を見て下さい。
遅延評価
LINQ の重要な要素に遅延評価というものがあります。 これについて説明します。メソッドの連結と遅延評価
遅延評価の説明の前にもう少し基本的なところから始めましょう。いまさらですが、 LINQ のメソッドの使える対象とは何でしょうか?
いろいろなものに使えると最初に書きましたが、 型で言うと IEnumerable<T> インターフェースを継承したクラスです。 インターフェースですが、これに拡張メソッドという機能を使って、 IEnumerable<T> がメソッドを持てるようになっています。 IEnumerable<T> を継承したものというのも長いので、 ここではシーケンスと呼びます。
先ほどの Select() や Where() は新しいコレクションを返します。 この戻り値がシーケンスです。 正確な型はコンパイラーが生成する複雑なものなので、 変数に入れたい場合などは var を使った型推論が必要となります。
Console.WriteLine("{0}", src.Select(elem => elem * 2)); // => System.Linq.Enumerable+WhereSelectArrayIterator`2[System.Int32,System.Int32]シーケンスを返すメソッドは続けて書くことができます。
var src = new[] {3, 2, 9, 6}; var seq = src.Where(elem => elem % 2 == 1) .Select(elem => elem * 2); foreach (var elem in seq) { Console.Write("{0} ", elem); } Console.WriteLine(); // => 6 18このシーケンスには必要になるまで実行されないという遅延評価の機能があります。 上記の例では foreach で一つずつ取り出す時が実行のタイミングです。
連結の処理は一見、次のように処理してるように見えます。
Where Select {3, 2, 9, 6} → {3, 9} → {6, 18}しかし、実際には遅延評価により、メソッドごとに結果をためるのではなく、 1 要素ずつ流すように次のメソッドに渡していきます。
Where Select 3 → 3 → 6 2 → ☓ 9 → 9 → 18 6 → ☓実行するのは "必要なとき" です。
そのため、ソート(OrderBy)のような全要素が揃わないと完了しないようなメソッドの場合は、 その時点で要素は溜まることになります。
なお、「遅延評価を本当にやっているの ? 」と気になる方は、 以前の記事で確認用のコードを書いているので、そちらを見て下さい。
遅延評価のメリット
遅延評価は関数型プログラミングでは並列性のために欠かせない機能です。 関数型の話を抜きにしたとしても、遅延評価には大きなメリットがあります。それは処理結果を溜めないため、使用メモリーを減らせる点です。
例えば、 File クラス には、 指定したファイルの全行を文字列の配列として取得する ReadAllLines() というメソッドがあります。
これはループを回して1行ずつ取り出す必要がなく便利なのですが、 ログファイルのように大きなファイルに使うと大量のメモリーを使用してしまうことになります。
そこで ReadAllLines のシーケンス版である ReadLines() を使えば、 一行ずつ渡してくれるようになります。
CatFile.cs (抜粋) :
foreach (string line in File.ReadLines(fpath)) { Console.WriteLine(line); }「一行ずつ取りたいなら普通にループ回して一行ずつ読み取ればいいのでは ? 」 と思うかもしれませんが、シーケンスを返しているので、 それに対して LINQ の豊富なメソッドを使えるという利点があります。
LazySample.cs (抜粋) :
public static IEnumerable<int> ReadValues(string fpath) { var ptn = new Regex(@"\d+"); return File.ReadLines(fpath) .Select(line => ptn.Match(line).Value) // マッチした数字か空文字 .Where(str => !String.IsNullOrEmpty(str)) // 空文字を抜く .Select(str => int.Parse(str)); // 数値に変換 } // : // 使用 foreach (int val in ReadValues(args[0])) { Console.WriteLine("{0}", val); }
~/cs/LINQ $ cat test.txt # テスト用ファイル # test.txt 67 28 # 鉄人 999 # 銀河鉄道 009 # サイボーグ ~/cs/LINQ $ ./LazySample.exe test.txt 67 28 999 9なお、 foreach のところで実行するということは、 ptn の正規表現オブジェクトはローカル変数なので、 もう存在していないのではないかと思うかもしれません。 しかし、そこはクロージャーという技術によって、 無名関数に使うオブジェクトはうまいこと残してくれるようになっています。
コンテナー以外への LINQ の適用
LINQ はコンテナー以外でも、先ほどのファイルの読み取りや データベース(DB)、 XML などいろいろなものに使えます。というよりも、 LINQ はもともと DB や XML の処理しやすくすることをメインに導入されたものでしょう。
ここからは、コンテナー以外への LINQ の適用例を紹介したいと思います。 ただ、 DB や XML だとサンプルとして大きくなってしまうので、 もっと簡単な例にします。
フォルダーを走査して、 特定の条件にあるファイルのリストを取得したいといった処理はよくあると思います。 これも LINQ を使って処理することができます。
FindFile.cs (抜粋) :
/// <summary> /// dirPath 以下のファイルの中で str の文字列を含むファイル名のファイル群を返す /// </summary> public static IEnumerable<string> SearchDir(string dirPath, string str) { // 指定フォルダーのファイルをサブフォルダーまで列挙 DirectoryInfo di = new DirectoryInfo(dirPath); IEnumerable<System.IO.FileInfo> fiList = di.GetFiles("*.*", SearchOption.AllDirectories); return fiList .Where(fi => // str を含むかでフィルター (0 <= fi.Name.IndexOf(str, StringComparison.CurrentCultureIgnoreCase))) .Select(fi => fi.FullName); // フルパスに変換 } // : // 使用 foreach (string path in SearchDir(dirPath, str)) { Console.WriteLine(path); }
~/cs/LINQ $ ./FindFile.exe cs .
Search "." for "cs"
d:\home\cs\LINQ\BinFileIo.cs
d:\home\cs\LINQ\CatFile.cs
d:\home\cs\LINQ\FindFile.cs
d:\home\cs\LINQ\LazySample.cs
d:\home\cs\LINQ\StdQueryOperators.cs
d:\home\cs\LINQ\test.cs
シーケンスの自作
前章で LINQ にはいろいろデータのものが用意されていると書きましたが、 そうはいっても、すべてのケースが用意されているはずもありません。しかし、そんな場合でも、自分でシーケンスを返す関数を作ることができます。
File クラスの ReadLines はテキストファイル用のものでした。 サンプルとして自分で構成を定義したバイナリーファイル版 ReadLines を作ってみましょう。
バイナリーファイルの構成は、ヘッダーとして要素数が記述され、 その後に整数値が連続しているというシンプルなものにします。
| 要素 | バイト数 | 格納値(例) | |----------|----------|------------| | ヘッダー | 4 bytes | 4 | | 1 st | 4 bytes | 3 | | 2 nd | 4 bytes | 2 | | 3 rd | 4 bytes | 9 | | 4 th | 4 bytes | 6 |シーケンスを返す関数は IEnumerable<T> を戻り値として、 yield return で値を返すようにします。 返す値は IEnumerable<T>の T の型です。(サンプルでは int)
BinFileIo.cs :
// バイナリー版 ReadLines private static IEnumerable<int> ReadData(string fpath) { using(BinaryReader br = new BinaryReader(File.OpenRead(fpath))) { // 先頭は要素数 int siz = br.ReadInt32(); // 要素数分、読み取った値を返す for (int cnt = 0 ; cnt < siz ; cnt++) { yield return br.ReadInt32(); } } }ファイルのオープンに使っている using については以下の記事をご覧ください。 関数の戻り値がシーケンスなので、 ReadLines と同じように使えます。
foreach (int it in ReadData(testfile)) { Console.WriteLine("{0}", it); }
~/cs/LINQ $ ./BinFileIo.exe
3
2
9
6
まとめ
最後に LINQ を身につけるまでの手順をまとめておきます。最初は配列やリストなど C# が用意しているコンテナークラスに LINQ のメソッドを使っていきましょう。
まずは Select(マップ)と Where(フィルター) だけでも十分役に立つと思います。 この記事で紹介したメソッドや次のページを見て少しずつ増やしていって下さい。 また、自作のコンテナークラスを作るときには、 以下の記事を参考にして IEnumerable<T> を継承しておくようにしましょう。
コンテナー以外の対象に広げていくにはどれが使えるのか知っておく必要があります。 しかし、これはいろいろあるので、 使うクラスを調べるとき、 IEnumerable<T> クラスを継承していないか、 IEnumerable<T> を返すメソッドを持っていないか なども見ておいて、少しずつ増やしていくしかありません。
ただ、この記事の yield で自作する方法を身につけておけば、 大抵のものには使えるので、増やしていくのはゆっくりで構わないと思います。