Issue by fleed
_Friday Mar 31, 2017 at 04:24 GMT_
_Originally opened as https://github.com/gsscoder/commandline/issues/434_
Is there any existing way to define commands, intended as classes to execute specific options? IF not, any plan to add support? I would expect something like this, removing lot of the ceremony required to configure the option and run the related logic:
Example:
class CommitCommand : Command<CommitOptions>
{
public int Execute(CommitOptions options)
{
// execute
return 0;
}
// alternative
public int Execute()
{
// access options as property in AsyncCommand base
var file = this.Options.File;
// execute
return 0;
}
}
class UploadCommand : AsyncCommand<UploadOptions>
{
public async Task<int> ExecuteAsync(CommitOptions options)
{
// execute
return 0;
}
// alternative
public async Task<int> ExecuteAsync()
{
// access options as property in AsyncCommand base
var file = this.Options.File;
// execute
return 0;
}
}
// Program.cs
var parser = new CommandParser();
var parserResult = parser.Parse(args);
var result = parserResult.ExecuteCommand();
In general I'd like the possibility to discover options and commands through reflection, something similar to ManyConsole.
Comment by nemec
_Monday Apr 03, 2017 at 18:07 GMT_
There's no autodetection, but do verbs not do what you're asking?
Parser.Default.ParseArguments<Add_Verb, Commit_Verb, Clone_Verb>(
new[] { "clone", "https://value.org/user/file.git" })
.WithParsed<Add_Verb>(opts => expected = "wrong1")
.WithParsed<Commit_Verb>(opts => expected = "wrong2")
.WithParsed<Clone_Verb>(opts => expected = opts.Urls.First());
@ericnewton76 sure, but no support for async :(
With async main support in C# 7.1, that's a very important feature.
I implemented this like this:
in main (using MEF for discovering):
var handlers = container.GetExportedValues<ICommand>();
var returnCode = Parser.Default.ParseArguments(args, handlers.Select(x => x.OptionType).ToArray())
.MapResult<IOptions, int>(
x =>
{
var handler = handlers.First(h => h.OptionType == x.GetType());
// voodoo because I can't cast to Command<IOptions>
return (int)handler.GetType().GetMethod("Run").Invoke(handler, new object[] { x });
},
_ => 1
);
Base classes and interfaces:
public interface IOptions
{
}
public interface ICommand
{
Type OptionType { get; }
}
public abstract class Command<T> : ICommand where T : IOptions
{
public abstract int Run(T options);
public Type OptionType => typeof(T);
}
and a command would look like this:
[Export(typeof(ICommand))]
public class Search : Command<SearchOptions>
{
public override int Run(SearchOptions opts)
{
...
}
}
you can easily change this to make these commands async.
You probably meant to direct that at nemec, these issues were imported from gsscoder/commandline
Please forward async comments onto an async specific issue please, otherwise this conversation gets lost in here.
this reply was directed to @fleed .
Most helpful comment
@ericnewton76 sure, but no support for
async:(With async main support in C# 7.1, that's a very important feature.