再议C#中的装箱与拆箱的问题详解

所属分类: 软件编程 / C#教程 阅读数: 62
收藏 0 赞 0 分享
上一篇写了一下装箱拆箱的定义和IL分析,这一篇我们看下使用泛型和不使用泛型引发装箱拆箱的情况
1.使用非泛型集合时引发的装箱和拆箱操作
看下面的一段代码:
复制代码 代码如下:

var array = new ArrayList();
array.Add(1);
array.Add(2);

foreach (int value in array)
{
Console.WriteLine(“value is {0}”,value);
}

代码声明了一个ArrayList对象,向ArrayList中添加两个数字1,2;然后使用foreach将ArrayList中的元素打印到控制台。
在这个过程中会发生两次装箱操作和两次拆箱操作,在向ArrayList中添加int类型元素时会发生装箱,在使用foreach枚举ArrayList中的int类型元素时会发生拆箱操作,将object类型转换成int类型,在执行到Console.WriteLine时,还会执行两次的装箱操作;这一段代码执行了6次的装箱和拆箱操作;如果ArrayList的元素个数很多,执行装箱拆箱的操作会更多。
你可以通过使用ILSpy之类的工具查看IL代码的box,unbox指令查看装箱和拆箱的过程
2.使用泛型集合的情况
请看如下代码:
复制代码 代码如下:

var list = new List<int>();
list.Add(1);
list.Add(2);

foreach (int value in list)
{
Console.WriteLine("value is {0}", value);
}

代码和1中的代码的差别在于集合的类型使用了泛型的List,而非ArrayList;我们同样可以通过查看IL代码查看装箱拆箱的情况,上述代码只会在Console.WriteLine()方法时执行2次装箱操作,不需要拆箱操作。
可以看出泛型可以避免装箱拆箱带来的不必要的性能消耗;当然泛型的好处不止于此,泛型还可以增加程序的可读性,使程序更容易被复用等等。
本文使用的C#代码如下:
复制代码 代码如下:

using System;
using System.Collections;
using System.Collections.Generic;

namespace boxOrUnbox
{
    class Program
    {
        static void Main(string[] args)
        {
            //do nothing
        }

        static void Box()
        {
            object objValue = 9;
        }

        static void Unbox()
        {
            object objValue = 4;
            int value = (int)objValue;
        }

        static void LookatArrayList()
        {
            var array = new ArrayList();
            array.Add(1);
            array.Add(2);

            foreach (int value in array)
            {
                Console.WriteLine("value is {0}", value);
            }
        }

        static void LookatGenericList()
        {
            var list = new List<int>();
            list.Add(1);
            list.Add(2);

            foreach (int value in list)
            {
                Console.WriteLine("value is {0}", value);
            }
        }
    }
}

C#的IL代码如下:
复制代码 代码如下:

