The boxing overhead of the Enum.HasFlag method
By: Károly Ozsvárt
Tags: Csharp, Programming, Efficiency, Dotnet, Enum

Preface

Recently I have read the following in Jeffrey Richter’s book, CLR via C# (4th Edition) (page 368):

The Enum class defines a HasFlag method defined as follows.

public Boolean HasFlag(Enum flag);

(…)

I recommend that you avoid the HasFlag method for this reason: Because it takes a parameter of type Enum , any value you pass to it must be boxed, requiring a memory allocation.

and I decided to read and think some more about this topic and share what I have found.

I will discuss this considering the current version of .NET Framework, but .NET Core more than probably works the same way.

The origin of enums

Let’s create a simple enum:

[Flags]

public enum Color

{

Red = 1,

Green = 2,

Blue = 4,

}

Probably most you know that enums are value types. What is less known that all value types are derived implicitly from the System.ValueType type (it is a class ), which itself derives from System.Object class of course. But then you may ask: what makes them actually value types instead of reference types? The answer is: CLR. It detects that a type inherits from System.ValueType , and handles them accordingly (no, unfortunately you cannot derive from it in your code).

However, all enums have a common (implicit) ancestor, the System.Enum abstract class (which itself derives from System.ValueType ), where all common enum implementation is found, e.g.: GetValues , HasFlag , IsDefined , Parse , TryParse .

The Enum.HasFlag(Enum flag) method

Let’s see the implementation of the Enum.HasFlag(Enum flag) method (from referencesource):

The trouble of receiving a parameter of type Enum

The first part we are focusing on is the method header, where it can be seen that the type of the parameter is Enum , which itself is a reference (because it is a class), so if I pass my Color enum to it, it will be boxed. And most of the times it is wise to avoid any boxing since it requires extra memory allocation on the heap and eventually will give more job to the garbage collector (sometime after it goes out of scope).

It is important to note that in most applications, this does not even matter at all (except if you put it in a deeply nested cycle), but if you would like to write great and efficient C# code, you should definitely know this.

Type equality check at line 7–9

Since the received Enum can be any enum, the implementation has to make sure that the two enums ( this and the flag in the parameter) can be compared at all, so their type has to match. For safety reasons, this unfortunately has to be done. These lines further reduce the performance of flag checking (to a tiny extent, but they do).

Call into InternalHasFlag(flag) method

Here is where you would expect the real operation to happen; however if you try to locate the implementation inside referencesource, you will see this:

[System.Security.SecurityCritical] // auto-generated

[ResourceExposure(ResourceScope.None)]

[MethodImplAttribute(MethodImplOptions.InternalCall)]

private extern bool InternalHasFlag(Enum flags);

Which means this method is not implemented in the .NET framework, but in the CLR. By searching for the InternalHasFlag string in the CLR’s repository, you may find this method that is written in C++:

I am not a C++ developer so I can’t analyze it in depth, but we can easily see the following parts of the method:

lines 4–13 : there are some validation (self and target)

: there are some validation (self and target) lines 14–15 : self and target enums gets unboxed

: self and target enums gets unboxed lines 17–21 : some more validation about unboxed values

: some more validation about unboxed values lines 22-40: depending on the number of bytes of the underlying type of the enum, a bitwise AND operation is performed to perform the actual operation, which is basically this in C# code:

return (this & flag) == flag;

Note: an enum can have one the following types as an underlying type: byte , sbyte , short , ushort , int , uint , long , ulong , and the default is int .

Summary of boxing operations

So we can make a summary here about the boxing and unboxing operations performed. Let’s see this bit of code:

Color x = Color.Red | Color.Green;

bool hasFlag = x.HasFlag(Color.Blue);

While executing the second line of code, CLR will box x and Color.Blue , and later unbox them, so 2 boxing and 2 unboxing operations happen.

A better solution

So we want to find a way to avoid all these unnecessary memory allocations.

Extension methods

One possible solution is to write your own methods to perform this operation (you could inline these operations in place but that is not a clean way to do so and will make your code harder to read). C#’s extensions methods come in handy to implement it. Let’s see how to do it for our example Color enum.

Because of type safety, this implementation completely avoids boxing and unboxing and can be used conveniently like this (assuming you have the correct namespace referenced at your using s):

Color x = Color.Red | Color.Green;

bool hasFlag = x.IsSet(Color.Blue);

But can we make it generic? The answer is unfortunately not:

This does NOT compile

The above code will yield this error:

Operator ‘&’ cannot be applied to operands of type ‘T’ and ‘T’.

Performance impact

I ran a performance measurement using this code and got the following results on my PC (Intel i5–6500, DDR4). It was measured in Release mode, without attaching to the process.

Prefer 32-bit switch turned ON:

HasFlag: 46ms 50,2ms 71ms

Bitwise: 22ms 24,43ms 40ms

Prefer 32-bit switch turned OFF:

HasFlag: 33ms 34,39ms 38ms

Bitwise: 13ms 13,55ms 16ms

So manually implementing your HasFlag method can be around 2 times faster.

Summary

To sum up:

If you are either:

writing performance critical .NET code or

you just simply want to stay effective in terms of memory management

I recommend you to:

avoid the usage of the Enum class’s public Boolean HasFlag (Enum flag) method because it unnecessarily performs boxing and unboxing operations and

class’s method because it unnecessarily performs boxing and unboxing operations write extension methods for the target enum instead that will do their job more efficiently.

Further read

Besides the links inside the text, I recommend checking out the following: