为什么 Enum 的 HasFlag 方法需要装箱? [英] Why Enum's HasFlag method need boxing?

查看:31
本文介绍了为什么 Enum 的 HasFlag 方法需要装箱?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在阅读通过 CLR 的 C#",在第 380 页上有一条说明如下:

I am reading "C# via CLR" and on page 380, there's a note saying the following:

注意 Enum 类定义了一个 HasFlag 方法,定义如下

Note The Enum class defines a HasFlag method defined as follows

public Boolean HasFlag(Enum flag);

使用此方法,您可以像这样重写对 Console.WriteLine 的调用:

Using this method, you could rewrite the call to Console.WriteLine like this:

Console.WriteLine("Is {0} hidden? {1}", file, attributes.HasFlag(FileAttributes.Hidden));

但是,我建议您避免使用 HasFlag 方法,原因如下:

However, I recommend that you avoid the HasFlag method for this reason:

因为它需要一个枚举类型的参数,您传递给它的任何值都必须装箱,需要分配内存."

我无法理解这个粗体声明——为什么

I can not understand this bolded statement -- why "

传递给它的任何值都必须装箱

any value you pass to it must be boxed

flag参数类型是Enum,是值类型,为什么会有装箱?您传递给它的任何值都必须装箱"应该意味着当您将值类型传递给参数 Enum flag 时会发生装箱,对吗?

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?

推荐答案

在这种情况下,在进入 HasFlags 方法之前,需要两次装箱调用.一种是将值类型的方法调用解析为基类型方法,另一种是将值类型作为引用类型参数传递.如果你执行 var type = 1.GetType();,你可以在 IL 中看到相同的内容,文字 int 1 在 GetType() 之前被装箱代码> 调用.方法调用的装箱似乎只有在值类型定义本身没有覆盖方法时,可以在这里阅读更多内容:在.NET中调用值类型的方法会导致装箱吗?

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?

HasFlags 接受一个 Enum class 参数,所以这里会发生装箱.您正在尝试将 值类型 传递给期望引用类型.为了将值表示为引用,会发生装箱.

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.

有很多编译器支持值类型及其继承(使用 Enum/ValueType),在试图解释它时会混淆这种情况.人们似乎认为,因为EnumValueType 在值类型的继承链中,装箱突然不适用了.如果这是真的,那么 object 也可以这样说,因为一切都继承了它 - 但我们知道这是错误的.

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.

我们可以在 IL 中证明这一点(寻找 box 代码):

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

同样可以看到,当表示一个值类型为ValueType时,它也会导致装箱:

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

这篇关于为什么 Enum 的 HasFlag 方法需要装箱?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