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

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

问题描述

我正在阅读C#通过CLR和第380页,有一个说明说:


注意枚举类定义一个HasFlag方法定义如下



public Boolean HasFlag(枚举标志);



使用此方法,您可以重写对Console.WriteLine的调用,如下所示:



Console.WriteLine(Is {0}隐藏?{1},文件,属性.HasFlag(FileAttributes.Hidden));



但是,我建议你为避免使用HasFlag方法:



由于它需要一个
参数类型为枚举,您传递给它的任何值必须是盒装的,需要一个内存分配


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


您传递给它的任何值都必须是盒装



标志类型是枚举,它是值类型,这里还有拳击吗?
这里你传递给它的任何值必须是boxed应该意味着拳击发生时你传递值类型到参数枚举标志,对吗?

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



HasFlags 需要一个枚举 参数,所以拳击将在这里发生。您正在尝试将什么是值类型传递给预期的内容参考类型。为了表示值作为参考,将发生拳击。



有很多对值类型及其继承的编译器支持(使用枚举 / ValueType ),这在尝试解释它时会混淆这种情况。人们似乎认为,因为枚举 ValueType 在值类型的继承链中突然不适用。如果这是真的,同样的话可以说是对象,因为所有继承的都是 - 但是我们知道这是假的。



这并不能阻止表示价值类型作为参考类型的事实将招致拳击。



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

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

Console.ReadLine();
}
}

[标志]
枚举水果
{
苹果
}



.method private hidebysig static
void Main(
string [] args
)cil managed
{
//方法从RVA开始0x2050
//代码大小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:调用字符串[mscorlib] System.Console :: ReadLine()
IL_001a:pop
IL_001b: ret
} //方法结束程序::主

同样可以当表示的价值类型为 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
{
//方法从RVA开始0x2050
//代码大小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
} //方法结束程序::主
pre>

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

"? flag parament type is Enum, which is value type, why here still got boxing? here "any value you pass to it must be boxed" should mean boxing happens when you pass value type to parameter "Enum flag", right?

解决方案

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

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

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