Esercitazione: Esplora idee utilizzando istruzioni top-level per creare codice mentre impari
In questa esercitazione si apprenderà come:
- Scopri le regole che regolano l'uso delle dichiarazioni di livello superiore.
- Utilizzare istruzioni di alto livello per esplorare gli algoritmi.
- Trasformare le esplorazioni in componenti riutilizzabili.
Prerequisiti
È necessario configurare il computer per eseguire .NET 6 o versione successiva. Il compilatore C# è disponibile a partire da Visual Studio 2022 o .NET SDK.
Questa esercitazione presuppone che si abbia familiarità con C# e .NET, incluso Visual Studio o l'interfaccia della riga di comando di .NET.
Iniziare a esplorare
Le istruzioni di primo livello consentono di evitare la cerimonia aggiuntiva richiesta inserendo il punto di ingresso del programma in un metodo statico in una classe. Il punto di partenza tipico per una nuova applicazione console è simile al codice seguente:
using System;
namespace Application
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
}
}
}
Il codice precedente è il risultato dell'esecuzione del comando dotnet new console
e della creazione di una nuova applicazione console. Queste 11 righe contengono solo una riga di codice eseguibile. È possibile semplificare il programma con la nuova funzionalità di istruzioni a livello superiore. Ciò consente di rimuovere tutte tranne due righe di questo programma.
// See https://aka.ms/new-console-template for more information
Console.WriteLine("Hello, World!");
Importante
I modelli C# per .NET 6 usano istruzioni di primo livello. L'applicazione potrebbe non corrispondere al codice in questo articolo, se è già stato eseguito l'aggiornamento a .NET 6. Per altre informazioni, vedere l'articolo su Nuovi modelli C# generano istruzioni di primo livello
Il .NET 6 SDK aggiunge anche un set di direttive implicite global using
per i progetti che utilizzano i seguenti SDK:
- Microsoft.NET.Sdk
- Microsoft.NET.Sdk.Web
- Microsoft.NET.Sdk.Worker
Queste direttive implicite global using
includono i namespace più comuni del tipo di progetto.
Per altre informazioni, vedere l'articolo Direttive implicite using
Questa funzionalità semplifica l'esplorazione delle nuove idee. È possibile usare dichiarazioni di livello superiore per gli scenari di scripting o per fare esperimenti. Dopo aver impostato le basi del funzionamento, è possibile avviare il refactoring del codice e creare metodi, classi o altri assembly per i componenti riutilizzabili che hai costruito. Le istruzioni di primo livello consentono la sperimentazione rapida e le esercitazioni per principianti. Forniscono anche un percorso uniforme dalla sperimentazione ai programmi completi.
Le istruzioni di primo livello vengono eseguite nell'ordine in cui vengono visualizzate nel file. Le istruzioni di primo livello possono essere usate solo in un singolo file sorgente nell'applicazione. Il compilatore genera un errore se vengono usati in più file.
Creare una macchina di risposte magiche .NET
Per questa esercitazione si creerà un'applicazione console che risponde a una domanda "sì" o "no" con una risposta casuale. Si sviluppano le funzionalità passo dopo passo. Puoi concentrarti sul tuo compito anziché sulla cerimonia necessaria per la struttura di un programma tipico. Quindi, una volta soddisfatta la funzionalità, è possibile effettuare il refactoring dell'applicazione nel modo desiderato.
Un buon punto di partenza consiste nel scrivere nuovamente la domanda nella console. È possibile iniziare scrivendo il codice seguente:
Console.WriteLine(args);
Non si deve dichiarare la variabile args
. Per il singolo file di origine che contiene le istruzioni di primo livello, il compilatore riconosce args
per indicare gli argomenti della riga di comando. Il tipo di args è un string[]
, come in tutti i programmi C#.
È possibile testare il codice eseguendo il comando dotnet run
seguente:
dotnet run -- Should I use top level statements in all my programs?
Gli argomenti dopo il --
nella riga di comando vengono passati al programma. È possibile visualizzare il tipo della variabile args
stampata nella console:
System.String[]
Per scrivere la domanda nella console, è necessario enumerare gli argomenti e separarli con uno spazio. Sostituire la chiamata WriteLine
con il codice seguente:
Console.WriteLine();
foreach(var s in args)
{
Console.Write(s);
Console.Write(' ');
}
Console.WriteLine();
Ora, quando si esegue il programma, la domanda viene visualizzata correttamente come stringa di argomenti.
Rispondere con una risposta casuale
Dopo aver ripreso la domanda, è possibile aggiungere il codice per generare la risposta casuale. Per iniziare, aggiungere una matrice di possibili risposte:
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.",
];
Questa matrice ha 10 risposte affermative, cinque non committali e cinque negative. Aggiungere quindi il codice seguente per generare e visualizzare una risposta casuale dalla matrice:
var index = new Random().Next(answers.Length - 1);
Console.WriteLine(answers[index]);
È possibile eseguire di nuovo l'applicazione per visualizzare i risultati. Verrà visualizzato un output simile al seguente:
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.
Il codice per generare una risposta include una dichiarazione di variabile nelle istruzioni di primo livello. Il compilatore include tale dichiarazione nel metodo di Main
generato dal compilatore. Poiché queste dichiarazioni di variabile sono variabili locali, non è possibile includere il modificatore static
.
Questo codice risponde alle domande, ma aggiungiamo un'altra funzionalità. Vorresti che la tua app di domande simulasse il pensiero riguardo alla risposta. Puoi farlo aggiungendo un po' di animazione ASCII e sospendoti durante il lavoro. Aggiungere il codice seguente dopo la riga che visualizza la domanda:
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();
È anche necessario aggiungere una direttiva using
all'inizio del file di origine:
using System.Threading.Tasks;
Le direttive using
devono precedere qualsiasi altra istruzione nel file. In caso contrario, si tratta di un errore del compilatore. È possibile eseguire di nuovo il programma e visualizzare l'animazione. Questo rende un'esperienza migliore. Sperimenta con la durata del ritardo per adattarlo ai tuoi gusti.
Il codice precedente crea un set di linee rotanti separate da uno spazio. L'aggiunta della parola chiave await
indica al compilatore di generare il punto di ingresso del programma come metodo con il modificatore async
e restituisce un System.Threading.Tasks.Task. Questo programma non restituisce un valore, quindi il punto di ingresso del programma restituisce un Task
. Se il programma restituisce un valore intero, si dovrebbe aggiungere un'istruzione return alla fine delle istruzioni di primo livello. L'istruzione return specifica il valore intero da restituire. Se le dichiarazioni di livello superiore includono un'espressione await
, il tipo restituito diventa System.Threading.Tasks.Task<TResult>.
Ristrutturazione del codice per il futuro
Il programma dovrebbe essere simile al codice seguente:
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]);
Il codice precedente è ragionevole. Funziona. Ma non è riutilizzabile. Ora che l'applicazione funziona, è possibile estrarre parti riutilizzabili.
Un candidato è il codice che visualizza l'animazione d'attesa. Il frammento di codice può diventare un metodo:
È possibile iniziare creando una funzione locale nel file. Sostituire l'animazione corrente con il codice seguente:
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();
}
Il codice precedente crea una funzione locale all'interno del metodo main. Il codice non è ancora riutilizzabile. Estrai quindi il codice in una classe. Creare un nuovo file denominato utilities.cs e aggiungere il codice seguente:
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();
}
}
}
Un file con istruzioni di primo livello può anche contenere namespace e tipi di dati alla fine del file, dopo le istruzioni di primo livello. Ma per questa esercitazione si inserisce il metodo di animazione in un file separato per renderlo più facilmente riutilizzabile.
Infine, puoi pulire il codice di animazione per rimuovere alcune duplicazioni, usando il ciclo foreach
per scorrere un set di elementi di animazione definiti nell'array animations
.
Il metodo completo ShowConsoleAnimation
dopo il refactoring dovrebbe essere simile al codice seguente:
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();
}
Ora hai un'applicazione completa e hai ristrutturato le parti riutilizzabili per usarle in un secondo momento. È possibile chiamare il nuovo metodo di utilità dalle istruzioni di primo livello, come illustrato nella versione completata del programma principale:
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]);
Nell'esempio precedente viene aggiunta la chiamata a Utilities.ShowConsoleAnimation
e viene aggiunta un'altra direttiva using
.
Sommario
Le istruzioni di primo livello semplificano la creazione di programmi semplici da usare per esplorare nuovi algoritmi. È possibile provare algoritmi provando frammenti di codice diversi. Dopo aver appreso cosa funziona, è possibile effettuare il refactoring del codice per essere più gestibile.
Le istruzioni di primo livello semplificano i programmi basati sulle app console. Queste app includono funzioni di Azure, GitHub actions e altre utilità di piccole dimensioni. Per altre informazioni, vedere istruzioni di primo livello (Guida per programmatori C#).