1
resposta

[Projeto] Senhas de Atendimento

// Sistema de gerenciamento de senhas de atendimento
bool executar = true;
int senha = 1, proximaSenha = 0;

var SenhasGeradas = new List<int>();

// função para exibir o menu
void ExibirMenu ()
{
    while (executar)
    {
        Console.Clear();
        Console.WriteLine("Escolha uma das opções (1-2-0):");
        Console.WriteLine("[1] Gerar nova senha");
        Console.WriteLine("[2] Chamar próxima senha");
        Console.WriteLine("[0] Sair");
        Console.Write("Escolha uma opção: ");
        string opcaoSelecionada = ValidarOpcaoInformada();
        SelecaoDeOpcoes(opcaoSelecionada);
    }
}

// função para controlar o fluxo do sistema
void SelecaoDeOpcoes (string opcao)
{
    switch (opcao)
    {
        case "1": GerarSenha(); break;
        case "2": ChamarSenha(); break;
        case "0": executar = false; Console.WriteLine("\nEncerrando sistema.");  break;
        default: throw new ArgumentException();

    }
}

// funções das ações do sistema
void GerarSenha()
{
    SenhasGeradas.Add(senha);
    Console.Clear();
    Console.WriteLine($"Nova senha {senha.ToString("D3")} gerada com sucesso!");
    senha++;
    Thread.Sleep(2500);
}

void ChamarSenha()
{
    if (SenhasGeradas.Count == 0)
    {
        Console.Clear();
        Console.WriteLine("Ainda não foi gerada nenhuma senha!");
        Thread.Sleep(2500);
    }
    else if (SenhasGeradas.Count == proximaSenha) 
    {
        Console.Clear();
        Console.WriteLine("Não existem mais senhas na fila!");
        Thread.Sleep(2500);
    }
    else
    {
        Console.Clear();
        Console.WriteLine($"Próxima senha: {SenhasGeradas[proximaSenha].ToString("D3")}");
        Thread.Sleep(5000);
        proximaSenha++;
    }
}

// função para validar dados
string ValidarOpcaoInformada ()
{
    while (true)
    {
        string entrada = Console.ReadLine()!;

        if (!string.IsNullOrWhiteSpace(entrada))
        {
            if (byte.TryParse(entrada, out byte valida) && (valida >= 0 && valida <= 2))
            {
                return entrada;
            }
        }
    }
}

ExibirMenu();
1 resposta

Olá, José. Como vai?

Parabéns pela excelente estrutura do seu código! Você organizou o sistema de senhas de forma modular utilizando funções específicas para cada responsabilidade (ExibirMenu, SelecaoDeOpcoes, GerarSenha, ChamarSenha e ValidarOpcaoInformada), o que deixa o código limpo, fácil de ler e manter.

O uso do método .ToString("D3") foi uma ótima sacada para exibir as senhas no formato padrão de atendimento (como 001, 002), e a validação de entrada com byte.TryParse garante que o console não quebre caso o usuário digite letras ou caracteres especiais.

Para agregar ainda mais valor ao seu projeto e te ajudar a evoluir a lógica, vale a pena analisarmos uma boa prática sobre a estrutura de dados utilizada para filas de atendimento.

Otimizando a Estrutura de Dados: De List para Queue

No seu código, você utilizou uma List<int> combinada com a variável proximaSenha servindo como um ponteiro/índice para controlar quem é o próximo a ser chamado. Isso funciona perfeitamente!

Porém, no mundo real do desenvolvimento em C#, quando criamos sistemas baseados no princípio de FIFO (First In, First Out — o primeiro que entra é o primeiro que sai), a estrutura de dados nativa mais recomendada é a Queue (Fila).

A vantagem da Queue é que ela possui métodos próprios para isso:

  • Enqueue(): Adiciona um elemento no final da fila (equivalente ao seu Add).
  • Dequeue(): Remove e retorna o elemento que está no início da fila. Isso elimina a necessidade de você controlar manualmente a variável proximaSenha.

Veja como o seu código pode ser simplificado usando Queue<int> nas funções principais:

// Substituindo a List por Queue
var SenhasGeradas = new Queue<int>();
int senha = 1;

void GerarSenha()
{
    // Enqueue adiciona a senha no final da fila
    SenhasGeradas.Enqueue(senha);
    Console.Clear();
    Console.WriteLine($"Nova senha {senha.ToString("D3")} gerada com sucesso!");
    senha++;
    Thread.Sleep(2500);
}

void ChamarSenha()
{
    // Se a fila estiver vazia, não há ninguém para chamar
    if (SenhasGeradas.Count == 0)
    {
        Console.Clear();
        Console.WriteLine("Não existem mais senhas na fila!");
        Thread.Sleep(2500);
    }
    else
    {
        // Dequeue remove e já pega a senha do início da fila automaticamente
        int senhaAtual = SenhasGeradas.Dequeue();
        Console.Clear();
        Console.WriteLine($"Próxima senha: {senhaAtual.ToString("D3")}");
        Thread.Sleep(5000);
    }
}

Por que essa mudança é vantajosa?

Usando a fila real (Queue), seu código ganha em performance e legibilidade:

  1. Você não precisa mais gerenciar o índice proximaSenha, reduzindo as chances de bugs de lógica.
  2. A verificação do if fica mais simples, pois basta checar se o Count é igual a zero para saber se a fila acabou.

Seu projeto original demonstra um domínio muito bom de lógica e estruturas de controle (switch, while, tratamento de string). Continue praticando e aplicando esses conceitos!

Espero que possa ter lhe ajudado!