.class private auto ansi beforefieldinit boxOrUnbox.Program
    extends [mscorlib]System.Object
{
    // Methods
    .method private hidebysig static
        void Main (
            string[] args
        ) cil managed
    {
        // Method begins at RVA 0x2050
        // Code size 2 (0x2)
        .maxstack 8
        .entrypoint

        IL_0000: nop
        IL_0001: ret
    } // end of method Program::Main

    .method private hidebysig static
        void Box () cil managed
    {
        // Method begins at RVA 0x2054
        // Code size 10 (0xa)
        .maxstack 1
        .locals init (
            [0] object objValue
        )

        IL_0000: nop
        IL_0001: ldc.i4.s 9
        IL_0003: box [mscorlib]System.Int32
        IL_0008: stloc.0
        IL_0009: ret
    } // end of method Program::Box

    .method private hidebysig static
        void Unbox () cil managed
    {
        // Method begins at RVA 0x206c
        // Code size 16 (0x10)
        .maxstack 1
        .locals init (
            [0] object objValue,
            [1] int32 'value'
        )

        IL_0000: nop
        IL_0001: ldc.i4.4
        IL_0002: box [mscorlib]System.Int32
        IL_0007: stloc.0
        IL_0008: ldloc.0
        IL_0009: unbox.any [mscorlib]System.Int32
        IL_000e: stloc.1
        IL_000f: ret
    } // end of method Program::Unbox

    .method private hidebysig static
        void LookatArrayList () cil managed
    {
        // Method begins at RVA 0x2088
        // Code size 114 (0x72)
        .maxstack 2
        .locals init (
            [0] class [mscorlib]System.Collections.ArrayList 'array',
            [1] int32 'value',
            [2] class [mscorlib]System.Collections.IEnumerator CS$5$0000,
            [3] bool CS$4$0001,
            [4] class [mscorlib]System.IDisposable CS$0$0002
        )

        IL_0000: nop
        IL_0001: newobj instance void [mscorlib]System.Collections.ArrayList::.ctor()
        IL_0006: stloc.0
        IL_0007: ldloc.0
        IL_0008: ldc.i4.1
        IL_0009: box [mscorlib]System.Int32
        IL_000e: callvirt instance int32 [mscorlib]System.Collections.ArrayList::Add(object)
        IL_0013: pop
        IL_0014: ldloc.0
        IL_0015: ldc.i4.2
        IL_0016: box [mscorlib]System.Int32
        IL_001b: callvirt instance int32 [mscorlib]System.Collections.ArrayList::Add(object)
        IL_0020: pop
        IL_0021: nop
        IL_0022: ldloc.0
        IL_0023: callvirt instance class [mscorlib]System.Collections.IEnumerator [mscorlib]System.Collections.ArrayList::GetEnumerator()
        IL_0028: stloc.2
        .try
        {
            IL_0029: br.s IL_004a
            // loop start (head: IL_004a)
                IL_002b: ldloc.2
                IL_002c: callvirt instance object [mscorlib]System.Collections.IEnumerator::get_Current()
                IL_0031: unbox.any [mscorlib]System.Int32
                IL_0036: stloc.1
                IL_0037: nop
                IL_0038: ldstr "value is {0}"
                IL_003d: ldloc.1
                IL_003e: box [mscorlib]System.Int32
                IL_0043: call void [mscorlib]System.Console::WriteLine(string, object)
                IL_0048: nop
                IL_0049: nop

                IL_004a: ldloc.2
                IL_004b: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()
                IL_0050: stloc.3
                IL_0051: ldloc.3
                IL_0052: brtrue.s IL_002b
            // end loop

            IL_0054: leave.s IL_0070
        } // end .try
        finally
        {
            IL_0056: ldloc.2
            IL_0057: isinst [mscorlib]System.IDisposable
            IL_005c: stloc.s CS$0$0002
            IL_005e: ldloc.s CS$0$0002
            IL_0060: ldnull
            IL_0061: ceq
            IL_0063: stloc.3
            IL_0064: ldloc.3
            IL_0065: brtrue.s IL_006f

            IL_0067: ldloc.s CS$0$0002
            IL_0069: callvirt instance void [mscorlib]System.IDisposable::Dispose()
            IL_006e: nop

            IL_006f: endfinally
        } // end handler

        IL_0070: nop
        IL_0071: ret
    } // end of method Program::LookatArrayList

    .method private hidebysig static
        void LookatGenericList () cil managed
    {
        // Method begins at RVA 0x2118
        // Code size 90 (0x5a)
        .maxstack 2
        .locals init (
            [0] class [mscorlib]System.Collections.Generic.List`1<int32> list,
            [1] int32 'value',
            [2] valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32> CS$5$0000,
            [3] bool CS$4$0001
        )

        IL_0000: nop
        IL_0001: newobj instance void class [mscorlib]System.Collections.Generic.List`1<int32>::.ctor()
        IL_0006: stloc.0
        IL_0007: ldloc.0
        IL_0008: ldc.i4.1
        IL_0009: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<int32>::Add(!0)
        IL_000e: nop
        IL_000f: ldloc.0
        IL_0010: ldc.i4.2
        IL_0011: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<int32>::Add(!0)
        IL_0016: nop
        IL_0017: nop
        IL_0018: ldloc.0
        IL_0019: callvirt instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<int32>::GetEnumerator()
        IL_001e: stloc.2
        .try
        {
            IL_001f: br.s IL_003c
            // loop start (head: IL_003c)
                IL_0021: ldloca.s CS$5$0000
                IL_0023: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>::get_Current()
                IL_0028: stloc.1
                IL_0029: nop
                IL_002a: ldstr "value is {0}"
                IL_002f: ldloc.1
                IL_0030: box [mscorlib]System.Int32
                IL_0035: call void [mscorlib]System.Console::WriteLine(string, object)
                IL_003a: nop
                IL_003b: nop

                IL_003c: ldloca.s CS$5$0000
                IL_003e: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>::MoveNext()
                IL_0043: stloc.3
                IL_0044: ldloc.3
                IL_0045: brtrue.s IL_0021
            // end loop

            IL_0047: leave.s IL_0058
        } // end .try
        finally
        {
            IL_0049: ldloca.s CS$5$0000
            IL_004b: constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>
            IL_0051: callvirt instance void [mscorlib]System.IDisposable::Dispose()
            IL_0056: nop
            IL_0057: endfinally
        } // end handler

        IL_0058: nop
        IL_0059: ret
    } // end of method Program::LookatGenericList

    .method public hidebysig specialname rtspecialname
        instance void .ctor () cil managed
    {
        // Method begins at RVA 0x2190
        // Code size 7 (0x7)
        .maxstack 8

        IL_0000: ldarg.0
        IL_0001: call instance void [mscorlib]System.Object::.ctor()
        IL_0006: ret
    } // end of method Program::.ctor

} // end of class boxOrUnbox.Program
更多精彩内容其他人还在看

WPF仿三星手机充电界面实现代码

这篇文章主要为大家详细介绍了WPF仿三星手机充电界面实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

浅谈C#各种数组直接的数据复制/转换

下面小编就为大家带来一篇浅谈C#各种数组直接的数据复制/转换。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
收藏 0 赞 0 分享

C#访问SQLServer增删改查代码实例

这篇文章主要为大家详细介绍了C#访问SQLServer增删改查代码实例,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

C#根据身份证号码判断出生日期和性别

这篇文章主要为大家详细介绍了C#根据身份证号码判断出生日期和性别的方法,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

C# 向Word中设置/更改文本方向的方法(两种)

在一般情况下word中输入的文字都是横向的,今天小编给大家带来两种方法来设置更改文本方向的方法,非常不错,对c# word 更改文本方向的知识感兴趣的朋友一起看看吧
收藏 0 赞 0 分享

让C# Excel导入导出 支持不同版本Office

让C# Excel导入导出,支持不同版本的Office,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

C#设置自定义文件图标实现双击启动(修改注册表)

这篇文章介绍的是利用C#设置自定义文件图标,然后实现双击启动的功能,文章给出了示例代码,介绍的很详细,有需要的可以参考借鉴。
收藏 0 赞 0 分享

C#两个相同属性的类赋值方法

这篇文章主要介绍了C#两个相同属性的类赋值方法的相关资料,需要的朋友可以参考下
收藏 0 赞 0 分享

C#中ListView控件实现窗体代码

这篇文章主要介绍了C#中ListView控件实现窗体的核心代码,非常不错,具有参考借鉴价值,对c#listview相关知识感兴趣的朋友一起学习吧
收藏 0 赞 0 分享

浅谈C# 序列化与反序列化几种格式的转换

下面小编就为大家带来一篇浅谈C# 序列化与反序列化几种格式的转换。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
收藏 0 赞 0 分享
查看更多