Tutorial: Explore ideias usando instruções de nível superior para criar código enquanto aprende
Neste tutorial, você aprenderá a:
- Aprenda as regras que regem o uso de instruções de nível superior.
- Use instruções de nível superior para explorar algoritmos.
- Refatora explorações em componentes reutilizáveis.
Pré-requisitos
Você precisa configurar sua máquina para executar o .NET 6 ou posterior. O compilador C# está disponível a partir de Visual Studio 2022 ou SDK .NET.
Este tutorial pressupõe que você esteja familiarizado com C# e .NET, incluindo o Visual Studio ou a CLI do .NET.
Comece a explorar
As instruções de nível superior permitem que você evite a cerimônia extra exigida, colocando o ponto de entrada do seu 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 esse programa com o novo recurso de declarações de nível superior. Isso permite 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 .NET 6 usam instruções de nível superior. Seu aplicativo pode não corresponder ao código neste artigo, se você já tiver atualizado para o .NET 6. 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 diretivas implícitas de global using
para projetos que usam os seguintes SDKs:
- Microsoft.NET.Sdk
- Microsoft.NET.Sdk.Web
- Microsoft.NET.Sdk.Worker
Essas diretivas global using
implícitas incluem os namespaces mais comuns para o tipo de projeto.
Para obter mais informações, consulte o artigo sobre implícito usando diretivas
Este recurso simplifica o que é necessário para começar a explorar novas ideias. Você pode usar instruções de nível superior para 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 assemblies para componentes reutilizáveis que você criou. As declarações de nível superior permitem uma experimentação rápida e tutoriais para iniciantes. Eles também fornecem um caminho suave da experimentação para 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 ficheiro de origem do seu aplicativo. O compilador gera um erro se você usá-los em mais de um arquivo.
Crie uma máquina de resposta .NET mágica
Para este 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 de cerimônia necessária para a estrutura de um programa típico. Então, quando estiver satisfeito com a funcionalidade, você pode refatorar o aplicativo como achar melhor.
Um bom ponto de partida é escrever a pergunta novamente na consola. Você pode começar escrevendo o seguinte código:
Console.WriteLine(args);
Você não declara uma variável args
. Para o único arquivo de origem que contém as suas instruções de nível superior, o compilador reconhece args
como significando os argumentos de linha de comando. O tipo de args é um string[]
, como em todos os programas C#.
Você pode testar seu código executando o seguinte comando dotnet run
:
dotnet run -- Should I use top level statements in all my programs?
Os argumentos após o --
na linha de comando são passados para o programa. Você pode ver o tipo da variável args
, porque isso é impresso no console:
System.String[]
Para escrever a pergunta no console, você precisa enumerar os argumentos e separá-los com um espaço. Substitua a chamada WriteLine
pelo seguinte código:
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 sequência de argumentos.
Responda com uma resposta aleatória
Depois de ecoar a pergunta, você pode adicionar o código para gerar a resposta aleatória. Comece adicionando uma série 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.",
];
Esta matriz tem 10 respostas afirmativas, cinco sem compromisso 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 como o seguinte resultado:
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.
Este código responde às perguntas, mas vamos adicionar mais um recurso. Você gostaria que seu aplicativo de perguntas simulasse pensar na resposta. Você pode fazer isso adicionando um pouco de animação 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();
Você também precisa adicionar uma diretiva using
à parte superior do arquivo de origem:
using System.Threading.Tasks;
As diretivas using
devem preceder quaisquer outras declarações no ficheiro. Caso contrário, é um erro do compilador. Você pode executar o programa novamente e ver a animação. Isso torna a experiência melhor. Experimente a duração do atraso para corresponder ao seu gosto.
O código anterior cria um conjunto de linhas giratórias separadas por um espaço. Adicionar a 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. Este 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 das 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 com perspectivas futuras
Seu programa deve se parecer 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. Está a funcionar. Mas não é reutilizável. Agora que você tem o aplicativo funcionando, é hora de retirar as peças reutilizáveis.
Um candidato é o código que exibe a animação de espera. Esse trecho 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 código:
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 dentro do seu 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 que tem 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. Mas para este tutorial, você coloca o método de animação em um arquivo separado para torná-lo mais facilmente reutilizável.
Finalmente, pode limpar o código de animação para remover alguma duplicação, utilizando o loop foreach
para iterar pelo conjunto de elementos de animação definidos na matriz animations
.
O método de ShowConsoleAnimation
completo após a refatoração deve ser semelhante ao código a seguir:
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 uma aplicação completa e refatorou as peças reutilizáveis para uso posterior. Você pode chamar o novo método utilitário a partir das suas declarações de nível superior, conforme mostrado na versão concluída 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.ShowConsoleAnimation
e inclui outra diretiva using
.
Resumo
Instruções de nível superior facilitam a criação de programas simples para uso para explorar novos algoritmos. Você pode experimentar algoritmos experimentando diferentes trechos de código. Depois de aprender o que funciona, você pode refatorar o código para ser mais fácil de manter.
As instruções de nível superior simplificam os programas baseados 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#).