Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
In diesem Lernprogramm wird gezeigt, wie Sie eine .NET-Befehlszeilen-App erstellen, die die System.CommandLine Bibliothek verwendet. Sie beginnen mit dem Erstellen eines einfachen Stammbefehls, der über eine Option verfügt. Anschließend erstellen Sie auf dieser Basis eine komplexere App, die mehrere Unterbefehle und unterschiedliche Optionen für jeden Befehl enthält.
In diesem Tutorial lernen Sie Folgendes:
- Erstellen Sie Befehle, Optionen und Argumente.
- Geben Sie Standardwerte für Optionen an.
- Weisen Sie Befehlen Optionen und Argumente zu.
- Weisen Sie allen Unterbefehlen unter einem Befehl rekursiv eine Option zu.
- Arbeiten Sie mit mehreren Ebenen geschachtelter Unterbefehle.
- Erstellen Sie Aliase für Befehle und Optionen.
- Arbeiten Sie mit
string,string[],int,bool,FileInfound enum Optionstypen. - Lesen von Optionswerten im Befehlsaktionscode.
- Verwenden Sie benutzerdefinierten Code zum Analysieren und Überprüfen von Optionen.
Voraussetzungen
- Das neueste .NET SDK
- Visual Studio Code-Editor
- Das C# DevKit
Oder
- Visual Studio 2022 mit installierter Workload .NET-Desktopentwicklung.
Erstellen der App
Erstellen Sie ein .NET 9-Konsolen-App-Projekt mit dem Namen "scl".
Erstellen Sie einen Ordner mit dem Namen "scl " für das Projekt, und öffnen Sie dann eine Eingabeaufforderung im neuen Ordner.
Führen Sie den folgenden Befehl aus:
dotnet new console --framework net9.0
Installieren Sie das System.CommandLine-Paket
Führen Sie den folgenden Befehl aus:
dotnet add package System.CommandLine --prereleaseOder in .NET 10+:
dotnet package add System.CommandLine --prereleaseDie
--prereleaseOption ist erforderlich, da sich die Bibliothek noch in der Betaversion befindet.
Analysieren der Argumente
Ersetzen Sie den Inhalt von Program.cs durch den folgenden Code:
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.Errors.Count == 0 && 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); } } }
Der vorherige Code:
- Erstellt eine Option vom Typ
--file, die FileInfo genannt wird, und fügt sie dem Stammbefehl hinzu.
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);
- Analysiert
argsund überprüft, ob ein beliebiger Wert für die Option--filebereitgestellt wurde. Wenn dies der Fall ist, ruft sie dieReadFileMethode mit analysierten Werten auf und gibt Exit-Code zurück0:
ParseResult parseResult = rootCommand.Parse(args);
if (parseResult.Errors.Count == 0 && parseResult.GetValue(fileOption) is FileInfo parsedFile)
{
ReadFile(parsedFile);
return 0;
}
- Wenn kein Wert für
--fileangegeben wurde, werden verfügbare Analysefehler ausgegeben und der Exit-Code1zurückgegeben.
foreach (ParseError parseError in parseResult.Errors)
{
Console.Error.WriteLine(parseError.Message);
}
return 1;
- Die
ReadFileMethode liest die angegebene Datei und zeigt den Inhalt auf der Konsole an:
static void ReadFile(FileInfo file)
{
foreach (string line in File.ReadLines(file.FullName))
{
Console.WriteLine(line);
}
}
Testen der App
Sie können eine der folgenden Möglichkeiten zum Testen während der Entwicklung einer Befehlszeilen-App verwenden:
Führen Sie den
dotnet buildBefehl aus, und öffnen Sie dann eine Eingabeaufforderung im Ordner "scl/bin/Debug/net9.0 ", um die ausführbare Datei auszuführen:dotnet build cd bin/Debug/net9.0 scl --file scl.runtimeconfig.jsonVerwenden Sie
dotnet run, und übergeben Sie Optionswerte anstelle desrun-Befehls an die App, indem Sie sie wie im folgenden Beispiel gezeigt nach--einschließen:dotnet run -- --file bin/Debug/net9.0/scl.runtimeconfig.json
In diesem Lernprogramm wird davon ausgegangen, dass Sie die erste dieser Optionen verwenden.
Wenn Sie die App ausführen, wird der Inhalt der durch die --file Option angegebenen Datei angezeigt.
{
"runtimeOptions": {
"tfm": "net9.0",
"framework": {
"name": "Microsoft.NETCore.App",
"version": "9.0.0"
}
}
}
Aber was passiert, wenn Sie es mit --help auffordern, die Hilfe anzuzeigen? Auf der Konsole wird nichts ausgegeben, weil die App das Szenario, bei dem --file nicht angegeben ist und keine Parsefehler vorliegen, noch nicht behandelt.
Analysieren sie die Argumente, und rufen Sie das ParseResult auf.
System.CommandLine ermöglicht es Ihnen, eine Aktion anzugeben, die aufgerufen wird, wenn ein bestimmtes Symbol (Befehl, Direktive oder Option) erfolgreich analysiert wird. Die Aktion ist ein Delegat, der einen System.CommandLine.ParseResult Parameter verwendet und einen int Exitcode zurückgibt (asynchrone Aktionen sind ebenfalls verfügbar). Der Beendigungscode wird von der System.CommandLine.Parsing.ParseResult.Invoke Methode zurückgegeben und kann verwendet werden, um anzugeben, ob der Befehl erfolgreich ausgeführt wurde oder nicht.
Ersetzen Sie den Inhalt von Program.cs durch den folgenden Code:
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); } } }
Der vorherige Code:
Gibt die Methode an
ReadFile, die aufgerufen wird, wenn der Stammbefehl aufgerufen wird:rootCommand.SetAction(parseResult => { FileInfo parsedFile = parseResult.GetValue(fileOption); ReadFile(parsedFile); return 0; });Parst die
argsund ruft das Ergebnis auf:ParseResult parseResult = rootCommand.Parse(args); return parseResult.Invoke();
Wenn Sie die App ausführen, wird der Inhalt der durch die --file Option angegebenen Datei angezeigt.
Was geschieht, wenn Sie sie bitten, die Hilfe anzuzeigen, indem Sie angeben --help?
scl --help
Die folgende Ausgabe wird ausgegeben:
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
RootCommand stellt standardmäßig die Hilfeoption, die Versionsoption und die Vorschlags-Direktive bereit. Die ParseResult.Invoke(InvocationConfiguration) Methode ist für das Aufrufen der Aktion des analysierten Symbols verantwortlich. Dabei kann es sich um die explizit für den Befehl definierte Aktion oder um die Hilfeaktion handeln, die von System.CommandLine für System.CommandLine.Help.HelpOption definiert ist. Darüber hinaus werden beim Erkennen von Analysefehlern diese auf den Standardfehler gedruckt, die Ausgabe wird als Standardausgabe gedruckt und als Ausgangscode zurückgegeben 1 :
scl --invalid bla
Unrecognized command or argument '--invalid'.
Unrecognized command or argument 'bla'.
Hinzufügen eines Unterbefehls und von Optionen
In diesem Abschnitt führen Sie Folgendes aus:
- Erstellen Sie weitere Optionen.
- Erstellen Sie einen Unterbefehl.
- Weisen Sie dem neuen Unterbefehl die neuen Optionen zu.
Mit den neuen Optionen können Sie die Vordergrund- und Hintergrundtextfarben und die Lesegeschwindigkeit konfigurieren. Diese Features werden verwendet, um eine Sammlung von Zitaten zu lesen, die aus dem Lernprogramm der Teleprompter-Konsolen-App stammen.
Kopieren Sie die sampleQuotes.txt Datei aus dem GitHub-Repository für dieses Beispiel in Ihr Projektverzeichnis. Informationen zum Herunterladen von Dateien finden Sie in den Anweisungen in Beispielen und Lernprogrammen.
Öffnen Sie die Projektdatei, und fügen Sie direkt vor dem schließenden
<ItemGroup>Tag ein</Project>Element hinzu:<ItemGroup> <Content Include="sampleQuotes.txt"> <CopyToOutputDirectory>Always</CopyToOutputDirectory> </Content> </ItemGroup>Wenn Sie dieses Markup hinzufügen, wird die Textdatei beim Erstellen der App in den Ordner "bin/debug/net9.0" kopiert. Wenn Sie also die ausführbare Datei in diesem Ordner ausführen, können Sie nach Namen auf die Datei zugreifen, ohne einen Ordnerpfad anzugeben.
Erstellen Sie in Program.cs nach dem Code, der die
--fileOption erstellt, Optionen zum Steuern der Lesegeschwindigkeit und der Textfarben: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." };Löschen Sie nach der Zeile, die den Stammbefehl erstellt, den Code, der die
--fileOption hinzufügt. Sie entfernen es hier, da Sie ihn einem neuen Unterbefehl hinzufügen.Erstellen Sie nach der Zeile, die den Stammbefehl erstellt, einen
readUnterbefehl. Fügen Sie diesem Unterbefehl die Optionen hinzu, indem Sie die Sammlungsinitialisierungssyntax anstelle derOptionsEigenschaft verwenden, und fügen Sie den Unterbefehl zum Stammbefehl hinzu.Command readCommand = new("read", "Read and display the file.") { fileOption, delayOption, fgcolorOption, lightModeOption }; rootCommand.Subcommands.Add(readCommand);Ersetzen Sie den
SetActionCode durch den folgendenSetActionCode für den neuen Unterbefehl:readCommand.SetAction(parseResult => ReadFile( parseResult.GetValue(fileOption), parseResult.GetValue(delayOption), parseResult.GetValue(fgcolorOption), parseResult.GetValue(lightModeOption)));Sie rufen den Hauptbefehl
SetActionnicht mehr auf, da der Hauptbefehl keine Aktion mehr erfordert. Wenn ein Befehl Unterbefehle aufweist, müssen Sie in der Regel einen der Unterbefehle angeben, wenn Sie eine Befehlszeilen-App aufrufen.Ersetzen Sie die
ReadFileAktionsmethode durch den folgenden Code: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)); } }
Die App sieht nun wie folgt aus:
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));
}
}
}
Testen des neuen Unterbefehls
Wenn Sie nun versuchen, die App auszuführen, ohne den Unterbefehl anzugeben, wird eine Fehlermeldung gefolgt von einer Hilfemeldung angezeigt, die den verfügbaren Unterbefehl angibt.
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.
Der Hilfetext für den Unterbefehl read zeigt, dass vier Optionen verfügbar sind. Es werden gültige Werte für die Enumeration angezeigt.
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
Führen Sie den Unterbefehl read aus, der nur die --file Option angibt, und Sie erhalten die Standardwerte für die anderen drei Optionen.
scl read --file sampleQuotes.txt
Die Standardverzögerung von 42 Millisekunden pro Zeichen verursacht eine langsame Lesegeschwindigkeit. Sie können dies beschleunigen, indem Sie eine niedrigere Zahl festlegen --delay .
scl read --file sampleQuotes.txt --delay 0
Sie können --fgcolor und --light-mode verwenden, um Textfarben festzulegen.
scl read --file sampleQuotes.txt --fgcolor red --light-mode
Geben Sie einen ungültigen Wert ein --delay , und Sie erhalten eine Fehlermeldung:
scl read --file sampleQuotes.txt --delay forty-two
Cannot parse argument 'forty-two' for option '--int' as expected type 'System.Int32'.
Geben Sie einen ungültigen Wert ein --file , und Sie erhalten eine Ausnahme:
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''
Hinzufügen von Unterbefehlen und benutzerdefinierter Überprüfung
In diesem Abschnitt wird die endgültige Version der App erstellt. Nach Abschluss des Vorgangs verfügt die App über die folgenden Befehle und Optionen:
- Stammbefehl mit einer rekursiven* Option namens
--file-
quotesBefehl-
readBefehl mit optionen mit dem Namen--delay,--fgcolor, und--light-mode -
addBefehl mit benanntenquoteArgumenten undbyline -
deleteBefehl mit dem Namen der Option--search-terms
-
-
* Eine rekursive Option ist für den Befehl verfügbar, dem sie zugewiesen ist, und rekursiv für alle seine Unterbefehle.
Hier sehen Sie eine Beispiel-Befehlszeileneingabe, die jeden der verfügbaren Befehle mit den zugehörigen Optionen und Argumenten aufruft:
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"
Ersetzen Sie in Program.cs den Code, der die
--fileOption erstellt, durch den folgenden Code: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); } } };Dieser Code verwendet
System.CommandLine.Parsing.ArgumentResult, um benutzerdefinierte Analyse, Überprüfung und Fehlerbehandlung bereitzustellen.Ohne diesen Code werden fehlende Dateien mit einer Ausnahme und Stapelüberwachung gemeldet. Mit diesem Code wird nur die angegebene Fehlermeldung angezeigt.
Dieser Code gibt auch einen Standardwert an, weshalb er
DefaultValueFactoryauf eine benutzerdefinierte Analysemethode setzt.Fügen Sie nach dem Code, der
lightModeOptionerstellt, Optionen und Argumente für dieaddunddeleteBefehle hinzu.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." };Mit der
xref:System.CommandLine.Option.AllowMultipleArgumentsPerTokenEinstellung können Sie den--search-termsOptionsnamen weglassen, wenn Sie Elemente in der Liste nach dem ersten angeben. Die folgenden Beispiele für die Befehlszeileneingabe sind gleichwertig:scl quotes delete --search-terms David "You can do" scl quotes delete --search-terms David --search-terms "You can do"Ersetzen Sie den Code, der den Stammbefehl und den
readBefehl erstellt, durch den folgenden Code: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);Dieser Code nimmt die folgenden Änderungen vor:
Entfernt die
--fileOption aus demreadBefehl.Fügt die
--fileOption als rekursive Option zum Stammbefehl hinzu.Erstellt einen
quotesBefehl und fügt ihn dem Stammbefehl hinzu.Fügt den
readBefehl demquotesBefehl anstelle des Stammbefehls hinzu.Erstellt
addunddeletebefehle und fügt sie demquotesBefehl hinzu.
Das Ergebnis ist die folgende Befehlshierarchie:
- Stammbefehl
quotesreadadddelete
Die App implementiert jetzt das empfohlene Muster, bei dem der übergeordnete Befehl (
quotes) einen Bereich oder eine Gruppe angibt und die untergeordneten Elemente (read,add,delete) Aktionen sind.Rekursive Optionen werden auf den Befehl angewendet und rekursiv auf Unterbefehle angewendet. Da sich
--fileim Stammbefehl befindet, wird er automatisch in allen Unterbefehlen der App verfügbar sein.Fügen Sie nach dem
SetActionCode neuenSetActionCode für die neuen Unterbefehle hinzu:deleteCommand.SetAction(parseResult => DeleteFromFile( parseResult.GetValue(fileOption), parseResult.GetValue(searchTermsOption))); addCommand.SetAction(parseResult => AddToFile( parseResult.GetValue(fileOption), parseResult.GetValue(quoteArgument), parseResult.GetValue(bylineArgument)) );Der Unterbefehl
quotesverfügt nicht über eine Aktion, da es sich nicht um einen Blattbefehl handelt. Unterbefehleread,add, unddeletesind Blattbefehle unterquotes, undSetActionwird für jeden von ihnen aufgerufen.Fügen Sie die Aktionen für
addunddelete.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}"); }
Die fertige App sieht wie folgt aus:
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}");
}
}
Erstellen Sie das Projekt, und versuchen Sie dann die folgenden Befehle.
Übermitteln Sie mit dem --file-Befehl eine nicht vorhandene Datei an read, und Sie erhalten eine Fehlermeldung anstelle einer Ausnahme und Stapelüberwachung:
scl quotes read --file nofile
File does not exist
Versuchen Sie, den Unterbefehl quotes auszuführen, und Sie erhalten eine Nachricht, die Sie zur Verwendung von read, add oder delete auffordert.
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.
Führen Sie den Unterbefehl addaus, und sehen Sie sich dann das Ende der Textdatei an, um den hinzugefügten Text anzuzeigen:
scl quotes add "Hello world!" "Nancy Davolio"
Führen Sie den Unterbefehl delete mit Suchzeichenfolgen am Anfang der Datei aus, und sehen Sie sich dann den Anfang der Textdatei an, um zu sehen, wo Text entfernt wurde:
scl quotes delete --search-terms David "You can do" Antoine "Perfection is achieved"
Hinweis
Wenn Sie den Ordner "bin/debug/net9.0" ausführen, finden Sie in diesem Ordner die Datei mit Änderungen, die durch die Befehle add und delete vorgenommen wurden. Die Kopie der Datei im Projektordner bleibt unverändert.
Nächste Schritte
In diesem Tutorial haben Sie eine einfache Befehlszeilen-App erstellt, die System.CommandLine verwendet. Weitere Informationen zur Bibliothek finden Sie in System.CommandLine der Übersicht.