Esercitazione: Esplorare le idee usando istruzioni di primo livello per compilare codice durante l'apprendimento

Questa esercitazione illustra come:

  • Informazioni sulle regole che regolano l'uso delle istruzioni di primo livello.
  • Usare istruzioni di primo livello per esplorare gli algoritmi.
  • Eseguire il refactoring delle esplorazioni in componenti riutilizzabili.

Prerequisiti

È necessario configurare il computer per eseguire .NET 6, che include il compilatore C# 10. Il compilatore C# 10 è disponibile a partire da Visual Studio 2022 o .NET 6 SDK.

Questa esercitazione presuppone che si abbia familiarità con C# e .NET, incluso Visual Studio o l'interfaccia della riga di comando di .NET.

Inizia 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 dotnet new console comando 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 di primo livello. Ciò consente di rimuovere tutte le righe, ma due delle 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 sui nuovi modelli C# per generare istruzioni di primo livello

.NET 6 SDK aggiunge anche un set di direttive impliciteglobal using per i progetti che usano gli SDK seguenti:

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

Queste direttive implicite global using includono gli spazi dei nomi più comuni per il tipo di progetto.

Per altre informazioni, vedere l'articolo sulle direttive implicite using

Questa funzionalità semplifica ciò che è necessario per iniziare a esplorare nuove idee. È possibile usare istruzioni di primo livello per gli scenari di scripting o per esplorare. Dopo aver creato le nozioni di base, è possibile avviare il refactoring del codice e creare metodi, classi o altri assembly per i componenti riutilizzabili creati. 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 file di origine nell'applicazione. Il compilatore genera un errore se vengono usati in più file.

Creare un computer di risposte magic .NET

Per questa esercitazione si creerà un'applicazione console che risponde a una domanda "sì" o "no" con una risposta casuale. Si creerà la funzionalità in modo dettagliato. 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 dichiara una args variabile. 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 argomenti è , string[]come in tutti i programmi C#.

È possibile testare il codice eseguendo il comando seguente dotnet run :

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

Gli argomenti dopo la -- riga di comando vengono passati al programma. È possibile visualizzare il tipo della args variabile, perché è ciò che viene stampato nella console:

System.String[]

Per scrivere la domanda nella console, è necessario enumerare gli argomenti e separarli con uno spazio. Sostituire la WriteLine chiamata 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 verrà 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 dieci risposte affermative, cinque non commitali 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.

Questo codice risponde alle domande, ma aggiungiamo un'altra funzionalità. Si vuole che l'app della domanda simula il pensiero sulla risposta. Puoi farlo aggiungendo un po' di animazione ASCII e sospendoti durante il lavoro. Aggiungere il codice seguente dopo la riga che restituisce 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 un'istruzione using all'inizio del file di origine:

using System.Threading.Tasks;

Le using istruzioni devono essere prima di 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. Sperimentare con la lunghezza del ritardo per abbinare il vostro gusto.

Il codice precedente crea un set di linee rotanti separate da uno spazio. L'aggiunta della await parola chiave indica al compilatore di generare il punto di ingresso del programma come metodo con il async modificatore e restituisce un oggetto System.Threading.Tasks.Task. Questo programma non restituisce un valore, quindi il punto di ingresso del programma restituisce un oggetto Task. Se il programma restituisce un valore intero, aggiungere un'istruzione return alla fine delle istruzioni di primo livello. L'istruzione return specifica il valore intero da restituire. Se le istruzioni di primo livello includono un'espressione await , il tipo restituito diventa System.Threading.Tasks.Task<TResult>.

Refactoring 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. Viene eseguito correttamente. Ma non è riutilizzabile. Ora che l'applicazione funziona, è possibile estrarre parti riutilizzabili.

Un candidato è il codice che visualizza l'animazione in 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. 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ò contenere anche spazi dei nomi e tipi 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, è possibile pulire il codice di animazione per rimuovere alcune duplicazioni:

foreach (string s in animations)
{
    Console.Write(s);
    await Task.Delay(50);
    Console.Write("\b\b\b");
}

A questo punto è disponibile un'applicazione completa ed è stato eseguito il refactoring delle parti riutilizzabili per un uso successivo. È possibile chiamare il nuovo metodo di utilità dalle istruzioni di primo livello, come illustrato di seguito 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.ShowConsoleAnimatione viene aggiunta un'istruzione aggiuntiva using .

Riepilogo

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 applicazioni console. Queste includono funzioni di Azure, GitHub actions e altre utilità di piccole dimensioni. Per altre informazioni, vedere Istruzioni di primo livello (Guida per programmatori C#).