Peet Whittaker
Peet Whittaker

Reputation: 770

Assign Enum names to const variable

I'm currently trying to assign the names in a particular enum to a string so that I can use it in the help documentation that is output to the console. This is easy enough to do via:

public string names = string.Join(", ", Enum.GetNames(typeof(LicenseType)));

My problem is that I'm using the Command Line Parser Library, which requires the help text for each option to be specified as an attribute argument (HelpText), which must be a "constant expression, typeof expression or array creation expression of an attribute parameter type". Example of how names would be used:

[Option('t', "license-type", Required = true, HelpText = names)]

However, when I try and assign the enum names to a const string using the above code, the compiler complains that the expression is not constant.

Is there any way around this?

Upvotes: 1

Views: 2016

Answers (3)

David
David

Reputation: 10708

EDIT This can now be achieved using the nameof operator, albeit only by referencing each object one by one at compile time.

The problem is that even though enums might be compile-time constants, any code, including the above code to actually get those names, is not constant, since it requires evaluation beyond simply being a primitive. Thus, it is not possible to use an enum name in an Attribute which expects a string.

IF, however, the OptionAttribute is not sealed, you could define an inherited Attribute class which takes a parameter of the desired Enum, and then passes the above code to base(string). Using this Attribute, the library should see it as a OptionAttribute, even though you've handed it an enum value. See the following code:

public class EnumHelpTextAttribute // Always postpend the word "Attribute" to an attribute class
                                   // The compiler cleans this suffix when you actually use the Attribute
    : OptionAttribute
{
    public EnumHelpTextAttribute(LicenseType value)
        : base(string.Join(", ", Enum.GetName(typeof(LicenseType), value)))
    {
    }
}
// ...
[EnumHelpText(LicenseType.Restricted)]  // Or some other value in LicenseType...

Sadly, it has been noted that the OptionAttribute class is sealed, which prevents inheritors from being created. Being an open-source project however, it is possible to fork the source, unseal the class, and use the above suggestion thusly. As always, document the usage and make a pull request back - this could easily save someone else the trouble one day!

Upvotes: 3

Peet Whittaker
Peet Whittaker

Reputation: 770

After sleeping on it last night, the solution was actually pretty obvious (ain't it always the way!): just use string replacement...

class Options
{
    private static string LicenseTypeHelp = "License type (" + string.Join(", ", Enum.GetNames(typeof(CompanyLicenseType))) + ").";

    [Option('t', "license-type", Required = true, HelpText = "License type.")]
    public CompanyLicenseType LicenseType { get; set; }    

    [HelpOption('h', "help", HelpText = "Dispaly this help screen.")]
    public string GetUsage()
    {
        string helpText = HelpText.AutoBuild(this, current => HelpText.DefaultParsingErrorsHandler(this, current));
        return helpText.Replace("License type.", LicenseTypeHelp);
    }
}

Upvotes: 0

Yuval Itzchakov
Yuval Itzchakov

Reputation: 149518

Enums are compile time constants, but the compiler has no guarantee that a method call to string.Join will yield a constant value because it is being used with an Enum.GetName.

As your enum is a compile to constant, you will need to hardcode the values to your attributes.

Upvotes: 0

Related Questions