В этом случае требуется два вызова бокса, прежде чем вы даже попадете в метод HasFlags
. Один предназначен для разрешения вызова метода для типа значения в метод базового типа, другой - для передачи типа значения в качестве параметра ссылочного типа. Вы можете увидеть то же самое в IL, если сделаете var type = 1.GetType();
, литерал int
1 будет заключен в рамку перед вызовом GetType()
. Бокс при вызове метода кажется только тогда, когда методы не переопределены в самом определении типа значения, больше можно прочитать здесь: Приводит ли вызов метода к типу значения к упаковке в .NET?
HasFlags
принимает аргумент Enum
class, поэтому здесь будет происходить упаковка. Вы пытаетесь передать тип значения во что-то, ожидающее ссылочный тип. Чтобы представить значения в виде ссылок, используется упаковка.
Существует множество компиляторов, поддерживающих типы значений и их наследование (с Enum
/ ValueType
), что сбивает с толку ситуацию при попытке ее объяснить. Люди, кажется, думают, что из-за того, что Enum
и ValueType
находятся в цепочке наследования типов значений, бокс внезапно не применяется. Если бы это было правдой, то же самое можно было бы сказать о object
, поскольку все это наследует - но, как мы знаем, это неверно.
Это не останавливает того факта, что представление типа значения как ссылочного типа повлечет за собой бокс.
И мы можем доказать это на IL (ищите коды box
):
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
То же самое можно увидеть, когда представляет тип значения как ValueType
, это также приводит к боксу:
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
person
Adam Houldsworth
schedule
26.07.2012
Enum
не является перечислением ... - person Marc Gravell   schedule 26.07.2012ValueType
- это не тип значения, лол ... - person Adam Houldsworth   schedule 26.07.2012Enum.HasFlag
, я считаю, не упаковывается: blogs.msdn.microsoft.com/dotnet/2018/04/18/. Хотя я мог видетьbox
инструкцию в IL все еще в приложении 2.1, она не распределяется, поэтому я не вижу штраф за производительность. - person nawfal   schedule 24.10.2018