如何使用 System.CommandLine 绑定 NodaTime.Duration?
How to bind NodaTime.Duration using System.CommandLine?
是否可以使用 System.CommandLine
直接将命令行输入绑定到 NodaTime.Duration
(或 System.TimeSpan
)?也许通过在某处提供自定义转换器?
static void Main(string[] args)
{
var rootCommand = new RootCommand
{
new Option<Duration>("--my-duration"),
};
rootCommand.Handler = CommandHandler.Create(
(Duration myDuration) => { Console.WriteLine(myDuration); });
rootCommand.InvokeAsync(args);
}
我用 System.CommandLine
的工作不多,关于自定义解析的文档也不多,但我相信您想要的是 ParseArgument<T>
。幸运的是,在 NodaTime IPattern<T>
上编写扩展方法来创建其实例相当容易。
这里有一个未经充分测试的扩展方法:
using NodaTime.Text;
using System.CommandLine.Parsing;
namespace Demo
{
public static class PatternExtensions
{
public static ParseArgument<T> ToParseArgument<T>(this IPattern<T> pattern) =>
result => ParseResult<T>(pattern, result);
private static T ParseResult<T>(IPattern<T> pattern, ArgumentResult result)
{
// TODO: Check whether Tokens is actually what we want to use.
if (result.Tokens.Count != 1)
{
result.ErrorMessage = "Only a single token can be parsed";
return default;
}
var token = result.Tokens[0];
var nodaResult = pattern.Parse(token.Value);
if (nodaResult.Success)
{
return nodaResult.Value;
}
else
{
result.ErrorMessage = nodaResult.Exception.Message;
return default;
}
}
}
}
以及使用它的代码:
using NodaTime;
using NodaTime.Text;
using System;
using System.CommandLine;
using System.CommandLine.Invocation;
using Demo; // To make the extension method available
class Program
{
static void Main(string[] args)
{
var rootCommand = new RootCommand
{
new Option<Duration>(
"--my-duration",
DurationPattern.JsonRoundtrip.ToParseArgument()),
};
rootCommand.Handler = CommandHandler.Create(
(Duration myDuration) => Console.WriteLine(myDuration));
rootCommand.Invoke(args);
}
}
正在解析的模式 (DurationPattern.JsonRoundtrip
) 使用“小时数”作为最重要的部分,而默认格式(在本例中由 Console.WriteLine
使用)使用“天数” , 所以很容易看出它确实在解析:
$ dotnet run -- --my-duration=27:23:45
1:03:23:45
是否可以使用 System.CommandLine
直接将命令行输入绑定到 NodaTime.Duration
(或 System.TimeSpan
)?也许通过在某处提供自定义转换器?
static void Main(string[] args)
{
var rootCommand = new RootCommand
{
new Option<Duration>("--my-duration"),
};
rootCommand.Handler = CommandHandler.Create(
(Duration myDuration) => { Console.WriteLine(myDuration); });
rootCommand.InvokeAsync(args);
}
我用 System.CommandLine
的工作不多,关于自定义解析的文档也不多,但我相信您想要的是 ParseArgument<T>
。幸运的是,在 NodaTime IPattern<T>
上编写扩展方法来创建其实例相当容易。
这里有一个未经充分测试的扩展方法:
using NodaTime.Text;
using System.CommandLine.Parsing;
namespace Demo
{
public static class PatternExtensions
{
public static ParseArgument<T> ToParseArgument<T>(this IPattern<T> pattern) =>
result => ParseResult<T>(pattern, result);
private static T ParseResult<T>(IPattern<T> pattern, ArgumentResult result)
{
// TODO: Check whether Tokens is actually what we want to use.
if (result.Tokens.Count != 1)
{
result.ErrorMessage = "Only a single token can be parsed";
return default;
}
var token = result.Tokens[0];
var nodaResult = pattern.Parse(token.Value);
if (nodaResult.Success)
{
return nodaResult.Value;
}
else
{
result.ErrorMessage = nodaResult.Exception.Message;
return default;
}
}
}
}
以及使用它的代码:
using NodaTime;
using NodaTime.Text;
using System;
using System.CommandLine;
using System.CommandLine.Invocation;
using Demo; // To make the extension method available
class Program
{
static void Main(string[] args)
{
var rootCommand = new RootCommand
{
new Option<Duration>(
"--my-duration",
DurationPattern.JsonRoundtrip.ToParseArgument()),
};
rootCommand.Handler = CommandHandler.Create(
(Duration myDuration) => Console.WriteLine(myDuration));
rootCommand.Invoke(args);
}
}
正在解析的模式 (DurationPattern.JsonRoundtrip
) 使用“小时数”作为最重要的部分,而默认格式(在本例中由 Console.WriteLine
使用)使用“天数” , 所以很容易看出它确实在解析:
$ dotnet run -- --my-duration=27:23:45
1:03:23:45