2

私のC#アプリでは、7桁の文字列が1行ずつ区切られた単純なテキストドキュメントをReadLine()にフィードしようとしています。私がやろうとしているのは、関数が呼び出されるたびに次の7桁の文字列を取得することです。これが私がこれまでに持っているものです:

string invoiceNumberFunc()
    {
        string path = @"C:\Users\sam\Documents\GCProg\testReadFile.txt";
        try
        {
            using (StreamReader sr = new StreamReader(path))
            {
                invoiceNumber = sr.ReadLine();

            }

        }
        catch (Exception exp)
        {
            Console.WriteLine("The process failed: {0}", exp.ToString());
        }
       return invoiceNumber;
    }

invoiceNumberFunc()が呼び出されるたびに次の行に進むにはどうすればよいですか?

前もって感謝します。

4

6 に答える 6

8

StreamReader新しいパラメータとしてメソッドに渡すか、クラスのメンバー変数にするかのいずれかで、between呼び出しを保持する必要があります。

個人的には、それがパラメーターになるという考えを好みます。そうすれば、メンバー変数として終わることはありません。これにより、ライフタイムの管理が容易になります。

void DoStuff()
{
    string path = @"C:\Users\sam\Documents\GCProg\testReadFile.txt";
    using (StreamReader sr = new StreamReader(path))
    {
        while (keepGoing) // Whatever logic you have
        {
            string invoice = InvoiceNumberFunc(sr);
            // Use invoice
        }
    }
}

string InvoiceNumberFunc(TextReader reader)
{
    string invoiceNumber;
    try
    {
        invoiceNumber = reader.ReadLine();
    }
    catch (Exception exp)
    {
        Console.WriteLine("The process failed: {0}", exp.ToString());
    }
    return invoiceNumber;
}
于 2009-09-23T16:15:17.850 に答える
2

関数でストリームリーダーを作成して破棄するため、できません。2つの方法が思い浮かびます。

ストリームリーダーをメンバー変数に格納することも、一度にすべてを読み取って配列をメンバー変数に格納することもできます。

または、returnタイプをに変更し、ブロックIEnumerable<string>内のパーツを次のように変更して、イテレータメソッドにします。using

while ((invoiceNumber = sr.ReadLine()) != null) {
    yield return invoiceNumber;
}

このように、あなたはあなたのを呼び出すことができforeachますinvoiceNumberFunc

于 2009-09-23T16:18:25.923 に答える
1

新しいStreamReaderを作成するのではなく、同じStreamReaderを使用する必要があります。新しいファイルを作成し、古いファイルを破棄するたびに、ファイルの先頭に戻って開始します。

同じStreamReader参照を渡すか、ストリーム内の現在の位置の記録を保持し、必要に応じてベースストリームでSeek()を使用してみてください。私はこれらの最初のものを個人的にお勧めします。

于 2009-09-23T16:14:46.413 に答える
1

これをやり直す必要があります。これにより、メソッド内にストリームリーダーを作成するのではなく、クラスレベルで作成し、メソッドで使用するだけで、完了したらリーダーを破棄/閉じることができます。何かのようなもの:

class MyClass
{
    private StreamReader sr;

    string invoiceNumberFunc()
    {
        if (sr == null) 
            sr = new StreamReader(path);

        if (sr.EndOfStream)  {
            sr.Close();
            sr = null;
            return string.Empty;
        }

        try {
            return sr.ReadLine();
        }
        catch(Exception exp) {
            Console.WriteLine("Process failed {0}",exp.ToString());
            return string.Empty;
        }
    }
}

この場合、IDisposableStreamReaderが破棄されることを確認できるようにクラスを作成し、ここで行ったように初期化とシャットダウンを行う代わりに、「初期化」/「閉じる」ルーチンを作成することもお勧めします。

于 2009-09-23T16:17:57.423 に答える
1

あなたが探しているのはyieldコマンドです:-

IEnumerable<string> GetInvoiceNumbers()
{
    string path = @"C:\Users\sam\Documents\GCProg\testReadFile.txt";
    using (StreamReader sr = new StreamReader(path))
    {
        while (!sr.EndOfStream)
        {
           yield return sr.ReadLine();
        }
    }
}

これで、この関数の戻り値をそれぞれの単純なもので消費できます。-

foreach(string invoiceNumber in GetInvoiceNumbers())
{
   //Do Stuff with invoice number
}

または、LINQでクリエイティブになりましょう。

于 2009-09-23T16:22:33.840 に答える
1

これを行う別の方法は、yieldreturnステートメントを使用してイテレータブロックで関数を変換することです。

唯一のことは、tryにfinally句を追加し、catchを削除することです。これは、yieldreturnを裸のtry/catchでは使用できないためです。したがって、コードは次のようになります。

    IEnumerable<String> invoiceNumberFunc()
    {
        string path = @"C:\Users\sam\Documents\GCProg\testReadFile.txt";
        try
        {
            using ( System.IO.StreamReader sr = new System.IO.StreamReader( path ) )
            {
                String invoiceNumber;
                while ( ( invoiceNumber = sr.ReadLine() ) != null )
                {
                    yield return sr.ReadLine();
                }
            }
        }
        finally
        {
        }
    }
于 2009-09-23T16:24:27.860 に答える