1

After perusing some other questions regarding common ways to generically create access to friendly strings for enumeration values in C# this answer appeared to be my best bet for a generic solution where the friendly strings can be placed in the definition of the enumeration using DescriptionAttributes.

I implemented this as an extension method, but quickly realized that it would only work for standard enums, where the [Flags] attribute is not specified. I'm not completely sure of the best way to pursue implementing this for cases where the attribute is present.

Since the flags attribute means that multiple values can be selected simultaneously, using a single "friendly string" would not make sense. I was thinking of defining the friendly strings in the same way, but overloading the extension method to take that specific enum type where it would return a List<string> to provide friendly strings for all of the selected values.

The solution described above would work, but I feel like there will be lots of code duplication since each enum that uses the Flags attribute will require it's own extension method because enums can only be inherited by System.Enum, eliminating my ability to create a base type. It would be nicer if I could have a more generic method that can handle this by checking the enum if the flags attribute is present and then return one of the following:

  • single string (if no Flags), list (if Flags) - signature returns object
  • single string (if no Flags), list (if Flags) - signature returns dynamic
  • list that may only contain one value if flags is not specified - signature returns List<string>

I feel like this question may be a case of "having my cake and eating it too", since I would prefer to not have to do additional checks after getting the friendly string(s) and deduping my code. Is there a trick or good way to do this that isn't a messy hack?

Community
  • 1
  • 1
JNYRanger
  • 6,829
  • 12
  • 53
  • 81

2 Answers2

3

You can write a method just as in the answer you link, but with support for flag enums, and return a comma seperated string, something like:

public static string GetDescription(Enum value)
{
    Type type = value.GetType();
    var values = Enum.GetValues(type);
    var setValues = new List<Enum>();
    foreach(var enumValue in values)
    {
        if (value.HasFlag((Enum)enumValue))
            setValues.Add((Enum)enumValue);
    }
    var stringList = new List<string>();
    foreach (var singleValue in setValues)
    {
        var name = Enum.GetName(type, singleValue);
        if (name != null)
        {
            FieldInfo field = type.GetField(name);
            if (field != null)
            {
                DescriptionAttribute attr =
                       Attribute.GetCustomAttribute(field,
                         typeof(DescriptionAttribute)) as DescriptionAttribute;
                if (attr != null)
                {
                    stringList.Add(attr.Description);
                }
            }
        }
    }
    return string.Join(",", stringList.ToArray());
}

not the cleanest code, but you get the idea, only keep in my mind, that it wont work as expected for enums that are not flags - just throwing an idea.

Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
alek kowalczyk
  • 4,896
  • 1
  • 26
  • 55
  • Hmm..this is a possibility. I could just have a check within the method to branch to the correct method if the flags attribute is present or not. My only concern is that there's no way to know if the provided string contains a single description or multiple ones without performing additional checks. That's my only concern with this. – JNYRanger Aug 06 '15 at 14:08
  • If you need to know if the method returns a single string or more, then just return the List, and do the Join later on, then you can check the Count of that List. I don't know what the use case is – alek kowalczyk Aug 06 '15 at 14:13
  • The problem is that one method returns a single string, one returns a list. (I already have this implemented for non-flag attribute enums). In my question i mention that using this method is a possibility, but wasn't sure the best return type (always a list, generic object or dynamic type, or something else i haven't thought up). The use case is that these are options in an form that eventually generate a pre populated PDF. The friendly strings are the text in the pdf for the answers. (ASP.NET MVC program) – JNYRanger Aug 06 '15 at 14:16
  • So why not use one method returning a string, either with a single value or with more values comma-seperated? If you need the information if there is a single value or not after the method returned a value you have some possibilities, either return a List of string and join it in a comma seperated string on pdf population (then a single value will be just as a string), or return some custom class that holds a bool value "isMultipleValues" and the string itself, or have an "out" bool argument indicating if there are multiple values. I would not go with returning dynamic or object . – alek kowalczyk Aug 06 '15 at 14:19
  • For enums that can have multiple answers a bullet point list is created, which is why I wanted to differentiate between the two, but still only have one concise extension method. Now that I think about it though I guess it doesn't matter since I'll know which options would require a list.,, – JNYRanger Aug 06 '15 at 14:21
  • In that case I would always return a list, create a bullet when it has more elements than one. – alek kowalczyk Aug 06 '15 at 17:40
  • This solution didn't work for special enums with 0-value enums. [I've modified it slightly](http://pastebin.com/q9BBcLZN). – Uwe Keim Jun 20 '16 at 12:07
-1

Use enum.ToString() to get "unfriendly" strings (where enum is your Enum variable). Write a reusable extension method to convert UnfriendlyString to a friendly "unfriendly string" (eg insert space-lowercase wherever there is an uppercase or something similar).

For [Flags] you could either Split the unfriendly string, convert each sub-string, and perhaps Join again; or your extension method could take the commas into account.

Graham
  • 799
  • 2
  • 5
  • 14
  • This would mean I would essentially be using magic strings, which I do not want to do; actually this is what I'm currently refactoring out, which is why enums are being used in the first place. Additionally, I'm using `DescriptionAttribute`s to define the friendly strings to keep definitions within the same location. Please see the solution that I'm linking to in the first paragraph of my question for context. – JNYRanger Aug 05 '15 at 16:19
  • I didn't intend magic strings eg: `enum Example {Firsttype, SecondType, ThirdType}` then `ToString()` gives you "FirstType" etc and extension method gives you "first type". Perhaps I've missed something? – Graham Aug 05 '15 at 16:23
  • Sorry if I wasn't clear, and i guess they aren't *exactly* magic strings, but I want to avoid comparing strings when the values are known before hand. Also I want the definitions of the friendly strings within the enums definitions, so attributes are being used currently (this might be the part that you missed). – JNYRanger Aug 05 '15 at 16:25
  • I think I see what you mean. In my suggestion the actual enum-types form the definitions also (so no need to define them as descriptions). And the extension method would work for all enums. But of course it's your choice... – Graham Aug 05 '15 at 16:34
  • Your answer does not allow for the 'friendly strings' to be defined within the definitions of the enums, which is how it's currently set up. I'm using the [`DescriptionAttribute`](https://msdn.microsoft.com/en-us/library/system.componentmodel.descriptionattribute(v=vs.110).aspx) class to define the friendly strings inside the enum definitions. Your method would require that the friendly strings are defined within the extension method(s). This would work, but does not fulfill my requirements. – JNYRanger Aug 05 '15 at 16:38
  • You are right, the friendly strings shouldn't be defined in the extension method. My intention was that the extension method would convert any unfriendly string to a friendly string (using the terminology from the linked post). – Graham Aug 06 '15 at 08:35