Partager via


Tutoriel : Bien démarrer avec System.CommandLine

Importante

System.CommandLine est actuellement disponible en préversion et cette documentation concerne la version 2.0 bêta 5. Certaines informations se rapportent à un produit en version préliminaire qui peut être sensiblement modifié avant sa sortie. Microsoft n’offre aucune garantie, expresse ou implicite, en ce qui concerne les informations fournies ici.

Ce tutoriel montre comment créer une application en ligne de commande .NET qui utilise la System.CommandLine bibliothèque. Vous commencerez par créer une commande racine simple qui a une option. Ensuite, vous allez créer une application plus complexe qui contient plusieurs sous-commandes et différentes options pour chaque commande.

Dans ce tutoriel, vous allez apprendre à :

  • Créez des commandes, des options et des arguments.
  • Spécifiez les valeurs par défaut pour les options.
  • Attribuez des options et des arguments à des commandes.
  • Attribuez une option de manière récursive à toutes les sous-commandes sous une commande.
  • Utilisez plusieurs niveaux de sous-commandes imbriqués.
  • Créez des alias pour les commandes et les options.
  • stringUtilisez les types d’options , , boolstring[]int, FileInfoet enum.
  • Lire les valeurs d’option dans le code d’action de commande.
  • Utilisez du code personnalisé pour l’analyse et la validation des options.

Conditions préalables

ou

  • Visual Studio 2022 avec la charge de travail de développement de bureau .NET installée.

Créer l’application

Créez un projet d’application console .NET 9 nommé « scl ».

  1. Créez un dossier nommé scl pour le projet, puis ouvrez une invite de commandes dans le nouveau dossier.

  2. Exécutez la commande suivante:

    dotnet new console --framework net9.0
    

Installer le package System.CommandLine

  • Exécutez la commande suivante:

    dotnet add package System.CommandLine --prerelease
    

    Ou, dans .NET 10+ :

    dotnet package add System.CommandLine --prerelease
    

    L’option --prerelease est nécessaire, car la bibliothèque est toujours en version bêta.

Analyser les arguments

  1. Remplacez le contenu du fichier Program.cs par le code suivant :

    using System.CommandLine;
    using System.CommandLine.Parsing;
    
    namespace scl;
    
    class Program
    {
        static int Main(string[] args)
        {
            Option<FileInfo> fileOption = new("--file")
            {
                Description = "The file to read and display on the console."
            };
    
            RootCommand rootCommand = new("Sample app for System.CommandLine");
            rootCommand.Options.Add(fileOption);
    
            ParseResult parseResult = rootCommand.Parse(args);
            if (parseResult.GetValue(fileOption) is FileInfo parsedFile)
            {
                ReadFile(parsedFile);
                return 0;
            }
            foreach (ParseError parseError in parseResult.Errors)
            {
                Console.Error.WriteLine(parseError.Message);
            }
            return 1;
        }
    
        static void ReadFile(FileInfo file)
        {
            foreach (string line in File.ReadLines(file.FullName))
            {
                Console.WriteLine(line);
            }
        }
    }
    

Code précédent :

Option<FileInfo> fileOption = new("--file")
{
    Description = "The file to read and display on the console."
};

RootCommand rootCommand = new("Sample app for System.CommandLine");
rootCommand.Options.Add(fileOption);
  • Analyse et args vérifie si une valeur a été fournie pour --file l’option. Dans ce cas, elle appelle la méthode à l’aide de la valeur analysée et retourne 0 le ReadFile code de sortie :
ParseResult parseResult = rootCommand.Parse(args);
if (parseResult.GetValue(fileOption) is FileInfo parsedFile)
{
    ReadFile(parsedFile);
    return 0;
}
  • Si aucune valeur n’a été fournie, --fileelle imprime les erreurs d’analyse disponibles et retourne 1 le code de sortie :
foreach (ParseError parseError in parseResult.Errors)
{
    Console.Error.WriteLine(parseError.Message);
}
return 1;
  • La ReadFile méthode lit le fichier spécifié et affiche son contenu sur la console :
static void ReadFile(FileInfo file)
{
    foreach (string line in File.ReadLines(file.FullName))
    {
        Console.WriteLine(line);
    }
}

Tester l’application

Vous pouvez utiliser l’une des méthodes suivantes pour tester tout en développant une application en ligne de commande :

  • Exécutez la dotnet build commande, puis ouvrez une invite de commandes dans le dossier scl/bin/Debug/net9.0 pour exécuter l’exécutable :

    dotnet build
    cd bin/Debug/net9.0
    scl --file scl.runtimeconfig.json
    
  • Utilisez dotnet run et transmettez des valeurs d’option à l’application au lieu de la run commande en les incluant après --, comme dans l’exemple suivant :

    dotnet run -- --file bin/Debug/net9.0/scl.runtimeconfig.json
    

Ce tutoriel suppose que vous utilisez la première de ces options.

Lorsque vous exécutez l’application, elle affiche le contenu du fichier spécifié par l’option --file .

{
  "runtimeOptions": {
    "tfm": "net9.0",
    "framework": {
      "name": "Microsoft.NETCore.App",
      "version": "9.0.0"
    }
  }
}

Mais que se passe-t-il si vous lui demandez d’afficher l’aide en fournissant --help? Rien n’est imprimé dans la console, car l’application ne gère pas encore le scénario où --file elle n’est pas fournie et il n’y a pas d’erreurs d’analyse.

Analyser les arguments et appeler le parseResult

System.CommandLine vous permet de spécifier une action appelée lorsqu’un symbole donné (commande, directive ou option) est analysé avec succès. L’action est un délégué qui prend un System.CommandLine.ParseResult paramètre et retourne un code de int sortie (les actions asynchrones sont également disponibles). Le code de sortie est retourné par la System.CommandLine.Parsing.ParseResult.Invoke méthode et peut être utilisé pour indiquer si la commande a été exécutée correctement ou non.

  1. Remplacez le contenu du fichier Program.cs par le code suivant :

    using System.CommandLine;
    
    namespace scl;
    
    class Program
    {
        static int Main(string[] args)
        {
            Option<FileInfo> fileOption = new("--file")
            {
                Description = "The file to read and display on the console."
            };
    
            RootCommand rootCommand = new("Sample app for System.CommandLine");
            rootCommand.Options.Add(fileOption);
    
            rootCommand.SetAction(parseResult =>
            {
                FileInfo parsedFile = parseResult.GetValue(fileOption);
                ReadFile(parsedFile);
                return 0;
            });
    
            ParseResult parseResult = rootCommand.Parse(args);
            return parseResult.Invoke();
        }
    
        static void ReadFile(FileInfo file)
        {
            foreach (string line in File.ReadLines(file.FullName))
            {
                Console.WriteLine(line);
            }
        }
    }
    

Code précédent :

  • Spécifie qu’il ReadFile s’agit de la méthode qui sera appelée lorsque la commande racine est appelée :

    rootCommand.SetAction(parseResult =>
    {
        FileInfo parsedFile = parseResult.GetValue(fileOption);
        ReadFile(parsedFile);
        return 0;
    });
    
  • Analyse le args résultat et appelle le résultat :

    ParseResult parseResult = rootCommand.Parse(args);
    return parseResult.Invoke();
    

Lorsque vous exécutez l’application, elle affiche le contenu du fichier spécifié par l’option --file .

Que se passe-t-il si vous lui demandez d’afficher l’aide en fournissant --help?

scl --help

La sortie suivante est imprimée :

Description:
  Sample app for System.CommandLine

Usage:
  scl [options]

Options:
  -?, -h, --help  Show help and usage information
  --version       Show version information
  --file          The file to read and display on the conso

System.CommandLine.RootCommand par défaut fournit l’option d’aide, l’option Version et la directive Suggest. ParseResult.Invoke la méthode est responsable de l’appel de l’action du symbole analysé. Il peut s’agir de l’action explicitement définie pour notre commande ou de l’action d’aide définie par System.CommandLine .System.CommandLine.Help.HelpOption De plus, lorsqu’elle détecte toutes les erreurs d’analyse, elle les imprime à l’erreur standard, imprime l’aide à la sortie standard et retourne 1 le code de sortie :

scl --invalid bla
Unrecognized command or argument '--invalid'.
Unrecognized command or argument 'bla'.

Ajouter une sous-commande et des options

Dans cette section, vous allez :

  • Créez d’autres options.
  • Créez une sous-commande.
  • Affectez les nouvelles options à la nouvelle sous-commande.

Les nouvelles options vous permettent de configurer les couleurs du premier plan et du texte d’arrière-plan et la vitesse de lecture. Ces fonctionnalités seront utilisées pour lire une collection de citations tirées du didacticiel sur l’application console Teleprompter.

  1. Copiez le fichier sampleQuotes.txt à partir du dépôt GitHub pour cet exemple dans votre répertoire de projet. Pour plus d’informations sur le téléchargement de fichiers, consultez les instructions des exemples et des didacticiels.

  2. Ouvrez le fichier projet et ajoutez un <ItemGroup> élément juste avant la balise de fermeture </Project> :

    <ItemGroup>
      <Content Include="sampleQuotes.txt">
        <CopyToOutputDirectory>Always</CopyToOutputDirectory>
      </Content>
    </ItemGroup>
    

    L’ajout de ce balisage entraîne la copie du fichier texte dans le dossier bin/debug/net9.0 lorsque vous générez l’application. Par conséquent, lorsque vous exécutez l’exécutable dans ce dossier, vous pouvez accéder au fichier par nom sans spécifier de chemin d’accès au dossier.

  3. Dans Program.cs, après le code qui crée l’option --file , créez des options pour contrôler la vitesse de lecture et les couleurs du texte :

    Option<int> delayOption = new("--delay")
    {
        Description = "Delay between lines, specified as milliseconds per character in a line.",
        DefaultValueFactory = parseResult => 42
    };
    Option<ConsoleColor> fgcolorOption = new("--fgcolor")
    {
        Description = "Foreground color of text displayed on the console.",
        DefaultValueFactory = parseResult => ConsoleColor.White
    };
    Option<bool> lightModeOption = new("--light-mode")
    {
        Description = "Background color of text displayed on the console: default is black, light mode is white."
    };
    
  4. Après la ligne qui crée la commande racine, supprimez le code qui lui ajoute l’option --file . Vous la supprimez ici, car vous l’ajouterez à une nouvelle sous-commande.

  5. Après la ligne qui crée la commande racine, créez une read sous-commande. Ajoutez les options à cette sous-commande (à l’aide de la syntaxe d’initialiseur de collection plutôt que Options de propriété) et ajoutez la sous-commande à la commande racine.

    Command readCommand = new("read", "Read and display the file.")
    {
        fileOption,
        delayOption,
        fgcolorOption,
        lightModeOption
    };
    rootCommand.Subcommands.Add(readCommand);
    
  6. Remplacez le SetAction code par le code suivant SetAction pour la nouvelle sous-commande :

    readCommand.SetAction(parseResult => ReadFile(
        parseResult.GetValue(fileOption),
        parseResult.GetValue(delayOption),
        parseResult.GetValue(fgcolorOption),
        parseResult.GetValue(lightModeOption)));
    

    Vous n’appelez SetAction plus sur la commande racine, car la commande racine n’a plus besoin d’une action. Lorsqu’une commande a des sous-commandes, vous devez généralement spécifier l’une des sous-commandes lors de l’appel d’une application de ligne de commande.

  7. Remplacez la méthode d’action ReadFile par le code suivant :

    internal static void ReadFile(FileInfo file, int delay, ConsoleColor fgColor, bool lightMode)
    {
        Console.BackgroundColor = lightMode ? ConsoleColor.White : ConsoleColor.Black;
        Console.ForegroundColor = fgColor;
        foreach (string line in File.ReadLines(file.FullName))
        {
            Console.WriteLine(line);
            Thread.Sleep(TimeSpan.FromMilliseconds(delay * line.Length));
        }
    }
    

L’application ressemble maintenant à ceci :

using System.CommandLine;

namespace scl;

