引用类型变量的装箱和拆箱技术的性能?

san*_*kum 2 .net c# boxing

装箱和拆箱仅为值类型定义。来源

装箱是将值类型转换为类型对象或由该值类型实现的任何接口类型的过程。当 CLR 装箱值类型时,它会将值包装在 System.Object 内并将其存储在托管堆上。拆箱从对象中提取值类型。拳击是含蓄的;拆箱是明确的。装箱和拆箱的概念是 C# 类型系统统一视图的基础,其中任何类型的值都可以被视为对象。

装箱和拆箱的性能是一个昂贵的过程,来源

装箱和拆箱是计算成本较高的过程。当一个值类型被装箱时,必须创建一个全新的对象。这可能比简单的参考分配花费最多 20 倍的时间。拆箱时,铸造过程可能需要四倍于作业的时间。

现在,如果我使用stringand string[],它们是引用类型,我会执行以下操作:

string A;
return (string)(object)A;
// IMP: Here first casting is similar to boxing (though for a reference type), and second casting is similar to unboxing.
Run Code Online (Sandbox Code Playgroud)

相似地,

string[] A;
return (string[])(object)A;
// IMP: Here first casting is similar to boxing (though for a reference type), and second casting is similar to unboxing.
Run Code Online (Sandbox Code Playgroud)

与计算成本较高的值类型不同,我们使用引用类型。对引用类型使用装箱/拆箱之类的技术是否会产生类似的性能影响?

它看起来类似于以下内容,但没有讨论性能影响(如果有):

Dam*_*ver 6

您可能有兴趣知道 C# 编译器完全删除了object强制转换1。您最终得到的是(假设该方法A从常量中分配一个值,然后具有您显示的代码):

.method private hidebysig static string Thing() cil managed
{
    .maxstack 8
    L_0000: ldstr "fred"
    L_0005: castclass string
    L_000a: ret 
}
Run Code Online (Sandbox Code Playgroud)

您可能最终会在此处对引用类型进行运行时检查,但如果 JIT 无法静态地证明堆栈上的引用已经存在,ldstr因此string可以删除它所引用的任何代码,我也不会感到惊讶。可能已考虑为该castclass操作生成。

引用强制转换是断言(我比编译器更好地知道我正在处理什么类型)。它们与装箱和拆箱完全不同。


1一般来说,对于引用类型之间的任何向上转型都是如此。