Didacticiel : explorez les idées à l’aide d’instructions de niveau supérieur pour générer du code au fur et à mesure que vous apprenez

Dans ce tutoriel, vous apprendrez à :

  • Découvrez les règles qui régissent votre utilisation des instructions de niveau supérieur.
  • Utilisez des instructions de niveau supérieur pour explorer les algorithmes.
  • Refactorisez des explorations en composants réutilisables.

Prérequis

Vous devez configurer votre ordinateur pour exécuter .NET 6, qui inclut le compilateur C# 10. Le compilateur C# 10 est disponible à partir de Visual Studio 2022 ou du SDK .NET 6.

Ce tutoriel suppose de connaître C# et .NET, y compris Visual Studio ou l’interface CLI .NET.

Commencez à explorer

Les instructions de niveau supérieur vous permettent d’éviter les étapes supplémentaires requises en plaçant le point d’entrée de votre programme dans une méthode statique dans une classe. Le point de départ classique d’une nouvelle application console ressemble au code suivant :

using System;

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

Le code précédent est le résultat de l’exécution de la commande dotnet new console et de la création d’une application console. Ces 11 lignes ne contiennent qu’une seule ligne de code exécutable. Vous pouvez simplifier ce programme avec la nouvelle fonctionnalité d’instructions de niveau supérieur. Cela vous permet de supprimer toutes les lignes de ce programme, à l’exception de deux :

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

Important

Les modèles C# pour .NET 6 utilisent des instructions de niveau supérieur. Votre application ne correspond peut-être pas au code de cet article, si vous avez déjà effectué une mise à niveau vers .NET 6. Pour plus d’informations, consultez l’article Les nouveaux modèles C# génèrent des instructions de niveau supérieur.

Le SDK .NET 6 ajoute également un ensemble de directives implicitesglobal using pour les projets qui utilisent les kits SDK suivants :

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

Ces directives implicites global using incluent les espaces de noms les plus courants pour le type de projet.

Pour plus d’informations, consultez l’article sur les directives d’utilisation implicite

Cette fonctionnalité simplifie ce qui est nécessaire pour commencer à explorer de nouvelles idées. Vous pouvez utiliser des instructions de niveau supérieur pour des scénarios de script ou pour explorer. Une fois que les principes de base fonctionnent, vous pouvez commencer à refactoriser le code et créer des méthodes, des classes ou d’autres assemblys pour les composants réutilisables que vous avez créés. Les instructions de niveau supérieur permettent une expérimentation rapide et des didacticiels pour débutants. Ils offrent également un parcours fluide de l’expérimentation, jusqu’aux programmes complets.

Les instructions de niveau supérieur sont exécutées dans leur ordre d’apparition dans le fichier. Les instructions de niveau supérieur ne peuvent être utilisées que dans un seul fichier source dans votre application. Le compilateur génère une erreur si vous les utilisez dans plusieurs fichiers.

Créer un répondeur .NET magique

Pour ce tutoriel, créons une application console qui répond à une question « oui » ou « non » par une réponse aléatoire. Vous allez générer la fonctionnalité étape par étape. Vous pouvez vous concentrer sur votre tâche plutôt que sur les étapes nécessaires à la structure d’un programme classique. Ensuite, une fois que vous êtes satisfait(e) de la fonctionnalité, vous pouvez refactoriser l’application comme bon vous semble.

Un bon point de départ consiste à réécrire la question dans la console. Vous pouvez commencer par écrire le code suivant :

Console.WriteLine(args);

Vous ne déclarez pas de variable args. Pour le fichier source unique qui contient vos instructions de niveau supérieur, le compilateur reconnaît qu’il s’agit des arguments args de ligne de commande. Le type d’args est un string[], comme dans tous les programmes C#.

Vous pouvez tester votre code en exécutant la commande dotnet run suivante :

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

Les arguments après le -- sur la ligne de commande sont passés au programme. Vous pouvez voir le type de la variable args, car il s’agit de ce qui est imprimé sur la console :

System.String[]

Pour écrire la question dans la console, vous devez énumérer les arguments et les séparer avec un espace. Remplacez l’appel WriteLine par le code suivant :

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

