C#では、StreamReader
を使用してファイルを1行ずつ読み取ります。また、エラーメッセージの可能性を報告するために、現在の行の番号をint
に保持しています。
各行の読み取りにはいくつかのテストが伴います(たとえば、_#
_で始まる行はコメントであり、スキップする必要があります)。そのため、読み取り手順全体を関数に配置して、それまで読み取りを続けることを計画しています。有用な行に遭遇し、その行を返します。 EOF
に遭遇すると、単にnull
を返します。
この関数をstring read(StreamReader sr, out int lineNumber)
と定義したときは賢いと思っていましたが、C#はその関数内で_lineNumber++
_のようなことを実行できないことがわかりました。変数がまだ割り当てられていないことを前提としています。おそらく、この関数呼び出しの前に変数が割り当てられているかどうかを知る方法がないためです。
したがって、問題は単純です。この変数がinout
パラメーターであることをどのように指定できますか(これが用語だと思います。他のプログラミング言語のコンテキストで言及されていると聞きました)。そもそもこれは可能ですか? lineNumber
をクラスのメンバーにするつもりは絶対にありませんなので、それはオプションではありません。
その場合、ref
の代わりにout
パラメーターが必要です。 out
キーワードを使用すると、値を割り当て/インスタンス化する責任は、 召命 メソッドと呼ばれます。 ref
を使用すると、呼び出されるメソッドの外側にあります。
Outの代わりにrefキーワードを使用します。これにより、呼び出し元は呼び出す前に引数を初期化する必要があります。
Refパラメータに渡される引数は、最初に初期化する必要があります。これを、outパラメーターに渡す前に引数を明示的に初期化する必要がないoutパラメーターと比較してください。
Refはあなたが必要とするものです
MSDN
メソッドパラメータのrefmethod parameterキーワードにより、メソッドは、メソッドに渡されたのと同じ変数を参照します。メソッド内のパラメーターに加えられた変更は、制御が呼び出し元のメソッドに戻るときにその変数に反映されます。
誰もが言うように、あなたは単にref
を使うことができます。
あなたがそれを知っているように、私は別のアプローチを提案するつもりです。
_IEnumerable<Line>
_を返すメソッドを作成できます。ここで、Line
は、テキストの行と行番号をカプセル化するだけの非常に単純なクラスです。
_public class Line
{
public string Text;
public int Number;
}
_
次に、行を読み取る方法は次のようになります。
_public IEnumerable<Line> ReadLines(StreamReader sr)
{
int number = 0;
while (true)
{
string line = sr.ReadLine();
if (line == null)
break;
++number;
if (wantLine(line)) // Some predicate which decides if you want to keep the line.
yield return new Line{Text = line, Number = number};
}
}
_
次に、次のように使用できます。
_public void Test()
{
StreamReader sr = new StreamReader("Whatever");
foreach (var line in ReadLines(sr))
{
if (line.Text == "SomeSpecialValue")
doSomethingWith(line.Text, line.Number);
}
}
_
これは書くのに手間がかかりますが、コードがより明確になる可能性があると思います。また、行番号カウンターがReadLines()
内に完全に隠されているという利点もあります。 (クラス内のフィールドであるという意味では、クラスのメンバーではありません。メソッド内の単なるローカル変数です。)