What Is It That Makes Enum.Hasflag So Slow

What is it that makes Enum.HasFlag so slow?

Does anyone know the internals of Enum.HasFlag and why it is so slow?

The actual check is just a simple bit check in Enum.HasFlag - it's not the problem here. That being said, it is slower than your own bit check...

There are a couple of reasons for this slowdown:

First, Enum.HasFlag does an explicit check to make sure that the type of the enum and the type of the flag are both the same type, and from the same Enum. There is some cost in this check.

Secondly, there is an unfortunate box and unbox of the value during a conversion to UInt64 that occurs inside of HasFlag. This is, I believe, due to the requirement that Enum.HasFlag work with all enums, regardless of the underlying storage type.

That being said, there is a huge advantage to Enum.HasFlag - it's reliable, clean, and makes the code very obvious and expressive. For the most part, I feel that this makes it worth the cost - but if you're using this in a very performance critical loop, it may be worth doing your own check.

C# Enum.HasFlag vs. Bitwise AND Operator Check

There is a performance cost to using HasFlag, because the implementation verifies that the enum value that you pass is of the same type as the flag.

With this difference out of the way, the implementation is highly optimized to avoid promoting shorter types, such as byte, to int:

switch (pMTThis->GetNumInstanceFieldBytes()) {
case 1:
cmp = ((*(UINT8*)pThis & *(UINT8*)pFlags) == *(UINT8*)pFlags);
break;
case 2:
cmp = ((*(UINT16*)pThis & *(UINT16*)pFlags) == *(UINT16*)pFlags);
break;
case 4:
cmp = ((*(UINT32*)pThis & *(UINT32*)pFlags) == *(UINT32*)pFlags);
break;
case 8:
cmp = ((*(UINT64*)pThis & *(UINT64*)pFlags) == *(UINT64*)pFlags);
break;
default:
// should not reach here.
UNREACHABLE_MSG("Incorrect Enum Type size!");
break;
}

The source of ReflectionEnum::InternalHasFlag can be found here.

Although the cost is relatively high, it is unlikely to matter, except for the most extreme situations. I would recommend keeping it, unless your profiler points to this call as a largest bottleneck in your program.

Why Enum's HasFlag method need boxing?

In this instance, two boxing calls are required before you even get into the HasFlags method. One is for resolving the method call on the value type to the base type method, the other is passing the value type as a reference type parameter. You can see the same in IL if you do var type = 1.GetType();, the literal int 1 is boxed before the GetType() call. The boxing on method call seems to be only when methods are not overridden in the value type definition itself, more can be read here: Does calling a method on a value type result in boxing in .NET?

The HasFlags takes an Enum class argument, so the boxing will occur here. You are trying to pass what is a value type into something expecting a reference type. To represent values as references, boxing occurs.

There is lots of compiler support for value types and their inheritance (with Enum / ValueType) that confuses the situation when trying to explain it. People seem to think that because Enum and ValueType is in the inheritance chain of value types boxing suddenly doesn't apply. If this were true, the same could be said of object as everything inherits that - but as we know this is false.

This doesn't stop the fact that representing a value type as a reference type will incur boxing.

And we can prove this in IL (look for the box codes):

class Program
{
static void Main(string[] args)
{
var f = Fruit.Apple;
var result = f.HasFlag(Fruit.Apple);

Console.ReadLine();
}
}

[Flags]
enum Fruit
{
Apple
}

.method private hidebysig static
void Main (
string[] args
) cil managed
{
// Method begins at RVA 0x2050
// Code size 28 (0x1c)
.maxstack 2
.entrypoint
.locals init (
[0] valuetype ConsoleApplication1.Fruit f,
[1] bool result
)

IL_0000: nop
IL_0001: ldc.i4.0
IL_0002: stloc.0
IL_0003: ldloc.0
IL_0004: box ConsoleApplication1.Fruit
IL_0009: ldc.i4.0
IL_000a: box ConsoleApplication1.Fruit
IL_000f: call instance bool [mscorlib]System.Enum::HasFlag(class [mscorlib]System.Enum)
IL_0014: stloc.1
IL_0015: call string [mscorlib]System.Console::ReadLine()
IL_001a: pop
IL_001b: ret
} // end of method Program::Main

The same can be seen when representing a value type as ValueType, it also results in boxing:

class Program
{
static void Main(string[] args)
{
int i = 1;
ValueType v = i;

Console.ReadLine();
}
}

