Edited at

C#:IEnumerable<T>の実装サンプルとして簡易catコマンドを作成してみた

この記事は、IEnumerable<T>の実装を理解を深めるために書いたものです。


TextReaderを列挙可能にする

.NET Frameworkには、File.ReadLinesというメソッドが用意されているのですが、入力がファイルに限定されています。しかし、今回作成する簡易catコマンドは、標準入力もサポートしたいので利用できません。

ということで、IEnumerable<T>を実装したEnumerableTextReaderクラスを作成しました。TextReaderオブジェクトから行を順に列挙するクラスです。

汎用性を持たせるために、テキスト形式のStreamも扱えるようにします。

以下、EnumerableTextReaderクラスのソースコードです。

using System;

using System.Collections;
using System.Collections.Generic;
using System.IO;

namespace Cat {
public class EnumerableTextReader : IEnumerable<string> {
private TextReader _sr;

public EnumerableTextReader(TextReader tr) => _sr = tr;

public EnumerableTextReader(Stream s) => _sr = new StreamReader(s);

public IEnumerator<string> GetEnumerator() {
string s;
while ((s = _sr.ReadLine()) != null) {
yield return s;
}
}

IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator();

}
}

このクラスは、IEnumerable<T>インターフェースを実装していますので、テキストファイルに対して、LINQの拡張メソッドが利用できるようになります。とは言っても、簡易catコマンドではLINQのメソッドは利用してないですが...

TextReaderを受け取るコンストラクタを用意していますので、Console.Inを渡せば、標準入力からも行単位で入力データを列挙することができます。


簡易catコマンドを実装する

上記のEnumerableTextReaderクラスを使って、簡易catコマンドを書いてみました。

このプログラムは、標準入力からデータを読み込み、標準出力に書きだすだけの簡単なものです。

使い方は以下のような感じ。

C:\>cat < sample.txt > sample2.txt

これで、sample.txtの内容を、sample2.txtに複写することができます。

以下のようなcatコマンド名だけの場合、キーボードから入力した行をそのままコンソール画面に表示します。この場合は、Ctrl+Zで入力を終了させます。

C:\>cat

以下、EnumerableTextReaderクラスを利用した簡易catコマンドのソースコードです。

using System;

using System.Linq;
using System.Collections.Generic;

namespace Cat {
class Program {
static void Main() {
var reader = new EnumerableTextReader(Console.In);
reader.ForEach(Console.WriteLine);
}
}

public static class EnumerableExtentions {
public static void ForEach<T>(this IEnumerable<T> source, Action<T> action) {
foreach (T x in source) {
action(x);
}
}
}
}


補足

このコード、.NET Core 2.0でも動作確認しています。

ソースは、GitHubで公開しています。


この記事は、Gushwell's C# Programming Pageで公開したものを加筆・修正したものです。