mirror of
https://github.com/Tyrrrz/CliFx.git
synced 2025-10-25 15:19:17 +00:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d1b5107c2c | ||
|
|
03873d63cd | ||
|
|
89aba39964 | ||
|
|
ab57a103d1 | ||
|
|
d0b2ebc061 |
@@ -8,7 +8,7 @@ namespace CliFx.Benchmarks
|
|||||||
[RankColumn]
|
[RankColumn]
|
||||||
public class Benchmark
|
public class Benchmark
|
||||||
{
|
{
|
||||||
private static readonly string[] Arguments = { "--str", "hello world", "-i", "13", "-b" };
|
private static readonly string[] Arguments = {"--str", "hello world", "-i", "13", "-b"};
|
||||||
|
|
||||||
[Benchmark(Description = "CliFx", Baseline = true)]
|
[Benchmark(Description = "CliFx", Baseline = true)]
|
||||||
public Task<int> ExecuteWithCliFx() => new CliApplicationBuilder().AddCommand(typeof(CliFxCommand)).Build().RunAsync(Arguments);
|
public Task<int> ExecuteWithCliFx() => new CliApplicationBuilder().AddCommand(typeof(CliFxCommand)).Build().RunAsync(Arguments);
|
||||||
@@ -19,16 +19,17 @@ namespace CliFx.Benchmarks
|
|||||||
[Benchmark(Description = "McMaster.Extensions.CommandLineUtils")]
|
[Benchmark(Description = "McMaster.Extensions.CommandLineUtils")]
|
||||||
public int ExecuteWithMcMaster() => McMaster.Extensions.CommandLineUtils.CommandLineApplication.Execute<McMasterCommand>(Arguments);
|
public int ExecuteWithMcMaster() => McMaster.Extensions.CommandLineUtils.CommandLineApplication.Execute<McMasterCommand>(Arguments);
|
||||||
|
|
||||||
// Skipped because this benchmark freezes after a couple of iterations
|
[Benchmark(Description = "CommandLineParser")]
|
||||||
// Probably wasn't designed to run multiple times in single process execution
|
|
||||||
//[Benchmark(Description = "CommandLineParser")]
|
|
||||||
public void ExecuteWithCommandLineParser()
|
public void ExecuteWithCommandLineParser()
|
||||||
{
|
{
|
||||||
var parsed = CommandLine.Parser.Default.ParseArguments(Arguments, typeof(CommandLineParserCommand));
|
var parsed = new CommandLine.Parser().ParseArguments(Arguments, typeof(CommandLineParserCommand));
|
||||||
CommandLine.ParserResultExtensions.WithParsed<CommandLineParserCommand>(parsed, c => c.Execute());
|
CommandLine.ParserResultExtensions.WithParsed<CommandLineParserCommand>(parsed, c => c.Execute());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Benchmark(Description = "PowerArgs")]
|
[Benchmark(Description = "PowerArgs")]
|
||||||
public void ExecuteWithPowerArgs() => PowerArgs.Args.InvokeMain<PowerArgsCommand>(Arguments);
|
public void ExecuteWithPowerArgs() => PowerArgs.Args.InvokeMain<PowerArgsCommand>(Arguments);
|
||||||
|
|
||||||
|
[Benchmark(Description = "Clipr")]
|
||||||
|
public void ExecuteWithClipr() => clipr.CliParser.Parse<CliprCommand>(Arguments).Execute();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="BenchmarkDotNet" Version="0.11.5" />
|
<PackageReference Include="BenchmarkDotNet" Version="0.11.5" />
|
||||||
|
<PackageReference Include="clipr" Version="1.6.1" />
|
||||||
<PackageReference Include="CommandLineParser" Version="2.6.0" />
|
<PackageReference Include="CommandLineParser" Version="2.6.0" />
|
||||||
<PackageReference Include="McMaster.Extensions.CommandLineUtils" Version="2.3.4" />
|
<PackageReference Include="McMaster.Extensions.CommandLineUtils" Version="2.3.4" />
|
||||||
<PackageReference Include="PowerArgs" Version="3.6.0" />
|
<PackageReference Include="PowerArgs" Version="3.6.0" />
|
||||||
|
|||||||
20
CliFx.Benchmarks/Commands/CliprCommand.cs
Normal file
20
CliFx.Benchmarks/Commands/CliprCommand.cs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
using clipr;
|
||||||
|
|
||||||
|
namespace CliFx.Benchmarks.Commands
|
||||||
|
{
|
||||||
|
public class CliprCommand
|
||||||
|
{
|
||||||
|
[NamedArgument('s', "str")]
|
||||||
|
public string StrOption { get; set; }
|
||||||
|
|
||||||
|
[NamedArgument('i', "int")]
|
||||||
|
public int IntOption { get; set; }
|
||||||
|
|
||||||
|
[NamedArgument('b', "bool", Constraint = NumArgsConstraint.Optional, Const = true)]
|
||||||
|
public bool BoolOption { get; set; }
|
||||||
|
|
||||||
|
public void Execute()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -31,6 +31,7 @@ namespace CliFx.Tests
|
|||||||
.UseDescription("test")
|
.UseDescription("test")
|
||||||
.UseConsole(new VirtualConsole(TextWriter.Null))
|
.UseConsole(new VirtualConsole(TextWriter.Null))
|
||||||
.UseCommandFactory(schema => (ICommand) Activator.CreateInstance(schema.Type))
|
.UseCommandFactory(schema => (ICommand) Activator.CreateInstance(schema.Type))
|
||||||
|
.UseCommandOptionInputConverter(new CommandOptionInputConverter())
|
||||||
.Build();
|
.Build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -214,6 +214,12 @@ namespace CliFx.Tests.Services
|
|||||||
new[] {47, 69}
|
new[] {47, 69}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
yield return new TestCaseData(
|
||||||
|
new CommandOptionInput("option", new[] {"47"}),
|
||||||
|
typeof(int[]),
|
||||||
|
new[] {47}
|
||||||
|
);
|
||||||
|
|
||||||
yield return new TestCaseData(
|
yield return new TestCaseData(
|
||||||
new CommandOptionInput("option", new[] {"value1", "value3"}),
|
new CommandOptionInput("option", new[] {"value1", "value3"}),
|
||||||
typeof(TestEnum[]),
|
typeof(TestEnum[]),
|
||||||
@@ -270,6 +276,16 @@ namespace CliFx.Tests.Services
|
|||||||
typeof(int)
|
typeof(int)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
yield return new TestCaseData(
|
||||||
|
new CommandOptionInput("option", new[] {"123", "456"}),
|
||||||
|
typeof(int)
|
||||||
|
);
|
||||||
|
|
||||||
|
yield return new TestCaseData(
|
||||||
|
new CommandOptionInput("option"),
|
||||||
|
typeof(int)
|
||||||
|
);
|
||||||
|
|
||||||
yield return new TestCaseData(
|
yield return new TestCaseData(
|
||||||
new CommandOptionInput("option", "123"),
|
new CommandOptionInput("option", "123"),
|
||||||
typeof(TestNonStringParseable)
|
typeof(TestNonStringParseable)
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ namespace CliFx
|
|||||||
private string _description;
|
private string _description;
|
||||||
private IConsole _console;
|
private IConsole _console;
|
||||||
private ICommandFactory _commandFactory;
|
private ICommandFactory _commandFactory;
|
||||||
|
private ICommandOptionInputConverter _commandOptionInputConverter;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public ICliApplicationBuilder AddCommand(Type commandType)
|
public ICliApplicationBuilder AddCommand(Type commandType)
|
||||||
@@ -108,6 +109,13 @@ namespace CliFx
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public ICliApplicationBuilder UseCommandOptionInputConverter(ICommandOptionInputConverter converter)
|
||||||
|
{
|
||||||
|
_commandOptionInputConverter = converter.GuardNotNull(nameof(converter));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public ICliApplication Build()
|
public ICliApplication Build()
|
||||||
{
|
{
|
||||||
@@ -117,6 +125,7 @@ namespace CliFx
|
|||||||
_versionText = _versionText ?? GetDefaultVersionText() ?? "v1.0";
|
_versionText = _versionText ?? GetDefaultVersionText() ?? "v1.0";
|
||||||
_console = _console ?? new SystemConsole();
|
_console = _console ?? new SystemConsole();
|
||||||
_commandFactory = _commandFactory ?? new CommandFactory();
|
_commandFactory = _commandFactory ?? new CommandFactory();
|
||||||
|
_commandOptionInputConverter = _commandOptionInputConverter ?? new CommandOptionInputConverter();
|
||||||
|
|
||||||
// Project parameters to expected types
|
// Project parameters to expected types
|
||||||
var metadata = new ApplicationMetadata(_title, _executableName, _versionText, _description);
|
var metadata = new ApplicationMetadata(_title, _executableName, _versionText, _description);
|
||||||
@@ -124,7 +133,7 @@ namespace CliFx
|
|||||||
|
|
||||||
return new CliApplication(metadata, configuration,
|
return new CliApplication(metadata, configuration,
|
||||||
_console, new CommandInputParser(), new CommandSchemaResolver(),
|
_console, new CommandInputParser(), new CommandSchemaResolver(),
|
||||||
_commandFactory, new CommandInitializer(), new HelpTextRenderer());
|
_commandFactory, new CommandInitializer(_commandOptionInputConverter), new HelpTextRenderer());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>net45;netstandard2.0</TargetFrameworks>
|
<TargetFrameworks>net45;netstandard2.0</TargetFrameworks>
|
||||||
<LangVersion>latest</LangVersion>
|
<LangVersion>latest</LangVersion>
|
||||||
<Version>0.0.4</Version>
|
<Version>0.0.5</Version>
|
||||||
<Company>Tyrrrz</Company>
|
<Company>Tyrrrz</Company>
|
||||||
<Authors>$(Company)</Authors>
|
<Authors>$(Company)</Authors>
|
||||||
<Copyright>Copyright (C) Alexey Golub</Copyright>
|
<Copyright>Copyright (C) Alexey Golub</Copyright>
|
||||||
|
|||||||
@@ -59,6 +59,11 @@ namespace CliFx
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
ICliApplicationBuilder UseCommandFactory(ICommandFactory factory);
|
ICliApplicationBuilder UseCommandFactory(ICommandFactory factory);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Configures application to use specified implementation of <see cref="ICommandOptionInputConverter"/>.
|
||||||
|
/// </summary>
|
||||||
|
ICliApplicationBuilder UseCommandOptionInputConverter(ICommandOptionInputConverter converter);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates an instance of <see cref="ICliApplication"/> using configured parameters.
|
/// Creates an instance of <see cref="ICliApplication"/> using configured parameters.
|
||||||
/// Default values are used in place of parameters that were not specified.
|
/// Default values are used in place of parameters that were not specified.
|
||||||
|
|||||||
@@ -36,8 +36,13 @@ namespace CliFx.Internal
|
|||||||
|
|
||||||
public static bool Implements(this Type type, Type interfaceType) => type.GetInterfaces().Contains(interfaceType);
|
public static bool Implements(this Type type, Type interfaceType) => type.GetInterfaces().Contains(interfaceType);
|
||||||
|
|
||||||
|
public static Type GetNullableUnderlyingType(this Type type) => Nullable.GetUnderlyingType(type);
|
||||||
|
|
||||||
public static Type GetEnumerableUnderlyingType(this Type type)
|
public static Type GetEnumerableUnderlyingType(this Type type)
|
||||||
{
|
{
|
||||||
|
if (type.IsPrimitive)
|
||||||
|
return null;
|
||||||
|
|
||||||
if (type == typeof(IEnumerable))
|
if (type == typeof(IEnumerable))
|
||||||
return typeof(object);
|
return typeof(object);
|
||||||
|
|
||||||
|
|||||||
@@ -31,8 +31,13 @@ namespace CliFx.Services
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
private object ConvertValue(string value, Type targetType)
|
/// <summary>
|
||||||
|
/// Converts a single string value to specified target type.
|
||||||
|
/// </summary>
|
||||||
|
protected virtual object ConvertValue(string value, Type targetType)
|
||||||
{
|
{
|
||||||
|
targetType.GuardNotNull(nameof(targetType));
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// String or object
|
// String or object
|
||||||
@@ -108,7 +113,7 @@ namespace CliFx.Services
|
|||||||
return Enum.Parse(targetType, value, true);
|
return Enum.Parse(targetType, value, true);
|
||||||
|
|
||||||
// Nullable
|
// Nullable
|
||||||
var nullableUnderlyingType = Nullable.GetUnderlyingType(targetType);
|
var nullableUnderlyingType = targetType.GetNullableUnderlyingType();
|
||||||
if (nullableUnderlyingType != null)
|
if (nullableUnderlyingType != null)
|
||||||
return !value.IsNullOrWhiteSpace() ? ConvertValue(value, nullableUnderlyingType) : null;
|
return !value.IsNullOrWhiteSpace() ? ConvertValue(value, nullableUnderlyingType) : null;
|
||||||
|
|
||||||
@@ -126,48 +131,66 @@ namespace CliFx.Services
|
|||||||
var parseMethod = GetStaticParseMethod(targetType);
|
var parseMethod = GetStaticParseMethod(targetType);
|
||||||
if (parseMethod != null)
|
if (parseMethod != null)
|
||||||
return parseMethod.Invoke(null, new object[] {value});
|
return parseMethod.Invoke(null, new object[] {value});
|
||||||
|
|
||||||
throw new CliFxException($"Can't convert value [{value}] to type [{targetType}].");
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
// Wrap and rethrow exceptions that occur when trying to convert the value
|
||||||
throw new CliFxException($"Can't convert value [{value}] to type [{targetType}].", ex);
|
throw new CliFxException($"Can't convert value [{value}] to type [{targetType}].", ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Throw if we can't find a way to convert the value
|
||||||
|
throw new CliFxException($"Can't convert value [{value}] to type [{targetType}].");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public object ConvertOptionInput(CommandOptionInput optionInput, Type targetType)
|
public virtual object ConvertOptionInput(CommandOptionInput optionInput, Type targetType)
|
||||||
{
|
{
|
||||||
optionInput.GuardNotNull(nameof(optionInput));
|
optionInput.GuardNotNull(nameof(optionInput));
|
||||||
targetType.GuardNotNull(nameof(targetType));
|
targetType.GuardNotNull(nameof(targetType));
|
||||||
|
|
||||||
// Single value
|
// Get the underlying type of IEnumerable<T> if it's implemented by the target type.
|
||||||
if (optionInput.Values.Count <= 1)
|
// Ignore string type because it's IEnumerable<T> but we don't treat it as such.
|
||||||
|
var enumerableUnderlyingType = targetType != typeof(string) ? targetType.GetEnumerableUnderlyingType() : null;
|
||||||
|
|
||||||
|
// Convert to a non-enumerable type
|
||||||
|
if (enumerableUnderlyingType == null)
|
||||||
{
|
{
|
||||||
|
// Throw if provided with more than 1 value
|
||||||
|
if (optionInput.Values.Count > 1)
|
||||||
|
{
|
||||||
|
throw new CliFxException(
|
||||||
|
$"Can't convert a sequence of values [{optionInput.Values.JoinToString(", ")}] " +
|
||||||
|
$"to non-enumerable type [{targetType}].");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve a single value and convert
|
||||||
var value = optionInput.Values.SingleOrDefault();
|
var value = optionInput.Values.SingleOrDefault();
|
||||||
return ConvertValue(value, targetType);
|
return ConvertValue(value, targetType);
|
||||||
}
|
}
|
||||||
// Multiple values
|
// Convert to an enumerable type
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Determine underlying type of elements inside the target collection type
|
// Convert values to the underlying enumerable type and cast it to dynamic array
|
||||||
var underlyingType = targetType.GetEnumerableUnderlyingType() ?? typeof(object);
|
var convertedValues = optionInput.Values
|
||||||
|
.Select(v => ConvertValue(v, enumerableUnderlyingType))
|
||||||
|
.ToNonGenericArray(enumerableUnderlyingType);
|
||||||
|
|
||||||
// Convert values to that type
|
// Get the type of produced array
|
||||||
var convertedValues = optionInput.Values.Select(v => ConvertValue(v, underlyingType)).ToNonGenericArray(underlyingType);
|
|
||||||
var convertedValuesType = convertedValues.GetType();
|
var convertedValuesType = convertedValues.GetType();
|
||||||
|
|
||||||
// Assignable from array of values (e.g. T[], IReadOnlyList<T>, IEnumerable<T>)
|
// Try to assign the array (works for T[], IReadOnlyList<T>, IEnumerable<T>, etc)
|
||||||
if (targetType.IsAssignableFrom(convertedValuesType))
|
if (targetType.IsAssignableFrom(convertedValuesType))
|
||||||
return convertedValues;
|
return convertedValues;
|
||||||
|
|
||||||
// Has a constructor that accepts an array of values (e.g. HashSet<T>, List<T>)
|
// Try to inject the array into the constructor (works for HashSet<T>, List<T>, etc)
|
||||||
var arrayConstructor = targetType.GetConstructor(new[] {convertedValuesType});
|
var arrayConstructor = targetType.GetConstructor(new[] {convertedValuesType});
|
||||||
if (arrayConstructor != null)
|
if (arrayConstructor != null)
|
||||||
return arrayConstructor.Invoke(new object[] {convertedValues});
|
return arrayConstructor.Invoke(new object[] {convertedValues});
|
||||||
|
|
||||||
|
// Throw if we can't find a way to convert the values
|
||||||
throw new CliFxException(
|
throw new CliFxException(
|
||||||
$"Can't convert sequence of values [{optionInput.Values.JoinToString(", ")}] to type [{targetType}].");
|
$"Can't convert a sequence of values [{optionInput.Values.JoinToString(", ")}] " +
|
||||||
|
$"to type [{targetType}].");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
49
Readme.md
49
Readme.md
@@ -30,6 +30,10 @@ _CliFx is to command line interfaces what ASP.NET Core is to web applications._
|
|||||||
- Targets .NET Framework 4.5+ and .NET Standard 2.0+
|
- Targets .NET Framework 4.5+ and .NET Standard 2.0+
|
||||||
- No external dependencies
|
- No external dependencies
|
||||||
|
|
||||||
|
## Screenshots
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
## Argument syntax
|
## Argument syntax
|
||||||
|
|
||||||
This library employs a variation of the GNU command line argument syntax. Because CliFx uses a context-unaware parser, the syntax rules are generally more consistent and intuitive.
|
This library employs a variation of the GNU command line argument syntax. Because CliFx uses a context-unaware parser, the syntax rules are generally more consistent and intuitive.
|
||||||
@@ -123,6 +127,34 @@ When resolving options, CliFx can convert string values obtained from the comman
|
|||||||
|
|
||||||
If you want to define an option of your own type, the easiest way to do it is to make sure that your type is string-initializable, as explained above.
|
If you want to define an option of your own type, the easiest way to do it is to make sure that your type is string-initializable, as explained above.
|
||||||
|
|
||||||
|
It is also possible to configure the application to use your own converter, by calling `UseCommandOptionInputConverter` method on `CliApplicationBuilder`.
|
||||||
|
|
||||||
|
```c#
|
||||||
|
var app = new CliApplicationBuilder()
|
||||||
|
.AddCommandsFromThisAssembly()
|
||||||
|
.UseCommandOptionInputConverter(new MyConverter())
|
||||||
|
.Build();
|
||||||
|
```
|
||||||
|
|
||||||
|
The converter class must implement `ICommandOptionInputConverter` but you can also derive from `CommandOptionInputConverter` to extend the default behavior.
|
||||||
|
|
||||||
|
```c#
|
||||||
|
public class MyConverter : CommandOptionInputConverter
|
||||||
|
{
|
||||||
|
protected override object ConvertValue(string value, Type targetType)
|
||||||
|
{
|
||||||
|
// Custom conversion for MyType
|
||||||
|
if (targetType == typeof(MyType))
|
||||||
|
{
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default behavior for other types
|
||||||
|
return base.ConvertValue(value, targetType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### Reporting errors
|
### Reporting errors
|
||||||
|
|
||||||
You may have noticed that commands in CliFx don't return exit codes. This is by design as exit codes are considered a higher-level concern and thus handled by `CliApplication`, not by individual commands.
|
You may have noticed that commands in CliFx don't return exit codes. This is by design as exit codes are considered a higher-level concern and thus handled by `CliApplication`, not by individual commands.
|
||||||
@@ -388,13 +420,12 @@ var app = new CliApplicationBuilder()
|
|||||||
|
|
||||||
## Benchmarks
|
## Benchmarks
|
||||||
|
|
||||||
CliFx has the smallest performance overhead compared to other command line parsers and frameworks.
|
Here's how CliFx's execution overhead compares to that of other libraries.
|
||||||
Below you can see a table comparing execution times of a simple command across different libraries.
|
|
||||||
|
|
||||||
```ini
|
```ini
|
||||||
BenchmarkDotNet=v0.11.5, OS=Windows 10.0.14393.0 (1607/AnniversaryUpdate/Redstone1)
|
BenchmarkDotNet=v0.11.5, OS=Windows 10.0.14393.3144 (1607/AnniversaryUpdate/Redstone1)
|
||||||
Intel Core i5-4460 CPU 3.20GHz (Haswell), 1 CPU, 4 logical and 4 physical cores
|
Intel Core i5-4460 CPU 3.20GHz (Haswell), 1 CPU, 4 logical and 4 physical cores
|
||||||
Frequency=3125008 Hz, Resolution=319.9992 ns, Timer=TSC
|
Frequency=3125011 Hz, Resolution=319.9989 ns, Timer=TSC
|
||||||
.NET Core SDK=2.2.401
|
.NET Core SDK=2.2.401
|
||||||
[Host] : .NET Core 2.2.6 (CoreCLR 4.6.27817.03, CoreFX 4.6.27818.02), 64bit RyuJIT
|
[Host] : .NET Core 2.2.6 (CoreCLR 4.6.27817.03, CoreFX 4.6.27818.02), 64bit RyuJIT
|
||||||
Core : .NET Core 2.2.6 (CoreCLR 4.6.27817.03, CoreFX 4.6.27818.02), 64bit RyuJIT
|
Core : .NET Core 2.2.6 (CoreCLR 4.6.27817.03, CoreFX 4.6.27818.02), 64bit RyuJIT
|
||||||
@@ -404,10 +435,12 @@ Job=Core Runtime=Core
|
|||||||
|
|
||||||
| Method | Mean | Error | StdDev | Ratio | RatioSD | Rank |
|
| Method | Mean | Error | StdDev | Ratio | RatioSD | Rank |
|
||||||
|------------------------------------- |----------:|----------:|----------:|------:|--------:|-----:|
|
|------------------------------------- |----------:|----------:|----------:|------:|--------:|-----:|
|
||||||
| CliFx | 39.47 us | 0.7490 us | 0.9198 us | 1.00 | 0.00 | 1 |
|
| CliFx | 31.29 us | 0.6147 us | 0.7774 us | 1.00 | 0.00 | 2 |
|
||||||
| System.CommandLine | 153.98 us | 0.7112 us | 0.6652 us | 3.90 | 0.09 | 2 |
|
| System.CommandLine | 184.44 us | 3.4993 us | 4.0297 us | 5.90 | 0.21 | 4 |
|
||||||
| McMaster.Extensions.CommandLineUtils | 180.36 us | 3.5893 us | 6.7416 us | 4.59 | 0.16 | 3 |
|
| McMaster.Extensions.CommandLineUtils | 165.50 us | 1.4805 us | 1.3124 us | 5.33 | 0.13 | 3 |
|
||||||
| PowerArgs | 427.54 us | 6.9006 us | 6.4548 us | 10.82 | 0.26 | 4 |
|
| CommandLineParser | 26.65 us | 0.5530 us | 0.5679 us | 0.85 | 0.03 | 1 |
|
||||||
|
| PowerArgs | 405.44 us | 7.7133 us | 9.1821 us | 12.96 | 0.47 | 6 |
|
||||||
|
| Clipr | 220.82 us | 4.4567 us | 4.9536 us | 7.06 | 0.25 | 5 |
|
||||||
|
|
||||||
## Philosophy
|
## Philosophy
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user