跳转到主内容
新派编程网 - 新潮编程理念,全新技术课堂!

C#怎么使用装箱拆箱_C# Boxing Unboxing性能影响教程【进阶】

装箱和拆箱是堆分配+拷贝+类型检查的实操过程,非语法糖;常见于Console.WriteLine(i)、list.Add(100)、接口赋值等隐式场景;泛型可彻底避免装箱,性能敏感处需重点排查UI事件、序列化循环及数值计算中object委托调用。 装箱和拆箱不是语法糖,是实打实的堆分配+拷贝+类型检查;高频场景下性能损耗远超直觉,尤其在循环、集合遍历、事件参数传递中容易被忽略。 哪些代码会悄悄触发装箱 不是只有
object obj = 42;
这种写法才算装箱。以下情况都会发生:
Console.WriteLine(i)
(
i
是
int
)——
WriteLine(object)
重载被选中,隐式装箱
list.Add(100)
,其中
list
是
List 或非泛型
ArrayList
button.Click += (s, e) => { int x = 5; DoSomething(x); };
,而
DoSomething(object param)
接收该值
IComparable comp = 42;
——接口实现也会触发装箱,哪怕
int
原生支持
IComparable
关键判断点:只要值类型被当作
object
或任意接口类型使用,且该接口不是由泛型约束承载(如
T : IComparable
),就发生了装箱。 拆箱失败的典型错误和检查方式 拆箱必须显式、且类型严格匹配。常见错误包括:
object obj = 42; double d = (double)obj;
→ 抛出
InvalidCastException
,因为装箱前是
int
,不能直接拆成
double
if (obj is double) { ... }
对
int
装箱结果永远为
false
,
is
检查的是装箱时的原始类型 用
Convert.ToDouble(obj)
看似“安全”,但底层仍是先拆箱再转换,若类型不匹配仍抛异常 稳妥做法是先用
obj is int
判断,再强制转换:
if (obj is int i) { /* 使用 i */ }
(C# 7.0+ 模式匹配语法,避免重复拆箱)。 C知道 CSDN推出的一款AI技术问答工具 下载 泛型如何绕过装箱开销 泛型方法/类型在编译期生成专用版本,值类型参数不经过
object
中转。对比下面两段:
void LogValue(object v) => Console.WriteLine(v); // 装箱 LogValue(123); // int → object → WriteLine(object)

void LogValue(T v) => Console.WriteLine(v); // 无装箱 LogValue(123); // 编译器生成 LogValue(int),直接调用 WriteLine(int)

实际影响不止于函数调用:
List
内部存储
int
值本身,而
ArrayList
存储的是堆上装箱的
int
对象 —— 后者多一次堆分配、GC 压力、缓存不友好。 性能敏感路径里必须检查的三个地方 不是所有装箱都该被干掉,但以下位置一旦高频执行,极易成为瓶颈: UI 事件处理中的日志或状态更新(如每帧调用
Debug.Log(value)
,
value
是
struct
) 序列化/反序列化循环体内部(如
foreach (var item in list) { jsonWriter.Write(item.ToString()); }
,
item
是自定义
struct
) 数值计算密集型循环中传入
object
参数的委托调用(如
Array.ForEach(arr, Action) ) 真正难察觉的是间接装箱:一个
struct
实现了
IDisposable
,你把它传给接受
IDisposable
的方法,就已装箱——哪怕它没字段、没虚方法。

相关文章