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.
Von Bedeutung
System.CommandLine
befindet sich derzeit in DER VORSCHAU, und diese Dokumentation ist für Version 2.0 Beta 5 vorgesehen.
Einige Informationen beziehen sich auf vorab veröffentlichte Produkte, die vor der Veröffentlichung erheblich geändert werden können. Microsoft gibt keine Garantie, weder ausdrücklich noch impliziert, hinsichtlich der hier bereitgestellten Informationen.
Der Hauptfokus für die 2.0.0-Beta5-Version war die Verbesserung der APIs und ein Schritt zur Veröffentlichung einer stabilen Version von System.CommandLine. Die APIs wurden vereinfacht und mit den Framework-Entwurfsrichtlinien kohärenter gestaltet. In diesem Artikel werden die bahnbrechenden Änderungen beschrieben, die in 2.0.0-Beta5 vorgenommen wurden, und deren Begründung.
Umbenennung
In 2.0.0-beta4 folgen nicht alle Typen und Member den Benennungsrichtlinien. Einige waren nicht mit den Benennungskonventionen konsistent, z. B. die Verwendung des Is
Präfixes für boolesche Eigenschaften. In 2.0.0-beta5 wurden einige Typen und Member umbenannt. Die folgende Tabelle zeigt die alten und neuen Namen:
Alter Name | Neuer Name |
---|---|
System.CommandLine.Parsing.Parser |
System.CommandLine.Parsing.CommandLineParser |
System.CommandLine.Parsing.OptionResult.IsImplicit |
System.CommandLine.Parsing.OptionResult.Implicit |
System.CommandLine.Option.IsRequired |
System.CommandLine.Option.Required |
System.CommandLine.Symbol.IsHidden |
System.CommandLine.Symbol.Hidden |
System.CommandLine.Option.ArgumentHelpName |
System.CommandLine.Option.HelpName |
System.CommandLine.Parsing.OptionResult.Token |
System.CommandLine.Parsing.OptionResult.IdentifierToken |
System.CommandLine.Parsing.ParseResult.FindResultFor |
System.CommandLine.Parsing.ParseResult.GetResult |
System.CommandLine.Parsing.SymbolResult.ErrorMessage |
System.CommandLine.Parsing.SymbolResult.AddError |
Damit mehrere Fehler für dasselbe Symbol gemeldet werden können, wurde die ErrorMessage
Eigenschaft in eine Methode konvertiert und umbenannt AddError
in .
Verfügbarmachen von veränderbaren Sammlungen
Version 2.0.0-beta4 verfügte über zahlreiche Add
Methoden, die zum Hinzufügen von Elementen zu Auflistungen verwendet wurden, z. B. Argumente, Optionen, Unterbefehle, Validatoren und Fertigstellungen. Einige dieser Auflistungen wurden über Eigenschaften als schreibgeschützte Auflistungen verfügbar gemacht. Aus diesem Gründen war es unmöglich, Elemente aus diesen Sammlungen zu entfernen.
In 2.0.0-beta5 haben wir die APIs so geändert, dass änderbare Sammlungen anstelle von Add
Methoden und (manchmal) schreibgeschützte Auflistungen verfügbar gemacht werden. Auf diese Weise können Sie nicht nur Elemente hinzufügen oder aufzählen, sondern auch entfernen. In der folgenden Tabelle sind die alten Methoden und neuen Eigenschaftennamen aufgeführt:
Alter Methodenname | Neue Eigenschaft |
---|---|
System.CommandLine.Command.AddArgument |
System.CommandLine.Command.Arguments.Add |
System.CommandLine.Command.AddOption |
System.CommandLine.Command.Options.Add |
System.CommandLine.Command.AddCommand |
System.CommandLine.Command.Subcommands.Add |
System.CommandLine.Command.AddValidator |
System.CommandLine.Command.Validators.Add |
System.CommandLine.Option.AddValidator |
System.CommandLine.Option.Validators.Add |
System.CommandLine.Argument.AddValidator |
System.CommandLine.Argument.Validators.Add |
System.CommandLine.Command.AddCompletions |
System.CommandLine.Command.CompletionSources.Add |
System.CommandLine.Option.AddCompletions |
System.CommandLine.Option.CompletionSources.Add |
System.CommandLine.Argument.AddCompletions |
System.CommandLine.Argument.CompletionSources.Add |
System.CommandLine.Command.AddAlias |
System.CommandLine.Command.Aliases.Add |
System.CommandLine.Option.AddAlias |
System.CommandLine.Option.Aliases.Add |
Die RemoveAlias
Methoden und HasAlias
Methoden wurden ebenfalls entfernt, da die Aliases
Eigenschaft jetzt eine änderbare Auflistung ist. Mit der Remove
Methode können Sie einen Alias aus der Sammlung entfernen. Verwenden Sie die Contains
Methode, um zu überprüfen, ob ein Alias vorhanden ist.
Namen und Aliase
Vor dem 2.0.0.0-Beta5 gab es keine klare Trennung zwischen dem Namen und den Aliasen eines Symbols. Wenn name
für den Option<T>
Konstruktor nicht angegeben wurde, meldete das Symbol seinen Namen als längsten Alias mit Präfixen wie --
, -
oder /
entfernt. Das war verwirrend.
Darüber hinaus mussten Benutzer zum Abrufen des analysierten Werts einen Verweis auf eine Option oder ein Argument speichern und dann verwenden, um den Wert abzurufen ParseResult
.
Um Einfachheit und Explizitkeit zu fördern, ist der Name eines Symbols jetzt ein obligatorischer Parameter für jeden Symbolkonstruktor (einschließlich Argument<T>
). Wir trennten auch das Konzept eines Namens und Aliases; Jetzt sind Aliase nur Aliase und enthalten nicht den Namen des Symbols. Natürlich sind sie optional. Daher wurden die folgenden Änderungen vorgenommen:
-
name
ist jetzt ein obligatorisches Argument für jeden öffentlichen Konstruktor vonArgument<T>
,Option<T>
undCommand
. Im Fall vonArgument<T>
, wird es nicht für die Analyse verwendet, sondern um die Hilfe zu generieren. Im FallOption<T>
undCommand
, wird es verwendet, um das Symbol während der Analyse und auch für Hilfe und Fertigstellungen zu identifizieren. - Die
Symbol.Name
Eigenschaft ist nicht mehrvirtual
vorhanden. Sie ist jetzt schreibgeschützt und gibt den Namen zurück, wie er beim Erstellen des Symbols angegeben wurde. Aus diesemSymbol.DefaultName
Gründen wurde das Präfix oder-
/
ein anderes Präfix aus dem längsten--
Alias entfernt undOption.Name
nicht mehr entfernt. - Die
Aliases
Eigenschaft, die vonOption
undCommand
jetzt eine änderbare Auflistung verfügbar gemacht wird. Diese Auflistung enthält nicht mehr den Namen des Symbols. -
System.CommandLine.Parsing.IdentifierSymbol
wurde entfernt (es war ein Basistyp für beideCommand
undOption
).
Wenn der Name immer vorhanden ist, können Sie den analysierten Wert anhand des Namens abrufen:
RootCommand command = new("The description.")
{
new Option<int>("--number")
};
ParseResult parseResult = command.Parse(args);
int number = parseResult.GetValue<int>("--number");
Erstellen von Optionen mit Aliasen
In der Vergangenheit wurden Option<T>
viele Konstruktoren verfügbar gemacht, von denen einige den Namen akzeptierten. Da der Name jetzt obligatorisch ist und wir erwarten, dass Aliase häufig bereitgestellt Option<T>
werden, gibt es nur einen einzelnen Konstruktor. Er akzeptiert den Namen und ein params
Array von Aliasen.
Vor 2.0.0-beta5 hatte ein Konstruktor einen Option<T>
Namen und eine Beschreibung. Aus diesem Grund kann das zweite Argument nun als Alias und nicht als Beschreibung behandelt werden. Dies ist die einzige bekannte änderung in der API, die keinen Compilerfehler verursacht.
Alter Code, der den Konstruktor mit einer Beschreibung verwendet hat, sollte aktualisiert werden, um den neuen Konstruktor zu verwenden, der einen Namen und Alias verwendet, und dann die Description
Eigenschaft separat festlegen. Beispiel:
Option<bool> beta4 = new("--help", "An option with aliases.");
beta4b.Aliases.Add("-h");
beta4b.Aliases.Add("/h");
Option<bool> beta5 = new("--help", "-h", "/h")
{
Description = "An option with aliases."
};
Standardwerte und benutzerdefinierte Analyse
In 2.0.0-beta4 konnten Benutzer Standardwerte für Optionen und Argumente mithilfe der SetDefaultValue
Methoden festlegen. Diese Methoden akzeptierten einen object
Wert, der nicht typsicher war und zu Laufzeitfehlern führen konnte, wenn der Wert nicht mit dem Options- oder Argumenttyp kompatibel war:
Option<int> option = new("--number");
option.SetDefaultValue("text"); // This is not type-safe, as the value is a string, not an int.
Darüber hinaus akzeptierten einige der Option
und Argument
Konstruktoren einen Analysedelegat und einen booleschen Wert, der angibt, ob der Delegate ein benutzerdefinierter Parser oder ein Standardwertanbieter war. Dies war verwirrend.
Option<T>
und Argument<T>
Klassen verfügen jetzt über eine DefaultValueFactory
Eigenschaft, die zum Festlegen eines Delegaten verwendet werden kann, der aufgerufen werden kann, um den Standardwert für die Option oder das Argument abzurufen. Dieser Delegat wird aufgerufen, wenn die Option oder das Argument in der analysierten Befehlszeileneingabe nicht gefunden wird.
Option<int> number = new("--number")
{
DefaultValueFactory = _ => 42
};
Argument<T>
und Option<T>
enthält auch eine CustomParser
Eigenschaft, die verwendet werden kann, um einen benutzerdefinierten Parser für das Symbol festzulegen:
Argument<Uri> uri = new("arg")
{
CustomParser = result =>
{
if (!Uri.TryCreate(result.Tokens.Single().Value, UriKind.RelativeOrAbsolute, out var uriValue))
{
result.AddError("Invalid URI format.");
return null;
}
return uriValue;
}
};
Darüber hinaus CustomParser
akzeptiert eine Stellvertretung vom Typ Func<ParseResult, T>
statt der vorherigen ParseArgument
Stellvertretung. Dies und einige andere benutzerdefinierte Delegaten wurden entfernt, um die API zu vereinfachen und die Anzahl der Typen zu reduzieren, die von der API verfügbar gemacht werden, wodurch die Startzeit für die JIT-Kompilierung reduziert wird.
Weitere Beispiele für die Verwendung DefaultValueFactory
und CustomParser
die Überprüfung finden Sie unter "Anpassen der Analyse und Validierung" in System.CommandLine.
Trennung von Analyse und Aufruf
In 2.0.0-beta4 war es möglich, die Analyse und das Aufrufen von Befehlen zu trennen, aber es war ziemlich unklar, wie das geht.
Command
hat keine Parse
Methode verfügbar gemacht, sondern CommandExtensions
bereitgestellte Parse
, Invoke
und InvokeAsync
Erweiterungsmethoden für Command
. Dies war verwirrend, da es nicht klar war, welche Methode und wann verwendet werden soll. Die folgenden Änderungen wurden vorgenommen, um die API zu vereinfachen:
-
Command
stellt nun eineParse
Methode zur Verfügung, die einParseResult
Objekt zurückgibt. Diese Methode wird verwendet, um die Befehlszeileneingabe zu analysieren und das Ergebnis des Analysevorgangs zurückzugeben. Darüber hinaus wird klar, dass der Befehl nicht aufgerufen wird, sondern nur synchron analysiert wird. -
ParseResult
Stellt jetzt sowohl methodenInvoke
alsInvokeAsync
auch Methoden zur Verfügung, die zum Aufrufen des Befehls verwendet werden können. Dadurch wird deutlich, dass der Befehl nach der Analyse aufgerufen wird und sowohl synchrone als auch asynchrone Aufrufe ermöglicht. - Die
CommandExtensions
Klasse wurde entfernt, da sie nicht mehr benötigt wird.
Konfiguration
Vor 2.0.0-Beta5 war es möglich, die Analyse anzupassen, aber nur mit einigen der öffentlichen Parse
Methoden. Es gab eine Parser
Klasse, die zwei öffentliche Konstruktoren verfügbar gemacht hat: eine, die eine Command
und eine andere akzeptiert.CommandLineConfiguration
CommandLineConfiguration
war unveränderlich und zum Erstellen mussten Sie ein Generatormuster verwenden, das von der CommandLineBuilder
Klasse verfügbar gemacht wird. Die folgenden Änderungen wurden vorgenommen, um die API zu vereinfachen:
-
CommandLineConfiguration
wurde änderbar gemacht undCommandLineBuilder
entfernt. Das Erstellen einer Konfiguration ist jetzt so einfach wie das Erstellen einer InstanzCommandLineConfiguration
und das Festlegen der Eigenschaften, die Sie anpassen möchten. Darüber hinaus entspricht das Erstellen einer neuen Konfigurationsinstanz dem AufrufenCommandLineBuilder
UseDefaults
der Methode. - Jede
Parse
Methode akzeptiert jetzt einen optionalenCommandLineConfiguration
Parameter, der zum Anpassen der Analyse verwendet werden kann. Wenn sie nicht bereitgestellt wird, wird die Standardkonfiguration verwendet. -
Parser
wurde umbenannt,CommandLineParser
um Namenkonflikte zu vermeiden, um mehrdeutig von anderen Parsertypen zu unterscheiden. Da es zustandslos ist, ist es jetzt eine statische Klasse mit nur statischen Methoden. Es macht zweiParse
Analysemethoden verfügbar: eine, die eineIReadOnlyList<string> args
und eine andere akzeptiert.string args
Letzteres verwendetCommandLineParser.SplitCommandLine
(auch öffentlich), um die Befehlszeileneingabe in Token aufzuteilen, bevor sie analysiert werden.
CommandLineBuilderExtensions
wurde ebenfalls entfernt. Hier erfahren Sie, wie Sie die Methoden den neuen APIs zuordnen können:
CancelOnProcessTermination
ist jetzt eine Eigenschaft mit demCommandLineConfiguration
Namen "ProcessTerminationTimeout". Sie ist standardmäßig mit einem 2s-Timeout aktiviert. Legen Sie sie fest, umnull
sie zu deaktivieren.EnableDirectives
,UseEnvironmentVariableDirective
,UseParseDirective
undUseSuggestDirective
wurden entfernt. Ein neuer Direktiventyp wurde eingeführt, und der RootCommand machtSystem.CommandLine.RootCommand.Directives
jetzt die Eigenschaft verfügbar. Mithilfe dieser Auflistung können Sie Direktiven hinzufügen, entfernen und durchlaufen. Vorschlagsdirektive ist standardmäßig enthalten; Sie können auch andere Direktiven wie DiagramDirective oderEnvironmentVariablesDirective
.EnableLegacyDoubleDashBehavior
wurde entfernt. Alle nicht übereinstimmende Token werden jetzt von der ParseResult.UnmatchedTokens-Eigenschaft verfügbar gemacht.EnablePosixBundling
wurde entfernt. Die Bündelung ist jetzt standardmäßig aktiviert, Sie können sie deaktivieren, indem Sie die CommandLineConfiguration.EnableBundling-Eigenschaft auffalse
festlegen.RegisterWithDotnetSuggest
wurde entfernt, da sie einen kostspieligen Vorgang ausgeführt hat, in der Regel während des Anwendungsstarts. Jetzt müssen Sie Befehledotnet suggest
manuell registrieren.UseExceptionHandler
wurde entfernt. Der Standardausnahmehandler ist jetzt standardmäßig aktiviert, Sie können ihn deaktivieren, indem Sie die CommandLineConfiguration.EnableDefaultExceptionHandler-Eigenschaft auffalse
festlegen. Dies ist nützlich, wenn Sie Ausnahmen auf benutzerdefinierte Weise behandeln möchten, indem Sie einfach dieInvoke
OderInvokeAsync
Methoden in einen Try-Catch-Block umschließen.UseHelp
undUseVersion
wurden entfernt. Die Hilfe und Version werden jetzt von den öffentlichen Typen "HelpOption " und "VersionOption " verfügbar gemacht. Sie sind beide standardmäßig in den durch RootCommand definierten Optionen enthalten.UseHelpBuilder
wurde entfernt. Weitere Informationen zum Anpassen der Hilfeausgabe finden Sie unter Anpassen der Hilfe in System.CommandLine.AddMiddleware
wurde entfernt. Er hat den Start der Anwendung verlangsamt, und die Features können ohne sie ausgedrückt werden.UseParseErrorReporting
undUseTypoCorrections
wurden entfernt. Die Analysefehler werden jetzt standardmäßig beim AufrufenParseResult
gemeldet. Sie können sie mithilfe derParseErrorAction
verfügbar gemachtenParseResult.Action
Eigenschaft konfigurieren.ParseResult result = rootCommand.Parse("myArgs", config); if (result.Action is ParseErrorAction parseError) { parseError.ShowTypoCorrections = true; parseError.ShowHelp = false; }
UseLocalizationResources
undLocalizationResources
wurden entfernt. Dieses Feature wurde hauptsächlich von derdotnet
CLI verwendet, um fehlende Übersetzungen hinzuzufügenSystem.CommandLine
. Alle diese Übersetzungen wurden in das System.CommandLine Selbst verschoben, sodass dieses Feature nicht mehr benötigt wird. Wenn wir keine Unterstützung für Ihre Sprache haben, melden Sie bitte ein Problem.UseTokenReplacer
wurde entfernt. Antwortdateien sind standardmäßig aktiviert, aber Sie können sie deaktivieren, indem Sie dieSystem.CommandLine.CommandLineConfiguration.ResponseFileTokenReplacer
Eigenschaft aufnull
. Sie können auch eine benutzerdefinierte Implementierung bereitstellen, um die Verarbeitung von Antwortdateien anzupassen.
Zuletzt wurden die IConsole
und alle zugehörigen Schnittstellen (IStandardOut
, IStandardError
, IStandardIn
) entfernt.
System.CommandLine.CommandLineConfiguration
macht zwei TextWriter
Eigenschaften verfügbar: Output
und Error
. Diese können auf eine beliebige TextWriter
Instanz festgelegt werden, z. B. eine StringWriter
, die zum Erfassen der Ausgabe für Tests verwendet werden kann. Unsere Motivation war es, weniger Typen verfügbar zu machen und vorhandene Abstraktionen wiederzuverwenden.
Aufruf
In 2.0.0-beta4 wurde die ICommandHandler
Schnittstelle verfügbar gemacht Invoke
und InvokeAsync
Methoden, die zum Aufrufen des analysierten Befehls verwendet wurden. Dies erleichterte das Kombinieren von synchronem und asynchronem Code, z. B. durch Definieren eines synchronen Handlers für einen Befehl und anschließendes Aufrufen asynchron (was zu einem Deadlock führen kann). Darüber hinaus war es möglich, einen Handler nur für einen Befehl zu definieren, aber nicht für eine Option (z. B. Hilfe, die Hilfe anzeigt) oder eine Direktive.
Eine neue abstrakte Basisklasse System.CommandLine.CommandLineAction
und zwei abgeleitete Klassen: System.CommandLine.SynchronousCommandLineAction
und System.CommandLine.AsynchronousCommandLineAction
wurden eingeführt. Der erste Wird für synchrone Aktionen verwendet, die einen int
Exitcode zurückgeben, während letztere für asynchrone Aktionen verwendet wird, die einen Task<int>
Ausgangscode zurückgeben.
Sie müssen keinen abgeleiteten Typ erstellen, um eine Aktion zu definieren. Mit der System.CommandLine.Command.SetAction
Methode können Sie eine Aktion für einen Befehl festlegen. Die synchrone Aktion kann ein Delegat sein, der einen System.CommandLine.ParseResult
Parameter verwendet und einen int
Exitcode zurückgibt (oder nichts, und dann wird ein Standardmäßiger 0
Exitcode zurückgegeben). Bei der asynchronen Aktion kann es sich um einen Delegaten handeln, der einen Und-Parameter System.CommandLine.ParseResult
CancellationToken verwendet und einen Task<int>
(oder Task
zum Abrufen des zurückgegebenen Standardausgangscodes) zurückgibt.
rootCommand.SetAction(ParseResult parseResult =>
{
FileInfo parsedFile = parseResult.GetValue(fileOption);
ReadFile(parsedFile);
});
In der Vergangenheit wurde der CancellationToken
übergebene InvokeAsync
Handler über eine Methode von InvocationContext
:
rootCommand.SetHandler(async (InvocationContext context) =>
{
string? urlOptionValue = context.ParseResult.GetValueForOption(urlOption);
var token = context.GetCancellationToken();
returnCode = await DoRootCommand(urlOptionValue, token);
});
Die Meisten unserer Benutzer haben dieses Token nicht abgerufen und übergeben. Wir haben obligatorische Argumente für asynchrone Aktionen vorgenommen CancellationToken
, damit der Compiler eine Warnung erzeugt, wenn es nicht weiter übergeben wird (CA2016).
rootCommand.SetAction((ParseResult parseResult, CancellationToken token) =>
{
string? urlOptionValue = parseResult.GetValue(urlOption);
return DoRootCommandAsync(urlOptionValue, token);
});
Als Ergebnis dieser und anderer änderungen wurde die InvocationContext
Klasse ebenfalls entfernt. Die ParseResult
Datei wird nun direkt an die Aktion übergeben, sodass Sie direkt darauf zugreifen können.
So fassen Sie diese Änderungen zusammen:
- Die
ICommandHandler
Schnittstelle wurde entfernt.SynchronousCommandLineAction
undAsynchronousCommandLineAction
wurden eingeführt. - Die
Command.SetHandler
Methode wurde umbenannt inSetAction
. - Die
Command.Handler
Eigenschaft wurde umbenannt inCommand.Action
.Option
wurde mitOption.Action
. -
InvocationContext
wurde entfernt. DieParseResult
Aktion wird nun direkt an die Aktion übergeben.
Weitere Informationen zur Verwendung von Aktionen finden Sie unter Analysieren und Aufrufen von Befehlen in System.CommandLine.
Die Vorteile der vereinfachten API
Wir hoffen, dass die in 2.0.0-Beta5 vorgenommenen Änderungen die API konsistenter, zukunftssicherer und einfacher für vorhandene und neue Benutzer verwenden werden.
Neue Benutzer müssen weniger Konzepte und Typen lernen, da die Anzahl der öffentlichen Schnittstellen von 11 auf 0 gesunken ist, und öffentliche Klassen (und Strukturen) von 56 auf 38 zurückgegangen sind. Die Anzahl der öffentlichen Methoden wurde von 378 bis 235 verworfen, und öffentliche Eigenschaften von 118 bis 99.
Die Anzahl der Assemblys, auf System.CommandLine die verwiesen wird, wird von 11 auf 6 reduziert:
System.Collections
- System.Collections.Concurrent
- System.ComponentModel
System.Console
- System.Diagnostics.Process
System.Linq
System.Memory
- System.Net.Primitives
System.Runtime
- System.Runtime.Serialization.Formatters
+ System.Runtime.InteropServices
- System.Threading
Es erlaubte uns, die Größe der Bibliothek um 32% und die Größe der folgenden NativeAOT-App um 20%zu reduzieren:
Option<bool> boolOption = new Option<bool>(new[] { "--bool", "-b" }, "Bool option");
Option<string> stringOption = new Option<string>(new[] { "--string", "-s" }, "String option");
RootCommand command = new RootCommand
{
boolOption,
stringOption
};
command.SetHandler<bool, string>(Run, boolOption, stringOption);
return new CommandLineBuilder(command).UseDefaults().Build().Invoke(args);
static void Run(bool boolean, string text)
{
Console.WriteLine($"Bool option: {text}");
Console.WriteLine($"String option: {boolean}");
}
Option<bool> boolOption = new Option<bool>("--bool", "-b") { Description = "Bool option" };
Option<string> stringOption = new Option<string>("--string", "-s") { Description = "String option" };
RootCommand command = new ()
{
boolOption,
stringOption,
};
command.SetAction(parseResult => Run(parseResult.GetValue(boolOption), parseResult.GetValue(stringOption)));
return new CommandLineConfiguration(command).Invoke(args);
static void Run(bool boolean, string text)
{
Console.WriteLine($"Bool option: {text}");
Console.WriteLine($"String option: {boolean}");
}
Die Einfachheit hat auch die Leistung der Bibliothek verbessert (es ist ein Nebeneffekt der Arbeit, nicht das Hauptziel der Bibliothek). Die Benchmarks zeigen, dass die Analyse und Das Aufrufen von Befehlen jetzt schneller als in 2.0.0-Beta4 ist, insbesondere für große Befehle mit vielen Optionen und Argumenten. Die Leistungsverbesserungen sind sowohl in synchronen als auch in asynchronen Szenarien sichtbar.
Für die einfachste App, die zuvor vorgestellt wurde, wurden die folgenden Ergebnisse erzielt:
BenchmarkDotNet v0.15.0, Windows 11 (10.0.26100.4061/24H2/2024Update/HudsonValley)
AMD Ryzen Threadripper PRO 3945WX 12-Cores 3.99GHz, 1 CPU, 24 logical and 12 physical cores
.NET SDK 9.0.300
[Host] : .NET 9.0.5 (9.0.525.21509), X64 RyuJIT AVX2
Job-JJVAFK : .NET 9.0.5 (9.0.525.21509), X64 RyuJIT AVX2
EvaluateOverhead=False OutlierMode=DontRemove InvocationCount=1
IterationCount=100 UnrollFactor=1 WarmupCount=3
| Method | Args | Mean | StdDev | Ratio |
|------------------------ |--------------- |----------:|---------:|------:|
| Empty | --bool -s test | 63.58 ms | 0.825 ms | 0.83 |
| EmptyAOT | --bool -s test | 14.39 ms | 0.507 ms | 0.19 |
| SystemCommandLineBeta4 | --bool -s test | 85.80 ms | 1.007 ms | 1.12 |
| SystemCommandLineNow | --bool -s test | 76.74 ms | 1.099 ms | 1.00 |
| SystemCommandLineNowR2R | --bool -s test | 69.35 ms | 1.127 ms | 0.90 |
| SystemCommandLineNowAOT | --bool -s test | 17.35 ms | 0.487 ms | 0.23 |
Wie Sie sehen können, hat sich die Startzeit (die Benchmarks melden die Zum Ausführen einer ausführbaren Datei erforderliche Zeit) um 12% gegenüber 2.0.0-Beta4 verbessert. Wenn wir die App mit NativeAOT kompilieren, ist sie nur 3 ms langsamer als eine NativeAOT-App, die die Argumente überhaupt nicht analysiert (EmptyAOT in der obigen Tabelle). Wenn wir auch den Aufwand einer leeren App (63,58 ms) ausschließen, beträgt die Analyse 40% schneller als in 2.0.0-Beta4 (22,22 ms vs 13,66 ms).