Compartilhar via


Tutorial: Explorar ideias usando instruções de nível superior para criar código conforme você aprende

Neste tutorial, você aprenderá a:

  • Conheça as regras que regem o uso de instruções de nível superior.
  • Use instruções de nível superior para explorar algoritmos.
  • Refatore explorações em componentes reutilizáveis.

Pré-requisitos

Você precisa configurar seu computador para executar o .NET 6 ou posterior. O compilador C# está disponível a partir do Visual Studio 2022 ou do .NET SDK.

Este tutorial pressupõe que você esteja familiarizado com o C# e .NET, incluindo o Visual Studio ou a CLI do .NET.

Comece a explorar

As instruções de nível superior permitem evitar a cerimônia extra necessária colocando o ponto de entrada do programa em um método estático em uma classe. O ponto de partida típico para um novo aplicativo de console se parece com o seguinte código:

using System;

namespace Application
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
        }
    }
}

O código anterior é o resultado da execução do comando dotnet new console e da criação de um novo aplicativo de console. Essas 11 linhas contêm apenas uma linha de código executável. Você pode simplificar o programa usando a nova funcionalidade de instruções de nível superior. Isso possibilita remover todas as linhas deste programa, exceto duas.

// See https://aka.ms/new-console-template for more information
Console.WriteLine("Hello, World!");

Importante

Os modelos C# para o .NET 6 usam instruções de nível superior. Se você já tiver atualizado para o .NET 6, talvez seu aplicativo não corresponda ao código descrito neste artigo. Para obter mais informações, consulte o artigo sobre Novos modelos C# geram instruções de nível superior

O SDK do .NET 6 também adiciona um conjunto de diretrizes implícitas de para projetos que usam os seguintes SDKs:

  • Microsoft.NET.Sdk
  • Microsoft.NET.Sdk.Web
  • Microsoft.NET.Sdk.Worker

Essas diretivas implícitas global using incluem os namespaces mais comuns para o tipo de projeto.

Para obter mais informações, consulte o artigo sobre Diretivas de uso implícito

Esse recurso simplifica sua exploração de novas ideias. Você pode usar instruções de nível superior em cenários de script ou para explorar. Depois de ter o básico funcionando, você pode começar a refatorar o código e criar métodos, classes ou outros conjuntos para componentes reutilizáveis que você criou. As instruções de nível superior habilitam experimentações rápidas e tutoriais iniciantes. Elas também fornecem um caminho tranquilo da experimentação a programas completos.

As instruções de nível superior são executadas na ordem em que aparecem no arquivo. As instruções de nível superior só podem ser usadas em um arquivo de origem em seu aplicativo. O compilador gera um erro se você usá-los em mais de um arquivo.

Criar um computador de resposta mágico do .NET

Neste tutorial, vamos criar um aplicativo de console que responda a uma pergunta "sim" ou "não" com uma resposta aleatória. Você cria a funcionalidade passo a passo. Você pode se concentrar em sua tarefa em vez da cerimônia necessária para a estrutura de um programa típico. Em seguida, quando estiver satisfeito com a funcionalidade, você poderá refatorar o aplicativo conforme julgar adequado.

Um bom ponto de partida é escrever a pergunta novamente no console. Você pode começar gravando o seguinte código:

Console.WriteLine(args);

Você não declara uma variável args. Para o arquivo de origem único que contém suas instruções de nível superior, o compilador reconhece args como significando os argumentos de linha de comando. O tipo de argumento é um string[], como em todos os programas C#.

O código pode ser testado executando o comando dotnet run a seguir:

dotnet run -- Should I use top level statements in all my programs?

Os argumentos após a linha de comando -- são passados para o programa. Você pode ver o tipo da variável args impressa no console:

System.String[]

Para escrever a pergunta no console, é necessário enumerar os argumentos e separá-los com um espaço. Substitua a chamada WriteLine pelo código a seguir:

Console.WriteLine();
foreach(var s in args)
{
    Console.Write(s);
    Console.Write(' ');
}
Console.WriteLine();

Agora, quando você executa o programa, ele exibe corretamente a pergunta como uma cadeia de caracteres de argumentos.

Responder com uma resposta aleatória

Após ecoar a pergunta, você pode adicionar o código para gerar a resposta aleatória. Comece adicionando uma matriz de respostas possíveis:

string[] answers =
[
    "It is certain.",       "Reply hazy, try again.",     "Don’t count on it.",
    "It is decidedly so.",  "Ask again later.",           "My reply is no.",
    "Without a doubt.",     "Better not tell you now.",   "My sources say no.",
    "Yes – definitely.",    "Cannot predict now.",        "Outlook not so good.",
    "You may rely on it.",  "Concentrate and ask again.", "Very doubtful.",
    "As I see it, yes.",
    "Most likely.",
    "Outlook good.",
    "Yes.",
    "Signs point to yes.",
];

Essa matriz tem dez respostas afirmativas, cinco não confirmadas e cinco negativas. Em seguida, adicione o seguinte código para gerar e exibir uma resposta aleatória da matriz:

var index = new Random().Next(answers.Length - 1);
Console.WriteLine(answers[index]);

Você pode executar o aplicativo novamente para ver os resultados. Você deve ver algo semelhante à seguinte saída:

dotnet run -- Should I use top level statements in all my programs?

Should I use top level statements in all my programs?
Better not tell you now.

O código para gerar uma resposta inclui uma declaração de variável em suas instruções de nível superior. O compilador inclui essa declaração no método de Main gerado pelo compilador. Como essas declarações de variável são variáveis locais, você não pode incluir o modificador de static.

Esse código responde às perguntas, mas vamos adicionar mais um recurso. Você gostaria que seu aplicativo de perguntas simulasse o pensamento sobre a resposta. Você pode fazer isso adicionando um pouco de animação do ASCII e pausando enquanto trabalha. Adicione o seguinte código após a linha que ecoa a pergunta:

for (int i = 0; i < 20; i++)
{
    Console.Write("| -");
    await Task.Delay(50);
    Console.Write("\b\b\b");
    Console.Write("/ \\");
    await Task.Delay(50);
    Console.Write("\b\b\b");
    Console.Write("- |");
    await Task.Delay(50);
    Console.Write("\b\b\b");
    Console.Write("\\ /");
    await Task.Delay(50);
    Console.Write("\b\b\b");
}
Console.WriteLine();

Também será necessário adicionar uma diretiva using à parte superior do arquivo de origem:

using System.Threading.Tasks;

As diretivas using devem aparecer antes de qualquer outra instrução no arquivo. Caso contrário, é um erro do compilador. Você pode executar o programa novamente e ver a animação. Isso torna uma experiência melhor. Experimente a duração do atraso para corresponder ao seu gosto.

O código anterior cria um conjunto de linhas de rotação separadas por um espaço. A adição da palavra-chave await instrui o compilador a gerar o ponto de entrada do programa como um método que tem o modificador async e retorna um System.Threading.Tasks.Task. Esse programa não retorna um valor, portanto, o ponto de entrada do programa retorna um Task. Se o programa retornar um valor inteiro, você adicionará uma instrução return ao final de suas instruções de nível superior. Essa instrução return especificaria o valor inteiro a ser retornado. Se suas instruções de nível superior incluírem uma expressão await, o tipo de retorno se tornará System.Threading.Tasks.Task<TResult>.

Refatoração para o futuro

Seu programa deve ser parecido com o seguinte código:

Console.WriteLine();
foreach(var s in args)
{
    Console.Write(s);
    Console.Write(' ');
}
Console.WriteLine();

for (int i = 0; i < 20; i++)
{
    Console.Write("| -");
    await Task.Delay(50);
    Console.Write("\b\b\b");
    Console.Write("/ \\");
    await Task.Delay(50);
    Console.Write("\b\b\b");
    Console.Write("- |");
    await Task.Delay(50);
    Console.Write("\b\b\b");
    Console.Write("\\ /");
    await Task.Delay(50);
    Console.Write("\b\b\b");
}
Console.WriteLine();

string[] answers =
[
    "It is certain.",       "Reply hazy, try again.",     "Don't count on it.",
    "It is decidedly so.",  "Ask again later.",           "My reply is no.",
    "Without a doubt.",     "Better not tell you now.",   "My sources say no.",
    "Yes – definitely.",    "Cannot predict now.",        "Outlook not so good.",
    "You may rely on it.",  "Concentrate and ask again.", "Very doubtful.",
    "As I see it, yes.",
    "Most likely.",
    "Outlook good.",
    "Yes.",
    "Signs point to yes.",
];

