Freigeben über


System.CommandLine 2.0.0-beta5-Migrationshandbuch

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 AddErrorin .

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 von Argument<T>, Option<T>und Command. Im Fall von Argument<T>, wird es nicht für die Analyse verwendet, sondern um die Hilfe zu generieren. Im Fall Option<T> und Command, 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 mehr virtualvorhanden. Sie ist jetzt schreibgeschützt und gibt den Namen zurück, wie er beim Erstellen des Symbols angegeben wurde. Aus diesem Symbol.DefaultName Gründen wurde das Präfix oder -/ ein anderes Präfix aus dem längsten --Alias entfernt und Option.Name nicht mehr entfernt.
  • Die Aliases Eigenschaft, die von Option und Command 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 beide Command und Option).

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 CustomParserdie Ü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, Invokeund 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 eine Parse Methode zur Verfügung, die ein ParseResult 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 methoden Invoke als InvokeAsync 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 und CommandLineBuilder entfernt. Das Erstellen einer Konfiguration ist jetzt so einfach wie das Erstellen einer Instanz CommandLineConfiguration und das Festlegen der Eigenschaften, die Sie anpassen möchten. Darüber hinaus entspricht das Erstellen einer neuen Konfigurationsinstanz dem Aufrufen CommandLineBuilderUseDefaults der Methode.
  • Jede Parse Methode akzeptiert jetzt einen optionalen CommandLineConfiguration 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 zwei Parse Analysemethoden verfügbar: eine, die eine IReadOnlyList<string> args und eine andere akzeptiert.string args Letzteres verwendet CommandLineParser.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 dem CommandLineConfiguration Namen "ProcessTerminationTimeout". Sie ist standardmäßig mit einem 2s-Timeout aktiviert. Legen Sie sie fest, um null sie zu deaktivieren.

  • EnableDirectives, UseEnvironmentVariableDirective, UseParseDirectiveund UseSuggestDirective wurden entfernt. Ein neuer Direktiventyp wurde eingeführt, und der RootCommand macht System.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 oder EnvironmentVariablesDirective.

  • 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 auf falsefestlegen.

  • RegisterWithDotnetSuggest wurde entfernt, da sie einen kostspieligen Vorgang ausgeführt hat, in der Regel während des Anwendungsstarts. Jetzt müssen Sie Befehle dotnet suggestmanuell registrieren.

  • UseExceptionHandler wurde entfernt. Der Standardausnahmehandler ist jetzt standardmäßig aktiviert, Sie können ihn deaktivieren, indem Sie die CommandLineConfiguration.EnableDefaultExceptionHandler-Eigenschaft auf falsefestlegen. Dies ist nützlich, wenn Sie Ausnahmen auf benutzerdefinierte Weise behandeln möchten, indem Sie einfach die Invoke Oder InvokeAsync Methoden in einen Try-Catch-Block umschließen.

  • UseHelp und UseVersion 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 und UseTypoCorrections wurden entfernt. Die Analysefehler werden jetzt standardmäßig beim Aufrufen ParseResultgemeldet. Sie können sie mithilfe der ParseErrorAction verfügbar gemachten ParseResult.Action Eigenschaft konfigurieren.

    ParseResult result = rootCommand.Parse("myArgs", config);
    if (result.Action is ParseErrorAction parseError)
    {
        parseError.ShowTypoCorrections = true;
        parseError.ShowHelp = false;
    }
    
  • UseLocalizationResources und LocalizationResources wurden entfernt. Dieses Feature wurde hauptsächlich von der dotnet CLI verwendet, um fehlende Übersetzungen hinzuzufügen System.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 die System.CommandLine.CommandLineConfiguration.ResponseFileTokenReplacer Eigenschaft auf null. 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.CommandLineActionund 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.ParseResultCancellationToken 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 und AsynchronousCommandLineAction wurden eingeführt.
  • Die Command.SetHandler Methode wurde umbenannt in SetAction.
  • Die Command.Handler Eigenschaft wurde umbenannt in Command.Action. Option wurde mit Option.Action.
  • InvocationContext wurde entfernt. Die ParseResult 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).

Siehe auch