class Program
{
    static int Main(string[] args)
    {
        Option<FileInfo> fileOption = new("--file")
        {
            Description = "The file to read and display on the console."
        };

        Option<int> delayOption = new("--delay")
        {
            Description = "Delay between lines, specified as milliseconds per character in a line.",
            DefaultValueFactory = parseResult => 42
        };
        Option<ConsoleColor> fgcolorOption = new("--fgcolor")
        {
            Description = "Foreground color of text displayed on the console.",
            DefaultValueFactory = parseResult => ConsoleColor.White
        };
        Option<bool> lightModeOption = new("--light-mode")
        {
            Description = "Background color of text displayed on the console: default is black, light mode is white."
        };

        RootCommand rootCommand = new("Sample app for System.CommandLine");

        Command readCommand = new("read", "Read and display the file.")
        {
            fileOption,
            delayOption,
            fgcolorOption,
            lightModeOption
        };
        rootCommand.Subcommands.Add(readCommand);

        readCommand.SetAction(parseResult => ReadFile(
            parseResult.GetValue(fileOption),
            parseResult.GetValue(delayOption),
            parseResult.GetValue(fgcolorOption),
            parseResult.GetValue(lightModeOption)));

        return rootCommand.Parse(args).Invoke();
    }

    internal static void ReadFile(FileInfo file, int delay, ConsoleColor fgColor, bool lightMode)
    {
        Console.BackgroundColor = lightMode ? ConsoleColor.White : ConsoleColor.Black;
        Console.ForegroundColor = fgColor;
        foreach (string line in File.ReadLines(file.FullName))
        {
            Console.WriteLine(line);
            Thread.Sleep(TimeSpan.FromMilliseconds(delay * line.Length));
        }
    }
}

Tester la nouvelle sous-commande

Maintenant, si vous essayez d’exécuter l’application sans spécifier la sous-commande, vous obtenez un message d’erreur suivi d’un message d’aide qui spécifie la sous-commande disponible.

scl --file sampleQuotes.txt
'--file' was not matched. Did you mean one of the following?
--help

Required command was not provided.
Unrecognized command or argument '--file'.
Unrecognized command or argument 'sampleQuotes.txt'.

Description:
  Sample app for System.CommandLine

Usage:
  scl [command] [options]

Options:
  -?, -h, --help  Show help and usage information
  --version       Show version information

Commands:
  read  Read and display the file.

Le texte d’aide de la sous-commande read indique que quatre options sont disponibles. Il affiche des valeurs valides pour l’énumération.

scl read -h
Description:
  Read and display the file.

Usage:
  scl read [options]

Options:
  --file <file>                                               The file to read and display on the console.
  --delay <delay>                                             Delay between lines, specified as milliseconds per
                                                              character in a line. [default: 42]
  --fgcolor                                                   Foreground color of text displayed on the console.
  <Black|Blue|Cyan|DarkBlue|DarkCyan|DarkGray|DarkGreen|Dark  [default: White]
  Magenta|DarkRed|DarkYellow|Gray|Green|Magenta|Red|White|Ye
  llow>
  --light-mode                                                Background color of text displayed on the console:
                                                              default is black, light mode is white.
  -?, -h, --help                                              Show help and usage information

Exécutez la sous-commande read en spécifiant uniquement l’option --file et vous obtenez les valeurs par défaut pour les trois autres options.

scl read --file sampleQuotes.txt

Le délai par défaut de 42 millisecondes par caractère entraîne une vitesse de lecture lente. Vous pouvez l’accélérer en définissant --delay sur un nombre inférieur.

scl read --file sampleQuotes.txt --delay 0

Vous pouvez utiliser --fgcolor et --light-mode définir des couleurs de texte :

scl read --file sampleQuotes.txt --fgcolor red --light-mode

Fournissez une valeur non valide pour --delay et vous recevrez un message d’erreur :

scl read --file sampleQuotes.txt --delay forty-two
Cannot parse argument 'forty-two' for option '--int' as expected type 'System.Int32'.

Fournissez une valeur non valide pour --file et vous obtiendrez une exception.

