Uwaga
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Ważne
System.CommandLine
jest obecnie dostępna w wersji zapoznawczej, a ta dokumentacja dotyczy wersji 2.0 beta 5.
Niektóre informacje odnoszą się do produktu w wersji wstępnej, który może zostać znacząco zmodyfikowany przed jego wydaniem. Firma Microsoft nie udziela żadnych gwarancji, wyraźnych ani domniemanych, w odniesieniu do podanych tutaj informacji.
Głównym celem wydania wersji 2.0.0-beta5 było ulepszenie interfejsów API i podjęcie kroku w kierunku wydania stabilnej wersji programu System.CommandLine. Interfejsy API zostały uproszczone, a także bardziej spójne i zgodne z wytycznymi projektowania Frameworku. W tym artykule opisano zmiany powodujące niezgodność wprowadzone w wersji 2.0.0-beta5 oraz ich przyczyny.
Zmienianie nazw
W wersji 2.0.0-beta4 nie wszystkie typy i elementy były zgodne z wytycznymi dotyczącymi nazewnictwa. Niektóre z nich nie były zgodne z konwencjami nazewnictwa, takimi jak używanie prefiksu Is
dla właściwości typu Boolean. W wersji 2.0.0-beta5 zmieniono nazwy niektórych typów i członków. W poniższej tabeli przedstawiono stare i nowe nazwy:
Stara nazwa | Nowa nazwa |
---|---|
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 |
Aby umożliwić raportowanie wielu błędów dla tego samego symbolu, ErrorMessage
właściwość została przekonwertowana na metodę i zmieniono jej nazwę na AddError
.
Eksponowanie kolekcji modyfikowalnych
Wersja 2.0.0-beta4 miała wiele Add
metod, które były używane do dodawania elementów do kolekcji, takich jak argumenty, opcje, polecenia podrzędne, moduły sprawdzania poprawności i uzupełniania. Niektóre z tych kolekcji zostały ujawnione za pośrednictwem właściwości jako kolekcji tylko do odczytu. Z tego powodu nie można było usunąć elementów z tych kolekcji.
W wersji 2.0.0-beta5 zmieniliśmy API, aby udostępniać kolekcje modyfikowalne zamiast metod Add
i (czasami) kolekcji tylko do odczytu. Pozwala to nie tylko dodawać elementy lub wyliczać je, ale także je usuwać. W poniższej tabeli przedstawiono starą metodę i nowe nazwy właściwości:
Stara nazwa metody | Nowa właściwość |
---|---|
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 |
Metody RemoveAlias
i HasAlias
zostały również usunięte, ponieważ właściwość Aliases
jest teraz kolekcją modyfikowalną. Możesz użyć Remove
metody , aby usunąć alias z kolekcji.
Contains
Użyj metody , aby sprawdzić, czy istnieje alias.
Nazwy i aliasy
Przed wersją 2.0.0-beta5 nie było wyraźnego rozdzielenia nazwy i aliasów symbolu. Jeśli nie podano name
dla konstruktora Option<T>
, symbol zgłaszał swoją nazwę jako najdłuższy alias z prefiksami, takimi jak --
, -
lub /
, usuniętymi. To było dezorientujące.
Ponadto, aby uzyskać przeanalizowaną wartość, użytkownicy musieli przechowywać odwołanie do opcji lub argumentu, a następnie użyć go do pobrania wartości z ParseResult
.
Aby podwyższyć prostotę i jawność, nazwa symbolu jest teraz obowiązkowym parametrem dla każdego konstruktora symboli (w tym Argument<T>
). Oddzieliliśmy również koncepcję nazwy i aliasów; teraz aliasy są tylko aliasami i nie zawierają nazwy symbolu. Oczywiście są one opcjonalne. W rezultacie wprowadzono następujące zmiany:
-
name
jest teraz obowiązkowym argumentem dla każdego publicznego konstruktoraArgument<T>
,Option<T>
iCommand
. W przypadkuArgument<T>
nie jest używany do analizowania, ale w celu wygenerowania pomocy. W przypadku elementówOption<T>
iCommand
służy do identyfikowania symbolu podczas analizowania, a także w celu uzyskania pomocy i ukończenia. - Właściwość
Symbol.Name
nie jest jużvirtual
; jest teraz tylko do odczytu i zwraca nazwę podaną podczas tworzenia symbolu. W związku z tymSymbol.DefaultName
został usunięty iOption.Name
nie usuwa już prefiksu--
,-
,/
ani żadnego innego prefiksu z najdłuższego aliasu. - Właściwość
Aliases
ujawniona przezOption
iCommand
jest teraz kolekcją modyfikowalną. Ta kolekcja nie zawiera już nazwy symbolu. -
System.CommandLine.Parsing.IdentifierSymbol
został usunięty (był to typ podstawowy dla obuCommand
iOption
).
Posiadanie nazwy zawsze obecnej umożliwia uzyskanie przeanalizowanej wartości według nazwy:
RootCommand command = new("The description.")
{
new Option<int>("--number")
};
ParseResult parseResult = command.Parse(args);
int number = parseResult.GetValue<int>("--number");
Tworzenie opcji za pomocą aliasów
W przeszłości Option<T>
uwidocznił wiele konstruktorów, z których niektóre zaakceptowały nazwę. Ponieważ nazwa jest teraz obowiązkowa i oczekujemy, że aliasy będą często podawane dla Option<T>
, istnieje tylko jeden konstruktor. Akceptuje nazwę i tablicę params
aliasów.
Przed wersją 2.0.0-beta5, Option<T>
miał konstruktor, który przyjmował nazwę i opis. Z tego powodu drugi argument może być teraz traktowany jako alias, a nie opis. Jest to jedyna znana zmiana łamiąca zgodność w interfejsie API, która nie spowoduje błędu kompilatora.
Stary kod, który używał konstruktora z opisem, powinien zostać zaktualizowany, aby użyć nowego konstruktora, który przyjmuje nazwę i aliasy, a następnie ustawić Description
właściwość oddzielnie. Przykład:
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."
};
Wartości domyślne i analizowanie niestandardowe
W wersji 2.0.0-beta4 użytkownicy mogą ustawić wartości domyślne opcji i argumentów przy użyciu SetDefaultValue
metod . Metody te przyjmowały wartość object
, która była niezgodna z typem i mogła prowadzić do błędów czasu wykonywania, jeśli wartość nie była zgodna z opcją lub typem argumentu.
Option<int> option = new("--number");
option.SetDefaultValue("text"); // This is not type-safe, as the value is a string, not an int.
Ponadto niektóre konstruktory Option
i Argument
przyjmowały delegata do analizy i wartość logiczną wskazującą, czy delegat był niestandardowym analizatorem, czy domyślnym dostawcą wartości. To było mylące.
Option<T>
i Argument<T>
klasy mają teraz właściwość DefaultValueFactory
, która może służyć do ustawiania delegata, którego można wywołać, aby uzyskać wartość domyślną dla opcji lub argumentu. Ten delegat jest wywoływany, gdy opcja lub argument nie zostanie znaleziony w przeanalizowanych danych wejściowych wiersza polecenia.
Option<int> number = new("--number")
{
DefaultValueFactory = _ => 42
};
Argument<T>
i Option<T>
także mają właściwość CustomParser
, która może służyć do ustawienia niestandardowego parsera dla symbolu:
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;
}
};
CustomParser
Ponadto akceptuje delegata typu Func<ParseResult, T>
, a nie poprzedniego ParseArgument
delegata. Ten i kilka innych delegatów niestandardowych zostały usunięte, aby uprościć interfejs API i zmniejszyć liczbę typów uwidocznionych przez interfejs API, co skraca czas uruchamiania spędzony podczas kompilacji JIT.
Aby uzyskać więcej przykładów używania poleceń DefaultValueFactory
i CustomParser
, zobacz Jak dostosować analizowanie i walidację w programie System.CommandLine.
Rozdzielenie analizy składniowej i wywołania
W wersji 2.0.0-beta4 można było oddzielić analizowanie i wywoływanie poleceń, ale nie było jasne, jak to zrobić.
Command
nie udostępnił metody Parse
, ale CommandExtensions
dostarczył metody rozszerzenia Parse
, Invoke
i InvokeAsync
dla elementu Command
. Było to mylące, ponieważ nie było jasne, której metody użyć i kiedy. Wprowadzono następujące zmiany w celu uproszczenia interfejsu API:
-
Command
teraz uwidacznia metodęParse
zwracającąParseResult
obiekt. Ta metoda służy do analizowania danych wejściowych wiersza polecenia i zwracania wyniku operacji analizy. Co więcej, jasno widać, że polecenie nie jest wywoływane, ale tylko analizowane i tylko w sposób synchroniczny. -
ParseResult
teraz uwidacznia metodyInvoke
iInvokeAsync
, które mogą służyć do wywoływania polecenia. Dzięki temu polecenie jest wywoływane po przeanalizowaniu i umożliwia wywołanie zarówno synchroniczne, jak i asynchroniczne. - Klasa została usunięta
CommandExtensions
, ponieważ nie jest już potrzebna.
Konfiguracja
Przed wersją 2.0.0.0-beta5 można było dostosować analizowanie, ale tylko przy użyciu niektórych metod publicznych Parse
. Istniała Parser
klasa, która uwidoczniła dwa publiczne konstruktory: jeden akceptujący element Command
i drugi akceptujący element CommandLineConfiguration
.
CommandLineConfiguration
był niezmienny i aby go utworzyć, trzeba było użyć wzorca konstruktora uwidocznionego przez klasę CommandLineBuilder
. Wprowadzono następujące zmiany w celu uproszczenia interfejsu API:
-
CommandLineConfiguration
został uczyniony modyfikowalnym, aCommandLineBuilder
został usunięty. Tworzenie konfiguracji jest teraz tak proste, jak utworzenie wystąpieniaCommandLineConfiguration
i ustawienie właściwości, które chcesz dostosować. Ponadto utworzenie nowego wystąpienia konfiguracji jest odpowiednikiem wywołania metodyCommandLineBuilder
dlaUseDefaults
. - Każda
Parse
metoda akceptuje teraz opcjonalnyCommandLineConfiguration
parametr, który może służyć do dostosowywania analizy. Jeśli nie zostanie podana, zostanie użyta konfiguracja domyślna. -
Parser
zmieniono nazwę naCommandLineParser
w celu odróżnienia od innych typów analizatorów, aby uniknąć konfliktów nazw. Ponieważ jest bezstanowa, jest to teraz klasa statyczna z tylko metodami statycznymi. Udostępnia dwie metody analizy: jedną akceptującąParse
, a drugą akceptującąIReadOnlyList<string> args
. Ten ostatni używaCommandLineParser.SplitCommandLine
(również publicznej) do podzielenia danych wejściowych wiersza polecenia na tokeny przed ich przeanalizowaniem.
CommandLineBuilderExtensions
został również usunięty. Poniżej przedstawiono sposób mapowania jej metod na nowe interfejsy API:
CancelOnProcessTermination
jest teraz właściwościąCommandLineConfiguration
o nazwie ProcessTerminationTimeout. Jest ona domyślnie włączona z limitem czasu 2s. Ustaw ją na wartośćnull
, aby ją wyłączyć.EnableDirectives
, ,UseEnvironmentVariableDirective
UseParseDirective
iUseSuggestDirective
zostały usunięte. Wprowadzono nowy typ dyrektywy, a RootCommand teraz ujawnia właściwośćSystem.CommandLine.RootCommand.Directives
. Za pomocą tej kolekcji można dodawać, usuwać i iterować dyrektywy. Sugerowana dyrektywa jest domyślnie dołączana; Można również użyć innych dyrektyw, takich jak DiagramDirective lubEnvironmentVariablesDirective
.EnableLegacyDoubleDashBehavior
został usunięty. Wszystkie niedopasowane tokeny są teraz udostępniane przez właściwość ParseResult.UnmatchedTokens .EnablePosixBundling
został usunięty. Tworzenie pakietów jest teraz domyślnie włączone, można ją wyłączyć, ustawiając właściwość CommandLineConfiguration.EnableBundling nafalse
.RegisterWithDotnetSuggest
został usunięty, ponieważ wykonał kosztowną operację, zwykle podczas uruchamiania aplikacji. Teraz musisz zarejestrować poleceniadotnet suggest
ręcznie.UseExceptionHandler
został usunięty. Domyślna procedura obsługi wyjątków jest teraz domyślnie włączona, można ją wyłączyć, ustawiając właściwość CommandLineConfiguration.EnableDefaultExceptionHandler nafalse
wartość . Jest to przydatne, gdy chcesz obsługiwać wyjątki w niestandardowy sposób, po prostu opakowując metodyInvoke
lubInvokeAsync
w blok try-catch.UseHelp
iUseVersion
zostały usunięte. Pomoc i wersja są teraz udostępniane przez typy publiczne HelpOption i VersionOption . Są one domyślnie uwzględniane w opcjach zdefiniowanych przez RootCommand.UseHelpBuilder
został usunięty. Aby uzyskać więcej informacji na temat dostosowywania danych wyjściowych pomocy, zobacz Jak dostosować pomoc w programie System.CommandLine.AddMiddleware
został usunięty. Spowolniło to uruchamianie aplikacji, a funkcje można zrealizować bez tego.UseParseErrorReporting
iUseTypoCorrections
zostały usunięte. Błędy analizy są teraz domyślnie zgłaszane podczas wywoływaniaParseResult
. Można ją skonfigurować, korzystając z właściwości udostępnionej przezParseErrorAction
wParseResult.Action
.ParseResult result = rootCommand.Parse("myArgs", config); if (result.Action is ParseErrorAction parseError) { parseError.ShowTypoCorrections = true; parseError.ShowHelp = false; }
UseLocalizationResources
iLocalizationResources
zostały usunięte. Ta funkcja była używana głównie przez konsolędotnet
do dodania brakujących tłumaczeń doSystem.CommandLine
. Wszystkie te tłumaczenia zostały przeniesione bezpośrednio do System.CommandLine, więc ta funkcja nie jest już potrzebna. Jeśli brakuje obsługi twojego języka, zgłoś problem.UseTokenReplacer
został usunięty. Pliki odpowiedzi są domyślnie włączone, ale można je wyłączyć, ustawiającSystem.CommandLine.CommandLineConfiguration.ResponseFileTokenReplacer
właściwość nanull
. Możesz również udostępnić niestandardową implementację, aby dostosować sposób przetwarzania plików odpowiedzi.
Ostatnia, ale nie mniej ważna, usunięto IConsole
oraz wszystkie powiązane interfejsy (IStandardOut
, IStandardError
, IStandardIn
).
System.CommandLine.CommandLineConfiguration
Uwidacznia dwie TextWriter
właściwości: Output
i Error
. Można je ustawić na dowolne TextWriter
wystąpienie, na przykład StringWriter
, które można wykorzystać do przechwytywania wyników na potrzeby testów. Naszą motywacją było uwidocznienie mniejszej liczby typów i ponowne użycie istniejących abstrakcji.
Wywołanie
W wersji 2.0.0-beta4 interfejs ICommandHandler
uwidocznił metody Invoke
i InvokeAsync
, które zostały użyte do wywołania przeanalizowanego polecenia. Ułatwiło to połączenie synchronicznego i asynchronicznego kodu, na przykład przez zdefiniowanie synchronicznej procedury obsługi dla polecenia, a następnie wywołanie go asynchronicznie (co może prowadzić do zakleszczenia). Ponadto można było zdefiniować program obsługi tylko dla polecenia, ale nie dla opcji (takiej jak pomoc, która wyświetla pomoc) lub dyrektywy.
Nowa abstrakcyjna klasa System.CommandLine.CommandLineAction
bazowa i dwie klasy pochodne: System.CommandLine.SynchronousCommandLineAction
i System.CommandLine.AsynchronousCommandLineAction
zostały wprowadzone. Pierwszy jest używany do synchronicznych akcji, które zwracają int
kod zakończenia, podczas gdy ten ostatni jest używany do asynchronicznych akcji, które zwracają Task<int>
kod zakończenia.
Nie musisz tworzyć typu pochodnego, aby zdefiniować akcję. Możesz użyć System.CommandLine.Command.SetAction
metody , aby ustawić akcję dla polecenia. Akcja synchroniczna może być delegatem System.CommandLine.ParseResult
przyjmującym parametr i zwracającym kod zakończenia int
(lub nic, wtedy zwracany jest domyślny kod zakończenia 0
). Akcja asynchroniczna może być delegatem, który przyjmuje parametry System.CommandLine.ParseResult
i CancellationToken, i zwraca wartość typu Task<int>
(lub Task
, aby uzyskać domyślny kod zakończenia).
rootCommand.SetAction(ParseResult parseResult =>
{
FileInfo parsedFile = parseResult.GetValue(fileOption);
ReadFile(parsedFile);
});
W przeszłości element CancellationToken
przekazany do InvokeAsync
został dostępny dla procedury obsługi poprzez metodę InvocationContext
.
rootCommand.SetHandler(async (InvocationContext context) =>
{
string? urlOptionValue = context.ParseResult.GetValueForOption(urlOption);
var token = context.GetCancellationToken();
returnCode = await DoRootCommand(urlOptionValue, token);
});
Większość naszych użytkowników nie uzyskała tego tokenu i nie przekazywała go dalej. Wprowadziliśmy CancellationToken
obowiązkowy argument dla akcji asynchronicznych, aby kompilator wygenerował ostrzeżenie, gdy nie zostanie przekazane dalej (CA2016).
rootCommand.SetAction((ParseResult parseResult, CancellationToken token) =>
{
string? urlOptionValue = parseResult.GetValue(urlOption);
return DoRootCommandAsync(urlOptionValue, token);
});
W wyniku tych i innych zmian, które zostały wymienione, klasa została również usunięta InvocationContext
. Element ParseResult
jest teraz przekazywany bezpośrednio do akcji, dzięki czemu można uzyskać dostęp do analizowanych wartości i opcji bezpośrednio z niej.
Aby podsumować te zmiany:
- Interfejs
ICommandHandler
został usunięty.SynchronousCommandLineAction
iAsynchronousCommandLineAction
zostały wprowadzone. - Nazwa
Command.SetHandler
metody została zmieniona naSetAction
. - Nazwa
Command.Handler
właściwości została zmieniona naCommand.Action
.Option
został rozszerzony oOption.Action
. -
InvocationContext
został usunięty. ElementParseResult
jest teraz przekazywany bezpośrednio do akcji.
Aby uzyskać więcej informacji na temat używania akcji, zobacz Jak analizować i wywoływać polecenia w programie System.CommandLine.
Zalety uproszczonego interfejsu API
Mamy nadzieję, że zmiany wprowadzone w wersji 2.0.0-beta5 sprawią, że interfejs API będzie bardziej spójny, niezawodny i łatwiejszy w użyciu dla istniejących i nowych użytkowników.
Nowi użytkownicy muszą nauczyć się mniej pojęć i typów, ponieważ liczba interfejsów publicznych spadła z 11 do 0, a klasy publiczne (i struktury) spadły z 56 do 38. Liczba metod publicznych spadła z 378 do 235, a właściwości publiczne z 118 do 99.
Liczba zestawów, System.CommandLine do których się odwołuje, jest ograniczona z 11 do 6:
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
Pozwoliło nam to zmniejszyć rozmiar biblioteki o 32% i rozmiar następującej aplikacji NativeAOT o 20%:
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}");
}
Prostota poprawiła również wydajność biblioteki (jest to efekt uboczny pracy, a nie główny cel). Testy porównawcze pokazują, że analizowanie i wywoływanie poleceń jest teraz szybsze niż w wersji 2.0.0-beta4, zwłaszcza w przypadku dużych poleceń z wieloma opcjami i argumentami. Ulepszenia wydajności są widoczne zarówno w scenariuszach synchronicznych, jak i asynchronicznych.
W przypadku najprostszej aplikacji przedstawionej wcześniej uzyskaliśmy następujące wyniki:
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 |
Jak widać, czas uruchamiania (testy porównawcze zgłaszają czas wymagany do uruchomienia danego pliku wykonywalnego) poprawił się o 12% w porównaniu z 2.0.0.0-beta4. Jeśli skompilujemy aplikację z funkcją NativeAOT, jest to tylko 3 ms wolniejsze niż aplikacja NativeAOT, która w ogóle nie analizuje args (EmptyAOT w powyższej tabeli). Ponadto, gdy wykluczamy obciążenie pustej aplikacji (63,58 ms), analizowanie jest 40% szybsze niż w wersji 2.0.0-beta4 (22.22 ms vs 13.66 ms).