0

I want to use PowerArgs for a console application I am writing. It offers some nice features I'd like to try. My root looks like this:

public static void Main(string[] args)
    {
        try
        {
            Args.InvokeAction<MyClass>(args);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
        Console.ReadKey();
    }

Pretty cool: PowerArgs creates an instance of MyClass, parses the given args and calls the corresponding action, defined by attributes as follows:

public class MyClass
{
    private readonly IConsole _console;
    private readonly IOtherDependency _dep;

    public Summoner(IConsole console, IOtherDependency dep)
    {
        _console = console;
        _dep = dep;
    }

    [ArgActionMethod]
    public void DoMyThing(
        [StickyArg][ArgRequired] string name,
        [StickyArg][ArgRequired] string street,
        [ArgRequired] string favoriteMeal)
    {
        var stuff = _dep.GetStuff(street, name);

        var properties = stuff.GetType().GetProperties();
        foreach (var property in properties)
        {
            _console.Write($"{property.Name}:{property.GetValue(summoner)}");
        }
    }
}

}

You might have already seen my problem. PowerArgs throws an exception since it cannot instantiate MyClass. It says that it needs an parameter-less constructor to do so. But I don't want to create a hard-coded console in my class or do something like _dep = new OtherDependency() in my method since I then would not be able to unit test. Is there any way to use dependency injection with a parameterless constructor?

Thanks in advance!

  • "If you need to support a different type or want to support custom syntax to populate a complex object then you can create a custom reviver." – Ewan Jun 28 '18 at 13:53
1

If there's a mismatch between the interface you want and the interface another system expects, consider using some kind of adapter or indirection. This does limit the usefulness of the framework you are using, but gives you more flexibility.

In this case, the target function could simply construct a DTO-style struct that just holds the parameters. Later, you can run the actual code. The usage would be something like:

var parsedArgs = Args.InvokeAction<ParsedArgs>(args);
runActualCode(dependencies, parsedArgs);

where

class ParsedArgs {
  public string Name { get; };
  public string Street { get; };
  public string FavoriteMeal { get; };

  [ArgActionMethod]
  public void DoMyThing(
    [StickyArg][ArgRequired] string name,
    [StickyArg][ArgRequired] string street,
    [ArgRequired] string favoriteMeal)
  {
    Name = name;
    Street = street;
    FavoriteMeal = favoriteMeal;
  }
}

In this particular case, the library in question already supports alternative ways to specify arguments in addition to this InvokeAction/ArgActionMethood approach. You might find them easier when constructing an object representing the parsed arguments.

If the library were developed for maximum flexibility, it would not make any assumptions about the action object lifecycle but allow you to pass in an already-constructed object, e.g.

Args.InvokeAction(new MyClass(dependencies), args);

Maybe such a method is already implemented in that library?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.