Search code examples
c#.netvb.netenumsenum-flags

Best practice to determine the amount of flags contained in a Enum-flag combination?


In some scenarios, when I pass a Enum to a method, I need to handle whether it is a single Enum value, or otherwise it is a flag combination, for that purpose I wrote this simple extension:

Vb.Net:

<Extension>
Public Function FlagCount(ByVal sender As System.[Enum]) As Integer
    Return sender.ToString().Split(","c).Count()
End Function

C# (online translation):

[Extension()]
public int FlagCount(this System.Enum sender) {
    return sender.ToString().Split(',').Count();
}

Example Usage:

Vb.Net:

Dim flags As FileAttributes = (FileAttributes.Archive Or FileAttributes.Compressed)
Dim count As Integer = flags.FlagCount()
MessageBox.Show(flagCount.ToString())

C# (online translation):

FileAttributes flags = (FileAttributes.Archive | FileAttributes.Compressed);
int count = flags.FlagCount();
MessageBox.Show(flagCount.ToString());

I just would like to ask If exists a more direct and efficient way that what I'm currently doing to avoid represent the flag combination as a String then split it.


Solution

  • Option A:

    public int FlagCount(System.Enum sender)
    {
        bool hasFlagAttribute = sender.GetType().GetCustomAttributes(typeof(FlagsAttribute), false).Length > 0;
        if (!hasFlagAttribute) // No flag attribute. This is a single value.
            return 1;
    
        var resultString = Convert.ToString(Convert.ToInt32(sender), 2);
        var count = resultString.Count(b=> b == '1');//each "1" represents an enum flag.
        return count;
    }
    

    Explanation:

    • If the enum does not have a "Flags attribute", then it is bound to be a single value.
    • If the enum has the "Flags attribute", Convert it to the bit representation and count the "1"s. each "1" represents an enum flag.

    Option B:

    1. Get all flaged items.
    2. Count them...

    The code:

    public int FlagCount(this System.Enum sender)
    {
      return sender.GetFlaggedValues().Count;
    }
    
    /// <summary>
    /// All of the values of enumeration that are represented by specified value.
    /// If it is not a flag, the value will be the only value returned
    /// </summary>
    /// <param name="value">The value.</param>
    /// <returns></returns>
    public static List<Enum> GetFlaggedValues(this Enum value)
    {
        //checking if this string is a flagged Enum
        Type enumType = value.GetType();
        object[] attributes = enumType.GetCustomAttributes(true);
    
        bool hasFlags = enumType.GetCustomAttributes(true).Any(attr => attr is System.FlagsAttribute);
        //If it is a flag, add all flagged values
        List<Enum> values = new List<Enum>();
        if (hasFlags)
        {
            Array allValues = Enum.GetValues(enumType);
            foreach (Enum currValue in allValues)
            {
                if (value.HasFlag(currValue))
                {
                    values.Add(currValue);
                }
            }
        }
        else//if not just add current value
        {
            values.Add(value);
        }
        return values;
    }