Maintenant, lorsque vous exécutez le programme, il affiche correctement la question sous la forme d’une chaîne d’arguments.

Répondre avec une réponse aléatoire

Après avoir renvoyé en écho la question, vous pouvez ajouter le code pour générer la réponse aléatoire. Commencez par ajouter un tableau de réponses possibles :

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.",
];

Ce tableau contient dix réponses affirmatives, cinq sans engagement et cinq qui sont négatives. Ensuite, ajoutez le code suivant pour générer et afficher une réponse aléatoire à partir du tableau :

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

Vous pouvez réexécuter l’application pour afficher les résultats. Vous devriez voir une sortie semblable à la suivante :

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.

Ce code répond aux questions, mais ajoutons une fonctionnalité supplémentaire. Vous souhaitez que votre application de questions simule la réflexion sur la réponse. Pour ce faire, ajoutez un peu d’animation ASCII et une pause pendant le traitement. Ajoutez le code suivant après la ligne qui renvoie en écho la question :

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();

Vous devez également ajouter une instruction using en haut du fichier source :

using System.Threading.Tasks;

Les instructions using doivent être antérieures à toutes les autres instructions du fichier. Sinon, il s’agit d’une erreur du compilateur. Vous pouvez réexécuter le programme et voir l’animation. Cela crée une meilleure expérience. Expérimentez la longueur du délai en fonction de vos goûts.

Le code précédent crée un ensemble de lignes tournantes séparées par un espace. L’ajout du mot clé await indique au compilateur de générer le point d’entrée du programme en tant que méthode qui a le modificateur asyncet retourne un System.Threading.Tasks.Task. Ce programme ne retourne pas de valeur, de sorte que le point d’entrée du programme retourne un Task. Si votre programme retourne une valeur entière, vous ajoutez une instruction de retour à la fin de vos instructions de niveau supérieur. Cette instruction de retour spécifie la valeur entière à retourner. Si vos instructions de niveau supérieur incluent une expression await, le type de retour devient System.Threading.Tasks.Task<TResult>.

Refactorisation pour l’avenir

Votre programme doit ressembler au code suivant :

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]);

Le code précédent est raisonnable. Il fonctionne. Mais il n’est pas réutilisable. Maintenant que l’application fonctionne, il est temps de retirer des parties réutilisables.

L’un des candidats est le code qui affiche l’animation d’attente. Cet extrait de code peut devenir une méthode :

Vous pouvez commencer en créant une fonction locale dans votre fichier. Remplacez l’animation actuelle par le code suivant :

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();
}

Le code précédent crée une fonction locale à l’intérieur de votre méthode principale. Ceci n’est toujours pas réutilisable. Par conséquent, extrayez ce code dans une classe. Créez un nouveau fichier nommé utilities.cs , puis ajoutez le code suivant :

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 fichier qui a des instructions de niveau supérieur peut également contenir des espaces de noms et des types à la fin du fichier, après les instructions de niveau supérieur. Toutefois, pour ce didacticiel, vous placez la méthode d’animation dans un fichier distinct pour la rendre plus facilement réutilisable.

Enfin, vous pouvez nettoyer le code d’animation pour supprimer une duplication :

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

Vous disposez maintenant d’une application complète et vous avez refactorisé les parties réutilisables pour une utilisation ultérieure. Vous pouvez appeler la nouvelle méthode utilitaire à partir de vos instructions de niveau supérieur, comme indiqué ci-dessous dans la version terminée du programme 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]);

L’exemple précédent ajoute l’appel à Utilities.ShowConsoleAnimation et ajoute une instruction supplémentaire using.

Résumé

Les instructions de niveau supérieur facilitent la création de programmes simples à utiliser pour explorer de nouveaux algorithmes. Vous pouvez expérimenter des algorithmes en essayant différents extraits de code. Une fois que vous avez appris ce qui fonctionne, vous pouvez refactoriser le code pour qu’il soit plus facile à gérer.

Les instructions de niveau supérieur simplifient les programmes qui sont basés sur des applications console. Il s’agit notamment des fonctions Azure, des actions GitHub et d’autres petits utilitaires. Pour plus d’informations, consultez Instructions de niveau supérieur (Guide de programmation C#).