scl read --file nofile
Unhandled exception: System.IO.FileNotFoundException: Could not find file 'C:\bin\Debug\net9.0\nofile''.
File name: 'C:\bin\Debug\net9.0\nofile''

Ajouter des sous-commandes et une validation personnalisée

Cette section crée la version finale de l’application. Lorsque vous avez terminé, l’application aura les commandes et options suivantes :

  • commande racine avec une option récursive* nommée --file
    • Commande quotes
      • read commande avec des options nommées --delay, --fgcoloret --light-mode
      • add commande avec des arguments nommés quote et byline
      • delete commande avec option nommée --search-terms

* Une option récursive est disponible pour la commande à laquelle elle est affectée et récursivement à toutes ses sous-commandes.

Voici un exemple d’entrée de ligne de commande qui appelle chacune des commandes disponibles avec ses options et arguments :

scl quotes read --file sampleQuotes.txt --delay 40 --fgcolor red --light-mode
scl quotes add "Hello world!" "Nancy Davolio"
scl quotes delete --search-terms David "You can do" Antoine "Perfection is achieved"
  1. Dans Program.cs, remplacez le code qui crée l’option --file par le code suivant :

    Option<FileInfo> fileOption = new("--file")
    {
        Description = "An option whose argument is parsed as a FileInfo",
        Required = true,
        DefaultValueFactory = result =>
        {
            if (result.Tokens.Count == 0)
            {
                return new FileInfo("sampleQuotes.txt");
    
            }
            string filePath = result.Tokens.Single().Value;
            if (!File.Exists(filePath))
            {
                result.AddError("File does not exist");
                return null;
            }
            else
            {
                return new FileInfo(filePath);
            }
        }
    };
    

    Ce code utilise System.CommandLine.Parsing.ArgumentResult pour fournir une analyse, une validation et une gestion des erreurs personnalisées.

    Sans ce code, les fichiers manquants sont signalés par une exception et une trace de pile. Avec ce code, seul le message d’erreur spécifié s’affiche.

    Ce code spécifie également une valeur par défaut, c’est pourquoi il définit DefaultValueFactory la méthode d’analyse personnalisée.

  2. Après le code qui crée lightModeOption, ajoutez des options et des arguments pour les commandes add et pour les commandes delete :

    Option<string[]> searchTermsOption = new("--search-terms")
    {
        Description = "Strings to search for when deleting entries.",
        Required = true,
        AllowMultipleArgumentsPerToken = true
    };
    Argument<string> quoteArgument = new("quote")
    {
        Description = "Text of quote."
    };
    Argument<string> bylineArgument = new("byline")
    {
        Description = "Byline of quote."
    };
    

    Le xref:System.CommandLine.Option.AllowMultipleArgumentsPerToken paramètre vous permet d’omettre le nom de l’option --search-terms lors de la spécification d’éléments dans la liste après le premier. Les exemples suivants d’entrée de ligne de commande sont équivalents :

    scl quotes delete --search-terms David "You can do"
    scl quotes delete --search-terms David --search-terms "You can do"
    
  3. Remplacez le code qui crée la commande racine et la read commande par le code suivant :

    RootCommand rootCommand = new("Sample app for System.CommandLine");
    fileOption.Recursive = true;
    rootCommand.Options.Add(fileOption);
    
    Command quotesCommand = new("quotes", "Work with a file that contains quotes.");
    rootCommand.Subcommands.Add(quotesCommand);
    
    Command readCommand = new("read", "Read and display the file.")
    {
        delayOption,
        fgcolorOption,
        lightModeOption
    };
    quotesCommand.Subcommands.Add(readCommand);
    
    Command deleteCommand = new("delete", "Delete lines from the file.");
    deleteCommand.Options.Add(searchTermsOption);
    quotesCommand.Subcommands.Add(deleteCommand);
    
    Command addCommand = new("add", "Add an entry to the file.");
    addCommand.Arguments.Add(quoteArgument);
    addCommand.Arguments.Add(bylineArgument);
    addCommand.Aliases.Add("insert");
    quotesCommand.Subcommands.Add(addCommand);
    

    Ce code apporte les modifications suivantes :

    • Supprime l’option --file de la read commande.

    • Ajoute l’option --file en tant qu’option récursive à la commande racine.

    • Crée une quotes commande et l’ajoute à la commande racine.

    • Ajoute la commande read à la commande quotes au lieu de l'ajouter à la commande racine.

    • Crée les commandes add et delete et les ajoute à la commande quotes.

    Le résultat est la hiérarchie de commandes suivante :

    • Commande racine
      • quotes
        • read
        • add
        • delete

    L’application implémente désormais le modèle recommandé où la commande parente (quotes) spécifie une zone ou un groupe, et ses commandes enfants (read, , adddelete) sont des actions.

    Les options récursives sont appliquées à la commande et récursivement aux sous-commandes. Étant donné qu’elle --file se trouve sur la commande racine, elle sera disponible automatiquement dans toutes les sous-commandes de l’application.

  4. Après le SetAction code, ajoutez un nouveau SetAction code pour les nouvelles sous-commandes :

    deleteCommand.SetAction(parseResult => DeleteFromFile(
        parseResult.GetValue(fileOption),
        parseResult.GetValue(searchTermsOption)));
    
    addCommand.SetAction(parseResult => AddToFile(
        parseResult.GetValue(fileOption),
        parseResult.GetValue(quoteArgument),
        parseResult.GetValue(bylineArgument))
        );
    

    La sous-commande quotes n’a pas d’action, car elle n’est pas une commande feuille. Les sous-commandes read, add et delete sont des commandes terminales sous quotes, et SetAction est appelée pour chacune d'elles.

  5. Ajoutez les actions pour add et delete.

    internal static void DeleteFromFile(FileInfo file, string[] searchTerms)
    {
        Console.WriteLine("Deleting from file");
    
        var lines = File.ReadLines(file.FullName).Where(line => searchTerms.All(s => !line.Contains(s)));
        File.WriteAllLines(file.FullName, lines);
    }
    internal static void AddToFile(FileInfo file, string quote, string byline)
    {
        Console.WriteLine("Adding to file");
    
        using StreamWriter writer = file.AppendText();
        writer.WriteLine($"{Environment.NewLine}{Environment.NewLine}{quote}");
        writer.WriteLine($"{Environment.NewLine}-{byline}");
    }
    