var index = new Random().Next(answers.Length - 1);
Console.WriteLine(answers[index]);

O código anterior é razoável. Funciona. Mas não é reutilizável. Agora que o aplicativo está funcionando, é hora de retirar as partes reutilizáveis.

Um candidato é o código que exibe a animação de espera. Esse snippet pode se tornar um método:

Você pode começar criando uma função local em seu arquivo. Substitua a animação atual pelo seguinte:

await ShowConsoleAnimation();

static async Task ShowConsoleAnimation()
{
    for (int i = 0; i < 20; i++)
    {
        Console.Write("| -");
        await Task.Delay(50);
        Console.Write("\b\b\b");
        Console.Write("/ \\");
        await Task.Delay(50);
        Console.Write("\b\b\b");
        Console.Write("- |");
        await Task.Delay(50);
        Console.Write("\b\b\b");
        Console.Write("\\ /");
        await Task.Delay(50);
        Console.Write("\b\b\b");
    }
    Console.WriteLine();
}

O código anterior cria uma função local no método principal. Esse código ainda não é reutilizável. Então, extraia esse código em uma classe. Crie um novo arquivo chamado utilities.cs e adicione o seguinte código:

namespace MyNamespace
{
    public static class Utilities
    {
        public static async Task ShowConsoleAnimation()
        {
            for (int i = 0; i < 20; i++)
            {
                Console.Write("| -");
                await Task.Delay(50);
                Console.Write("\b\b\b");
                Console.Write("/ \\");
                await Task.Delay(50);
                Console.Write("\b\b\b");
                Console.Write("- |");
                await Task.Delay(50);
                Console.Write("\b\b\b");
                Console.Write("\\ /");
                await Task.Delay(50);
                Console.Write("\b\b\b");
            }
            Console.WriteLine();
        }
    }
}

Um arquivo com instruções de nível superior também pode conter namespaces e tipos no final do arquivo, após as instruções de nível superior. Porém, para este tutorial, você coloca o método de animação em um arquivo separado para torná-lo mais facilmente reutilizável.

Por fim, você pode limpar o código de animação para remover algumas duplicações usando o laço foreach para iterar por meio do conjunto de elementos de animação definidos na matriz animations.
O método completo de ShowConsoleAnimation após o refatoramento deve ser semelhante ao seguinte código:

public static async Task ShowConsoleAnimation()
{
    string[] animations = ["| -", "/ \\", "- |", "\\ /"];
    for (int i = 0; i < 20; i++)
    {
        foreach (string s in animations)
        {
            Console.Write(s);
            await Task.Delay(50);
            Console.Write("\b\b\b");
        }
    }
    Console.WriteLine();
}

Agora você tem um aplicativo completo e refatorou as partes reutilizáveis para uso futuro. Você pode chamar o novo método utilitário de suas instruções de nível superior, conforme exibido abaixo na versão final do programa principal:

using MyNamespace;

Console.WriteLine();
foreach(var s in args)
{
    Console.Write(s);
    Console.Write(' ');
}
Console.WriteLine();

await Utilities.ShowConsoleAnimation();

string[] answers =
[
    "It is certain.",       "Reply hazy, try again.",     "Don’t count on it.",
    "It is decidedly so.",  "Ask again later.",           "My reply is no.",
    "Without a doubt.",     "Better not tell you now.",   "My sources say no.",
    "Yes – definitely.",    "Cannot predict now.",        "Outlook not so good.",
    "You may rely on it.",  "Concentrate and ask again.", "Very doubtful.",
    "As I see it, yes.",
    "Most likely.",
    "Outlook good.",
    "Yes.",
    "Signs point to yes.",
];

var index = new Random().Next(answers.Length - 1);
Console.WriteLine(answers[index]);

O exemplo anterior adiciona a chamada a Utilities.ShowConsoleAnimatione insere outra diretiva using.

Resumo

As instruções de nível superior facilitam a criação de programas simples para uso para explorar novos algoritmos. É possível experimentar algoritmos tentando diferentes snippets de código. Depois de aprender o que funciona, você pode refatorar o código para facilitar a manutenção.

As instruções de nível superior simplificam os programas que se baseiam em aplicativos de console. Esses aplicativos incluem funções do Azure, ações do GitHub e outros pequenos utilitários. Para obter mais informações, consulte Instruções de nível superior (Guia de Programação em C#).