Get Description Attributes From a Flagged Enum
Asked Answered
P

3

9

I am trying to create an extension method that will return a List<string> containing all the Description attributes for only the set values of a given [Flags] Enum.

For example, suppose I have the following enum declared in my C# code:

[Flags]
public enum Result
{
    [Description("Value 1 with spaces")]
    Value1 = 1,
    [Description("Value 2 with spaces")]
    Value2 = 2,
    [Description("Value 3 with spaces")]
    Value3 = 4,
    [Description("Value 4 with spaces")]
    Value4 = 8
}

And then have a variable set as:

Result y = Result.Value1 | Result.Value2 | Result.Value4;

So, the call I want to create would be:

List<string> descriptions = y.GetDescriptions();

and the final result would be:

descriptions = { "Value 1 with spaces", "Value 2 with spaces", "Value 4 with spaces" };

I have created an extension method for getting the single description attribute for an Enum that can not have multiple flags set that is along the following lines:

public static string GetDescription(this Enum value)
{
    Type type = value.GetType();
    string name = Enum.GetName(type, value);
    if (name != null)
    {
        System.Reflection.FieldInfo field = type.GetField(name);
        if (field != null)
        {
            DescriptionAttribute attr =
                   Attribute.GetCustomAttribute(field,
                     typeof(DescriptionAttribute)) as DescriptionAttribute;
            if (attr != null)
            {
                return attr.Description;
            }
        }
    }
    return null;
}

And I've found some answers online on how to get ALL the Description attributes for a given Enum type (such as here), but I'm having problems writing a generic extension method to return the list of descriptions for only the set attributes.

Any help would be really appreciated.

THANKS!!

Penult answered 31/7, 2017 at 22:29 Comment(2)
I edited your title because while you are using C# your question is not about C# (it's unnecessary to have tags in your title unless it is an integral part of it)Lotson
@slugster, I put that in my title as I wanted to mention it was a c# question and not Java / some other language - I am looking for an extension method written in a specific language, so I thought it appropriate.Penult
B
12

HasFlag is your friend. :-)

The extension method below uses the GetDescription extension method you've posted above, so ensure you have that. The following should then work:

public static List<string> GetDescriptionsAsText(this Enum yourEnum)
{       
    List<string> descriptions = new List<string>();

    foreach (Enum enumValue in Enum.GetValues(yourEnum.GetType()))
    {
        if (yourEnum.HasFlag(enumValue))
        {
            descriptions.Add(enumValue.GetDescription());
        }
    }

    return descriptions;
}

Note: HasFlag allows you to compare a given Enum value against the flags defined. In your example, if you have

Result y = Result.Value1 | Result.Value2 | Result.Value4;

then

y.HasFlag(Result.Value1)

should be true, while

y.HasFlag(Result.Value3)

will be false.

See also: https://msdn.microsoft.com/en-us/library/system.enum.hasflag(v=vs.110).aspx

Bock answered 31/7, 2017 at 22:54 Comment(2)
DARN IT!! - I was so close!! - Thank you so much for ending my pain!! :)Penult
Glad to help. I've updated the name of the foreach variable as well now - makes it feel a little more generic (with a small 'g'). Doesn't change anything - just looks neater.Bock
A
3

This is a compact solution using LINQ which also checks for null in case not all of the values have attributes:

public static List<T> GetFlagEnumAttributes<T>(this Enum flagEnum) where T : Attribute
{
   var type = flagEnum.GetType();
   return Enum.GetValues(type)
      .Cast<Enum>()
      .Where(flagEnum.HasFlag)
      .Select(e => type.GetMember(e.ToString()).First())
      .Select(info => info.GetCustomAttribute<T>())
      .Where(attribute => attribute != null)
      .ToList();
}
Angioma answered 18/9, 2018 at 8:37 Comment(0)
P
0

You can iterate all values from enum and then filter them that isn't contained into your input value.

    public static List<T> GetAttributesByFlags<T>(this Enum arg) where T: Attribute
    {
        var type = arg.GetType();
        var result = new List<T>();
        foreach (var item in Enum.GetValues(type))
        {
            var value = (Enum)item;
            if (arg.HasFlag(value)) // it means that '(arg & value) == value'
            {
                var memInfo = type.GetMember(value.ToString())[0];
                result.Add((T)memInfo.GetCustomAttribute(typeof(T), false));
            }
        }
        return result;
    }

And you get list of attributes that you want:

var arg = Result.Value1 | Result.Value4;
List<DescriptionAttribute> attributes = arg.GetAttributesByFlags<DescriptionAttribute>();
Pulpy answered 31/7, 2017 at 23:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.