I have a generic method that is used in the Program.Main for some microservices. I want want to reuse options, but have different defaults.
Is there a way to specify the defaults that aren't compiled (property attributes)?
Attributes are constant and can't be modified at runtime.
You can modify the corresponding option property after parsing if you re-use the same Options with different microservices within WithParsed method.
This doesn't affect (Default: XYZ) in the help message though. Is it possible to change the complete help message for a single argument?
This could possibly be handled by having a DefaultFactory property in the Option and Value attributes. Functions can't be attribute parameters, but you could make DefaultFactory be a string that could be the name of a method of your options class, e.g.:
[Option("foo", DefaultFactory=nameof(CalculateValue))]
string Foo { get; set; }
[Option("num")]
int Number { get; set; }
public string CalculateValue() {
return (this.Number > 0) ? "positive" : (this.Number == 0) ? "zero" : "negative";
}
Then the Parser would first apply all default values specified by Default="some-constant-value", then for any DefaultFunc definitions it would use reflection to look up that name as a method on the options instance and call the method.
Wouldn't be too hard to implement this, now that I think about it. @pauldotknopf - Would this idea fit your needs?
@rmunn
PR can use the Default=nameof(CalculateValue) as a factory method without adding extra properties.
@moh-hassan - That won't work, because nameof(CalculateValue) is just the string "CalculateValue". The only advantage of using nameof is that if you rename CalculateValue to something else in an IDE that does proper renames, it wouldn't change the string "CalculateValue" if it was entered as a literal string, but nameof(CalculateValue) will be detected by the IDE's rename logic, so the link won't be broken. And it's precisely because nameof(CalculateValue) is turned into the literal string "CalculateValue" at compile time that it can be used as an attribute property. But when you have Default="some literal string" in the Option attribute on a string property, you should not assume that it's anything other than the actual default value the user wants to pass into that string. And that's why a new property name like DefaultFactory is needed, because Default=nameof(Foo) on a string property is ambiguous.
@rmunn
I mean that we can check, using reflection, if Default literal value starts with nameof then invoke the method name in the same way as a DefaultFactory .
Have a look to this discussion.
Nope, can't be done. By the time reflection is happening (at run-time), the nameof(Foo) expression found in the source code has been turned into the literal "Foo" at compile-time, and there is no way for any runtime code to tell whether it started as "Foo" or nameof(Foo). (You can try it yourself if you think I'm wrong). It will have to have a different name than Default. Possible names are DefaultFactory as I suggested, or DefaultProperty as suggested in https://github.com/commandlineparser/commandline/issues/191 for the HelpTextProperty. After reading that discussion, I'm leaning more towards DefaultProperty, because that gives more of a hint to the library user about what "shape" they should give it. (A "Factory" name should indicate that it should be a function that takes no parameters, but if you have a function then someone sometime is going to want to put parameters on it. Calling it FooProperty indicates that it should be a simple property with a get method, which can not (by definition) take parameters.)
Most helpful comment
This could possibly be handled by having a DefaultFactory property in the Option and Value attributes. Functions can't be attribute parameters, but you could make DefaultFactory be a string that could be the name of a method of your options class, e.g.:
Then the Parser would first apply all default values specified by
Default="some-constant-value", then for anyDefaultFuncdefinitions it would use reflection to look up that name as a method on the options instance and call the method.Wouldn't be too hard to implement this, now that I think about it. @pauldotknopf - Would this idea fit your needs?