L’application terminée ressemble à ceci :

using System.CommandLine;

namespace scl;

class Program
{
    static int Main(string[] args)
    {
        Option<FileInfo> fileOption = new("--file")
        {
            Description = "An option whose argument is parsed as a FileInfo",
            Required = true,
            DefaultValueFactory = result =>
            {
                if (result.Tokens.Count == 0)
                {
                    return new FileInfo("sampleQuotes.txt");

                }
                string filePath = result.Tokens.Single().Value;
                if (!File.Exists(filePath))
                {
                    result.AddError("File does not exist");
                    return null;
                }
                else
                {
                    return new FileInfo(filePath);
                }
            }
        };

        Option<int> delayOption = new("--delay")
        {
            Description = "Delay between lines, specified as milliseconds per character in a line.",
            DefaultValueFactory = parseResult => 42
        };
        Option<ConsoleColor> fgcolorOption = new("--fgcolor")
        {
            Description = "Foreground color of text displayed on the console.",
            DefaultValueFactory = parseResult => ConsoleColor.White
        };
        Option<bool> lightModeOption = new("--light-mode")
        {
            Description = "Background color of text displayed on the console: default is black, light mode is white."
        };

        Option<string[]> searchTermsOption = new("--search-terms")
        {
            Description = "Strings to search for when deleting entries.",
            Required = true,
            AllowMultipleArgumentsPerToken = true
        };
        Argument<string> quoteArgument = new("quote")
        {
            Description = "Text of quote."
        };
        Argument<string> bylineArgument = new("byline")
        {
            Description = "Byline of quote."
        };

        RootCommand rootCommand = new("Sample app for System.CommandLine");
        fileOption.Recursive = true;
        rootCommand.Options.Add(fileOption);

        Command quotesCommand = new("quotes", "Work with a file that contains quotes.");
        rootCommand.Subcommands.Add(quotesCommand);

        Command readCommand = new("read", "Read and display the file.")
        {
            delayOption,
            fgcolorOption,
            lightModeOption
        };
        quotesCommand.Subcommands.Add(readCommand);

        Command deleteCommand = new("delete", "Delete lines from the file.");
        deleteCommand.Options.Add(searchTermsOption);
        quotesCommand.Subcommands.Add(deleteCommand);

        Command addCommand = new("add", "Add an entry to the file.");
        addCommand.Arguments.Add(quoteArgument);
        addCommand.Arguments.Add(bylineArgument);
        addCommand.Aliases.Add("insert");
        quotesCommand.Subcommands.Add(addCommand);

        readCommand.SetAction(parseResult => ReadFile(
            parseResult.GetValue(fileOption),
            parseResult.GetValue(delayOption),
            parseResult.GetValue(fgcolorOption),
            parseResult.GetValue(lightModeOption)));

        deleteCommand.SetAction(parseResult => DeleteFromFile(
            parseResult.GetValue(fileOption),
            parseResult.GetValue(searchTermsOption)));

        addCommand.SetAction(parseResult => AddToFile(
            parseResult.GetValue(fileOption),
            parseResult.GetValue(quoteArgument),
            parseResult.GetValue(bylineArgument))
            );

        return rootCommand.Parse(args).Invoke();
    }

    internal static void ReadFile(FileInfo file, int delay, ConsoleColor fgColor, bool lightMode)
    {
        Console.BackgroundColor = lightMode ? ConsoleColor.White : ConsoleColor.Black;
        Console.ForegroundColor = fgColor;
        foreach (string line in File.ReadLines(file.FullName))
        {
            Console.WriteLine(line);
            Thread.Sleep(TimeSpan.FromMilliseconds(delay * line.Length));
        }
    }
    internal static void DeleteFromFile(FileInfo file, string[] searchTerms)
    {
        Console.WriteLine("Deleting from file");

        var lines = File.ReadLines(file.FullName).Where(line => searchTerms.All(s => !line.Contains(s)));
        File.WriteAllLines(file.FullName, lines);
    }
    internal static void AddToFile(FileInfo file, string quote, string byline)
    {
        Console.WriteLine("Adding to file");

        using StreamWriter writer = file.AppendText();
        writer.WriteLine($"{Environment.NewLine}{Environment.NewLine}{quote}");
        writer.WriteLine($"{Environment.NewLine}-{byline}");
    }
}

Générez le projet, puis essayez les commandes suivantes.

Soumettez un fichier inexistant à --file avec la commande read, et vous obtiendrez un message d'erreur au lieu d'une exception et d'une trace de pile :

scl quotes read --file nofile
File does not exist

Essayez d’exécuter la sous-commande quotes et vous obtenez un message vous permettant d’utiliser read, addou delete:

scl quotes
Required command was not provided.

Description:
  Work with a file that contains quotes.

Usage:
  scl quotes [command] [options]

Options:
  --file <file>   An option whose argument is parsed as a FileInfo [default: sampleQuotes.txt]
  -?, -h, --help  Show help and usage information

Commands:
  read                          Read and display the file.
  delete                        Delete lines from the file.
  add, insert <quote> <byline>  Add an entry to the file.

Exécutez la sous-commande add, puis examinez la fin du fichier texte pour afficher le texte ajouté :

scl quotes add "Hello world!" "Nancy Davolio"

Exécutez la sous-commande delete avec des chaînes de recherche à partir du début du fichier, puis examinez le début du fichier texte pour voir où le texte a été supprimé :

scl quotes delete --search-terms David "You can do" Antoine "Perfection is achieved"

Remarque

Si vous êtes en cours d’exécution dans le dossier bin/debug/net9.0, ce dossier se trouve à l’emplacement où vous trouverez le fichier avec des modifications à partir des commandes et delete des add commandes. La copie du fichier dans le dossier du projet reste inchangée.

Étapes suivantes

Dans ce tutoriel, vous avez créé une application de ligne de commande simple qui utilise System.CommandLine. Pour en savoir plus sur la bibliothèque, consultez System.CommandLine vue d’ensemble.