Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In C#, is it possible to call a method (which has default parameters) with "as many parameters as I have"?

Tags:

c#

.net

c#-4.0

That is, I have a method such as the following:

public static int CreateTaskGroup(string TaskGroupName, 
    string Market = "en-us", string Project = "MyProject", 
    string Team = "DefaultTeam", string SatelliteID="abc");

I would like to call this method from the command line, by reading the standard array of command line arguments. The obvious way to do it would be as follows:

 if (args.Length == 1) CreateTaskGroup(args[0]);
 if (args.Length == 2) CreateTaskGroup(args[0], args[1]);
 if (args.Length == 3) CreateTaskGroup(args[0], args[1], args[2]);

Is it possible to do this in a more concise way?

like image 602
merlin2011 Avatar asked Jun 21 '12 23:06

merlin2011


1 Answers

Here's one alternative, with the downside that you have to redeclare the default value constants:

CreateTaskGroup(
    args[0],
    args.ElementAtOrDefault(1) ?? "en-us",
    args.ElementAtOrDefault(2) ?? "MyProject",
    args.ElementAtOrDefault(3) ?? "DefaultTeam",
    args.ElementAtOrDefault(4) ?? "abc");

You can reduce this issue by declaring the strings as consts, e.g.:

public const string MarketDefault = "en-us";
public static int CreateTaskGroup(string TaskGroupName,
    string Market = MarketDefault, ...)

static void Main(string[] args)
{
    CreateTaskGroup(
        args[0],
        args.ElementAtOrDefault(1) ?? MarketDefault,
        ...);
}

But then it's not guaranteed by the compiler, nor overtly obvious, that MarketDefault is, in fact, still (code can be refactored in the future) the default for Market.

Edit: Here's an alternate solution, using reflection:

var argsForMethod = new List<string>(args);
var m = typeof(Program).GetMethod("CreateTaskGroup");
foreach (var p in m.GetParameters().Skip(args.Length))
    if (p.Attributes.HasFlag(ParameterAttributes.HasDefault))
        argsForMethod.Add((string)p.DefaultValue);
    else
        throw new NotImplementedException();
var result = (int)m.Invoke(null, argsForMethod.ToArray());

This can be a bit hard to read, and won't be too fast, but it does what you asked, without resorting to repetitive code, or having any uncertainty as to the default value of the parameters. You'll probably want to add some error handling for too few or too many parameters. I prefer this solution.

like image 57
Tim S. Avatar answered Sep 28 '22 02:09

Tim S.