.method private hidebysig static
void Main (
string[] args
) cil managed
{
// Method begins at RVA 0x2050
// Code size 17 (0x11)
.maxstack 1
.entrypoint
.locals init (
[0] int32 i,
[1] class [mscorlib]System.ValueType v
)

IL_0000: nop
IL_0001: ldc.i4.1
IL_0002: stloc.0
IL_0003: ldloc.0
IL_0004: box [mscorlib]System.Int32
IL_0009: stloc.1
IL_000a: call string [mscorlib]System.Console::ReadLine()
IL_000f: pop
IL_0010: ret
} // end of method Program::Main

What are the pros and cons of using a flags enum?

At the very least, your second example has better semantics and indicates the meaning of the bits within the code. There is some documentation within the code of what the bit is used for.

Otherwise, based on your first example, you will need to add comments since you are basically twiddling magic (bit) numbers, which makes the code much more difficult to read, especially by another person not familiar with it. Even if you yourself will be maintaining this code six months down the road, you may find it difficult to remember what bit 5 was used for.

Enum.HasFlag, why no Enum.SetFlag?

The & operator will give you the same answer with a & b as it will with b & a, so

(EventMessaageScope.Private).Get(EventMessageScope.Private | EventMessageScope.PublicOnly)

is the same as writing

(EventMessageScope.Private | EventMessageScope.PublicOnly).Get(EventMessaageScope.Private)

If you just want to know if the value is the same as EventMessaageScope.Public, then just use equals:

EventMessageScope.Private == EventMessageScope.Public

Your method will always return false for (EventMessageScope.None).Get(EventMessaageScope.None) because None == 0 and it only returns true when the result of the AND operation is not zero. 0 & 0 == 0.

Which is the better way to compare Flags Enum?

So long as flag is a one-bit flag, they are equivalent. If flag has multiple bits,

(value & flag) == flag;

is a logical AND (ALL bits must match) while

(value & flag) != 0;

is a logical OR (ANY of the bits must match).

C# Enum Flags Comparison

Change your inner & to |:

if ((operation & (Operations.add | Operations.eval)) == (Operations.add | Operations.eval))

This is equivalent to:

if( ((operation & Operations.add)==Operations.add) &&
((operation & Operations.eval)==Operations.eval))

which might be more readable. You might also want to consider an Extension like this:

public static bool HasFlag(this Operations op, Operations checkflag)
{
return (op & checkflag)==checkflag;
}

then you can do this:

if(operation.HasFlag(Operations.add) && Operations.HasFlag(Operations.eval))

which might be even more readable. Finally you could create this extension for even more fun:

public static bool HasAllFlags(this Operations op, params Operations[] checkflags)
{
foreach(Operations checkflag in checkflags)
{
if((op & checkflag)!=checkflag)
return false;
}
return true;
}

Then your expression could turn into:

if(operation.HasAllFlags(Operations.add, Operations.eval))

Check if an enum contains more than one flag

I am trying to check if an "enum instance" contains more than one flag.
I do not care which Flags the "instance" contains, I just want to know if there are more than one

Additionally I really don't wanna use something like the following:

 var state = Foo.Bar | Foo.Far;
Console.WriteLine(state.ToString().Count(x => x == ',') > 0); // True

There are more than a few different ways to accomplish what you want, I propose to do a bit (bitwise) check:

 public static bool MoreThanOneFlag<TValue>(TValue flag) where TValue : Enum => (Convert.ToInt32(flag) & (Convert.ToInt32(flag) - 1)) != 0;

In the above code block, we check if flag is not a power of two by checking using flag & (flag-1)) != 0 (the & operator) which computes the bitwise logical AND of its operands. If there's only one flag set, we assume then that the value would be a power of two, otherwise it's a non power of two.

Or, if you don't want a helper function just perform that check anywhere:

 bool value = (multiState & (multiState -1)) != 0;

For more information about bitwise, please check out more here.

References :

Bitwise and shift operators (C# reference)

Why are Python Enums slow?

This is a known bug in Python 3.4's enum: https://bugs.python.org/issue23486

It's been "fixed" in Python 3.5, such that enum attribute lookup is only 3x slower than normal, instead of 20x.

What to do when bit mask (flags) enum gets too large

I see values from at least a handful of different enumerations in there...

My first thought was to approach the problem by splitting the permissions up in logical groups (RuleGroupPermissions, RulePermissions, LocationPermissions, ...), and then having a class (WebAgentPermissions) exposing a property for each permission enum type.

Since the permission values seem repetitive, you could probably get away with a single enum in the end:

[Flags]
public enum Permissions
{
View = 1,
Add = 2,
Edit = 4,
Delete = 8
}

And then have the WebAgentPermissions class expose a property for each area where permissions are to be set;

class WebAgentPermissions
{
public Permissions RuleGroup { get; set; }
public Permissions Rule { get; set; }
public Permissions Location { get; set; }
// and so on...
}


Related Topics



Leave a reply



Submit