using System.CommandLine;
using System.CommandLine.Binding;
using System.CommandLine.Invocation;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
public static class Program
public static int Main(string[] args)
"-Message", DateTime.Now+" > Hello {0}!",
var command = new RootCommand();
command.ConfigureFromClass<Hello>(hello =>
Console.WriteLine(hello.Speak());
return command.Invoke(args);
[Description("Say Hello")]
[Description("Someone's name")]
public string Name { get; set; }
[Description("A simple message"), Required]
public string Message { get; set; }
return string.Format(Message, Name);
public static void ConfigureFromClass<T>(this Command command, Action<T> execute)
var commandType = typeof(T);
command.Description = commandType
.OfType<DescriptionAttribute>()
var props = commandType.GetProperties();
foreach (var prop in props)
var description = prop.GetAttribute<DescriptionAttribute>()?.Description;
var required = prop.GetAttribute<RequiredAttribute>() != null;
var option = new Option($"-{prop.Name}", description)
option.Argument = new Argument{ArgumentType = prop.PropertyType, };
command.AddOption(option);
command.Handler = CommandHandler.Create((InvocationContext context) =>
var modelBinder = new ModelBinder<T>();
modelBinder.UpdateInstance(cmd, context.BindingContext);
public static T GetAttribute<T>(this PropertyInfo prop)
return prop.GetCustomAttributes().OfType<T>().FirstOrDefault();