Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Neatest way to 'OR' all values in a Flagged Enum?

Tags:

c#

enums

Given the enum:

[Flags]
public enum mytest
{
    a = 1,
    b = 2,
    c = 4
}

I've come up with two ways to represent all values in a single variable:

    var OR1 = (mytest)Enum.GetNames(typeof(mytest)).Sum(a => (int)Enum.Parse(typeof(mytest), a));
    var OR2 = (mytest)(typeof(mytest).GetEnumValues() as mytest[]).Sum(a => (int)a);

Now, although they both work, is there a neater way? Possibly a .NET method I'm missing?

Edit: For clarification, I need the function to be dynamic - I don't want to calculate it by specifying every single enum value.

like image 529
maxp Avatar asked Mar 08 '13 16:03

maxp


People also ask

What is a flagged enum?

Enum Flags Attribute The idea of Enum Flags is to take an enumeration variable and allow it hold multiple values. It should be used whenever the enum represents a collection of flags, rather than representing a single value. Such enumeration collections are usually manipulated using bitwise operators.

How do I assign multiple values to an enum?

Create enum constructor which accepts multiple values. Assign each constructor argument to a member field in the enum definition. Create getter methods so we can access any of the values assigned to a particular enum constant.

What is the role of flag attribute in enum?

The [Flag] attribute is used when Enum represents a collection of multiple possible values rather than a single value. All the possible combination of values will come. The [Flags] attribute should be used whenever the enumerable represents a collection of possible values, rather than a single value.

Do enums have to be sequential?

There is nothing that requires them to be sequential. Your enum definition is fine and will compile without issue.


3 Answers

If it makes sense to have an All member, just provide it directly:

[Flags]
public enum mytest
{
    a = 1,
    b = 2,
    c = 4,
    All = 7
}

Though, a more idiomatic way to write these could be:

[Flags]
public enum MyTest
{
    A = 1,
    B = 1 << 0x01,
    C = 1 << 0x02,
    All = A | B | C
}

This shows the logical progression of the enum values, and in the All case, makes it easy to add another member.

like image 73
Oded Avatar answered Sep 30 '22 05:09

Oded


Use Enumerable.Aggregate() to bitwise-or them together. This will work even if you have enum values that represent multiple set bits, as opposed to Sum().

var myTestValues = (MyTest[]) typeof(MyTest).GetEnumValues();
var sum = myTestValues.Aggregate((a, b) => a | b);
sum.Dump();

It's a little tricky to make this generic because you can't constrain generic types to be enums, nor do the primitive types have any subtype relationship to one another. The best I could come up with assumes that the underlying type is int which should be good enough most of the time:

TEnum AllEnums<TEnum>() 
{
    var values = typeof(TEnum).GetEnumValues().Cast<int>();
    return (TEnum) (object) values.Aggregate((a,b) => a|b);
}
like image 30
millimoose Avatar answered Sep 30 '22 07:09

millimoose


For a generic method, use Linq's Enumerable.Aggregate extension method;

var flags = Enum.GetValues(typeof(mytest))
                .Cast<int>()
                .Aggregate(0, (s, f) => s | f);

Or in a wrapper method

TEnum GetAll<TEnum>() where TEnum : struct
{
    return (TEnum) (object)
            Enum.GetValues(typeof(TEnum))
                .Cast<int>()
                .Aggregate(0, (s, f) => s | f);
}

full credit for this double-cast trick goes to @millimoose

like image 41
p.s.w.g Avatar answered Sep 30 '22 07:09

p.s.w.g