Why Enum's HasFlag method need boxing?
.net, boxing, c#, enums
Solution
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
Problem
I am reading "C# via CLR" and on page 380, there's a note saying the following: Note The Enum class defines a HasFlag method defined as follows `public Boolean HasFlag(Enum flag);` Using this method, you could rewrite the call to Console.WriteLine like this: `Console.WriteLine("Is {0} hidden? {1}", file, attributes.HasFlag(FileAttributes.Hidden));` However, I recommend that you avoid the HasFlag method for this reason: Since it takes a parameter of type Enum, any value you pass to it must be boxed, requiring a memory allocation ." I can not understand this bolded statement -- why " any value you pass to it must be boxed The `flag` parameter type is `Enum`, which is a value type, why would there be boxing? The "any value you pass to it must be boxed" should mean boxing happens when you pass value type to parameter `Enum flag`, right?