Files
My-Notes/笔记/CSharp/核心/万物之父和装箱与拆箱.md
2026-06-21 09:51:55 +08:00

5.9 KiB
Raw Permalink Blame History

万物之父和装箱与拆箱

object

概念: objectSystem.Object 的别名 在 C# 的统一类型系统里,可以把它理解成==万物之父== 因为==所有类型最终都能当成 object 来看待==

通常用法: 1. 作为所有类型的公共父类型来理解 C# 类型系统 2. 在不知道具体类型时,临时用 object 接收数据 3. 理解为什么值类型可以被当成“对象”使用

核心理解: 1. 引用类型赋值给 object 时,通常只是==把引用当成 object 看待== 2. 值类型赋值给 object 时,会发生==装箱== 3. 所以“能放进 object”不代表底层过程都一样

案例:

string str = "hello";
object o1 = str; // 引用类型赋值给 object,不是装箱

int num = 10;
object o2 = num; // 值类型赋值给 object,发生装箱

为什么说 object 是万物之父

可以先这样记:

  • 类最终都继承自 object
  • 数组、委托等引用类型也都可以当成 object
  • 值类型虽然不是普通类,但最终也能通过装箱当成 object

所以从使用角度看:

  • ==所有类型最终都能统一到 object 这一层==

常见成员:

  1. ToString() 把对象转成字符串
  2. Equals(object obj) 比较两个对象是否相等
  3. GetType() 获取对象运行时类型
  4. GetHashCode() 获取哈希码
  5. ReferenceEquals(a, b) 判断两个引用是不是指向同一个对象

例子:

int num = 123;
object obj = num;

Console.WriteLine(obj.ToString());
Console.WriteLine(obj.GetType());
Console.WriteLine(obj.Equals(123));

补充:

  • ToString()Equals()GetType()GetHashCode() 是最常见的基础成员
  • ReferenceEqualsobject 提供的静态方法

装箱(Boxing

概念: 装箱就是==把值类型转换成 object 或它实现的接口类型== 运行时会把这个值==复制一份==,包装成一个对象放到托管堆上

通常用法: 1. 把值类型当成对象处理 2. 把值类型传给接收 object 的 API 3. 把值类型放进某些非泛型容器里

语法:

int num = 10;
object obj = num;      // 隐式装箱
object obj2 = (object)num; // 显式写法,但一般没必要

案例:

int a = 123;
object obj = a; // 装箱

a = 456;

Console.WriteLine(a);   // 456
Console.WriteLine(obj); // 123

理解: 装箱时放进 object 的,是当时那个值的一份副本 所以后面 a 变了,不会影响已经装箱进去的 obj

注意:

  1. ==装箱是值类型 -> object 或接口类型==
  2. 装箱会产生额外对象分配,通常比普通赋值更耗性能
  3. 引用类型赋值给 object 不叫装箱

拆箱(Unboxing

概念: 拆箱就是==把 object 里的值类型取出来,还原成原来的值类型== 拆箱是==显式转换==

语法:

object obj = 123; // 装箱
int num = (int)obj; // 拆箱

案例:

object obj = 100;
int num = (int)obj;
Console.WriteLine(num);

核心理解: 拆箱做的事不只是“强转一下” 它会先检查 obj 里面装着的是不是目标值类型 检查通过后,再把值复制出来

常见错误:

object obj = 10;
short s = (short)obj; // 报错

原因: obj 里装箱进去的真实类型是 int 拆箱时要求==类型先对上== 所以应该先拆成 int,再按需要继续转换

正确写法:

object obj = 10;
short s = (short)(int)obj;

再补一个坑:

object obj = null;
int num = (int)obj; // 运行时报错

注意:

  1. ==拆箱一定是显式的==
  2. ==拆箱时目标类型必须和装箱时的值类型匹配==
  3. null 拆箱会报错
  4. 类型不匹配时会抛出转换异常

object 和装箱拆箱的关系

最核心的一句话:

==值类型之所以也能被当成“对象”来处理,就是因为有装箱和拆箱==

对比理解:

int num = 10;
object o1 = num; // 装箱

string str = "hello";
object o2 = str; // 不是装箱,只是引用转换

所以要分清:

  1. 引用类型 -> object 通常只是“把它当父类看”
  2. 值类型 -> object 通常会真的发生装箱

性能和使用建议

为什么要注意装箱拆箱:

  1. 装箱会分配新对象
  2. 拆箱要做类型检查和复制
  3. 大量发生时,会增加 GC 压力和性能开销

常见容易发生装箱的场景:

  1. 使用非泛型集合,比如 ArrayList
  2. 方法参数写成 object
  3. 值类型转成接口类型时

示意:

ArrayList list = new ArrayList();
list.Add(1); // 装箱
list.Add(2); // 装箱

int num = (int)list[0]; // 拆箱

更推荐:

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

这样通常可以避免很多不必要的装箱拆箱。


一句话记忆

  1. ==object 是万物之父,所有类型最终都能统一到它这一层==
  2. ==值类型进 object 叫装箱,从 object 还原值类型叫拆箱==
  3. ==引用类型给 object 不等于装箱==

引用:

  1. Microsoft Learn: Built-in reference types - The object type
  2. Microsoft Learn: Boxing and Unboxing (C# Programming Guide)
  3. Microsoft Learn: Types - C# language specification
  4. Microsoft Learn: Object.GetType Method
  5. Microsoft Learn: System.Object.ToString method
  6. Microsoft Learn: System.Object.Equals method

#核心 #object #装箱拆箱