Compiler le logiciel

Souvent, plusieurs algorithmes ou implémentations peuvent résoudre correctement la même tâche. Le code que vous choisissez communique un style. Les développeurs et les agents de codage qui lisent votre code utilisent sa structure pour déduire votre intention : ce dont chaque opération a besoin, où elle appartient et quand elle s’exécute.

Tip

Cet article fait partie de la section Notions de base pour les développeurs qui connaissent les expressions, instructions et méthodes C# de base. Si vous débutez avec la programmation, commencez par commencer par les didacticiels De prise en main .

Cette section compare les approches valides en matière d’algorithmes et explique les différences subtiles dans leur comportement et la façon dont les lecteurs les interprètent. Vous allez combiner des éléments de langage familiers, tels que des types, des expressions, des instructions et des méthodes, et choisir des formes qui communiquent la conception que vous souhaitez.

Comparer le comportement et l’intention de conception

Avant de choisir une implémentation, tenez compte de la façon dont le reste du code l’utilisera. Ce code est l’appelant : il fournit des entrées, appelle votre opération et utilise les résultats. A-t-il besoin d’un résultat complet immédiatement ou peut-il traiter des valeurs une par une ? Une aide fait-elle partie de cette opération seule ou d’autres opérations l’utiliseront-elles également ? Ces questions vous aident à comparer à la fois le comportement dont vous avez besoin et la conception que votre code communique.

Une opération inline courte montre aux lecteurs les étapes au point d’utilisation. Par exemple, Where(task => task.Priority > 3) rend la règle de filtrage immédiatement visible. Un helper nommé, comme dans Where(IsUrgent), met l’accent sur l’objectif de la règle et permet aux lecteurs d’inspecter ses détails séparément. Choisissez selon que les étapes ou leur objectif expliquent le mieux le code environnant.

L’endroit où vous déclarez une fonction auxiliaire communique sa portée prévue. Une fonction locale à l’intérieur de ShowDashboard indique que la fonction auxiliaire appartient à cette opération et empêche les autres membres de l’appeler. Une méthode privée sur le type conteneur rend la fonction auxiliaire disponible pour d’autres membres, ce qui suggère que vous attendez une réutilisation ailleurs dans le type. Les deux peuvent organiser le même calcul, mais ils amènent les lecteurs à des attentes différentes quant à son rôle.

La façon dont vous fournissez les entrées d’un assistant communique ses dépendances. Le passage d’une limite en tant que paramètre, tel que IsUrgent(task, minimumPriority), rend ce paramètre visible à chaque appel. Une fonction locale ou lambda peut plutôt capturerminimumPriority, en utilisant la variable de sa portée englobante sans la recevoir en tant qu’argument. Capture connecte l’assistant au contexte de l’opération conteneur ; les paramètres explicites facilitent l’identification des données fournies. Utilisez une static fonction locale ou une fonction lambda lorsque vous souhaitez garantir qu’elle ne capture pas l’état environnant.

La façon dont vous affichez les résultats indique à quel moment le travail a lieu. Une méthode qui génère et retourne une collection se termine avant que l’appelant ne reçoive la collection. Un itérateur produit des éléments à mesure que l’appelant les demande, de sorte que l’appelant peut s’arrêter avant que tous les éléments soient produits. Les deux peuvent produire les mêmes valeurs, mais les appelants doivent comprendre s’ils reçoivent des résultats déjà calculés ou une séquence dont le calcul reste à venir.

Pour chaque choix, identifiez d’abord le comportement dont le code appelant a besoin. Considérez ensuite ce qu’un autre développeur ou agent de codage déduit du nom, de l’étendue, des entrées et du résultat. Choisissez une forme qui fait correspondre ces attentes à votre conception et expliquez le comportement important que la forme du code seul ne révèle pas. L’objectif est de faire un choix délibéré entre des alternatives valides, et non d’appliquer une seule forme partout.

Lire les choix de conception dans un exemple

L’exemple suivant montre comment plusieurs choix communiquent différentes parties d’une conception. Il affiche les tâches urgentes et prêtes à démarrer. Un ProjectTask contient le titre, la priorité et l’état bloqué d’une tâche.

var tasks = new[]
{
    new ProjectTask("Confirm venue", Priority: 3, IsBlocked: false),
    new ProjectTask("Print badges", Priority: 2, IsBlocked: true),
    new ProjectTask("Test microphones", Priority: 2, IsBlocked: false),
};

ShowDashboard("Community meetup", tasks, minimumPriority: 2);

static void ShowDashboard(
    string projectName,
    IEnumerable<ProjectTask> tasks,
    int minimumPriority)
{
    var urgentTasks = tasks.Where(
        task => task.Priority >= minimumPriority);

    foreach (ProjectTask task in ReadyTasks(urgentTasks))
    {
        Console.WriteLine(FormatTask(task));
    }

    string FormatTask(ProjectTask task) =>
        $"{projectName}: {task.Title}";
}

static IEnumerable<ProjectTask> ReadyTasks(
    IEnumerable<ProjectTask> tasks)
{
    foreach (ProjectTask task in tasks)
    {
        if (!task.IsBlocked)
        {
            yield return task;
        }
    }
}

record ProjectTask(string Title, int Priority, bool IsBlocked);

Chaque choix permet de clarifier une partie différente du travail :

  • Le lambda passé pour Where place une règle de priorité courte en regard de l’opération qui l’utilise.
  • La fonction locale FormatTask nomme une étape de mise en forme qui appartient uniquement à ShowDashboard.
  • L’itérateur ReadyTasks permet aux appelants de consommer des tâches prêtes sans créer de collection intermédiaire.
  • La boucle foreach rend explicite l’action finale : l’écriture de chaque résultat.

Pour la comparaison, Where(static task => !task.IsBlocked) peut remplacer ReadyTasks , car ce test de préparation est un filtre simple. Les deux formes diffèrent l’application du filtre jusqu’à l’énumération. L’expression lambda place la règle sur le site d’appel ; ReadyTasks donne à la règle un nom. Choisissez entre les deux en fonction des informations qui aident les lecteurs à comprendre la personne qui appelle.

Les articles qui suivent utilisent des comparaisons comme celles-ci pour expliquer quand chaque approche convient et ce que les lecteurs peuvent déduire de votre choix.

Étapes suivantes