Antecedência C # ReadLine () para a próxima linha em uma chamada de função

StackOverflow https://stackoverflow.com/questions/1467041

  •  13-09-2019
  •  | 
  •  

Pergunta

Na minha C # app que eu estou tentando alimentar em ReadLine () um documento de texto simples com 7 cordas dígitos separados linha por linha. O que eu estou tentando fazer é pegar a próxima seqüência de 7 dígitos cada vez que a função é chamada. Aqui está o que eu tenho até agora:

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;
    }

Como faço para avançar para a próxima linha de cada vez que o invoiceNumberFunc () é chamado?

Agradecemos antecipadamente.

Foi útil?

Solução

Você precisa de manter a preensão do StreamReader entre chamadas, ou passá-lo para o método como um novo parâmetro ou tornando-se uma variável de membro da classe.

Pessoalmente eu prefiro a idéia de se tornar um parâmetro, para que nunca acaba como uma variável de membro - que faz com que o tempo de vida mais fácil de gerir:

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;
}

Outras dicas

Você não pode, desde que você criar e descartar o leitor de fluxo na função. Duas formas vêm à mente:

Você pode armazenar o leitor de fluxo em uma variável de membro, ou ler tudo de uma vez e armazenar uma matriz em uma variável de membro.

Ou você faz um método iterator alterando o tipo de retorno para IEnumerable<string>, e mudando a parte no bloco using a:

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

Desta forma, você pode chamar foreach em seu invoiceNumberFunc.

Você precisa usar o mesmo StreamReader em vez de criar um novo. Cada vez que você criar um novo e descartar o antigo você está começando para trás logo no início do arquivo.

Tente passar a mesma referência StreamReader ou manter um registro da posição que você está em na corrente e usando Seek () sobre o fluxo de base, se necessário. Eu recomendo o primeiro deles pessoalmente.

Você precisa refazer este, de modo que você não está criando o StreamReader dentro do método, mas em vez de criá-la no nível de classe, e apenas usá-lo no método, em seguida, descartar / fechar o leitor quando você está feito. Algo como:

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;
        }
    }
}

Neste caso, ele também pode ser uma boa idéia para fazer a sua IDisposable classe para que você possa verificar se o StreamReader fica disposto, e também, potencialmente, fazer "inicializar" / "fechar" rotinas, em vez de fazer a inicialização e desligamento como eu fiz aqui.

O que você está procurando é o comando 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();
        }
    }
}

Agora você pode consumir o retorno desta função com um simples para cada um: -

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

Ou seja criativo com o LINQ.

Uma outra maneira de fazer isso é transformar a sua função em um bloco de iterator usando o declaração de rendimento retorno

A única coisa é certificar-se de adicionar uma cláusula finalmente ao seu tentar remover a captura como o retorno de rendimento não pode ser usado em uma tentativa nua / catch. Portanto, o seu código seria:

    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
        {
        }
    }
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top