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

225 lines
5.9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 万物之父和装箱与拆箱
# object
概念:
`object``System.Object` 的别名
在 C# 的统一类型系统里,可以把它理解成==万物之父==
因为==所有类型最终都能当成 `object` 来看待==
通常用法:
1. 作为所有类型的公共父类型来理解 C# 类型系统
2. 在不知道具体类型时,临时用 `object` 接收数据
3. 理解为什么值类型可以被当成“对象”使用
核心理解:
1. 引用类型赋值给 `object` 时,通常只是==把引用当成 `object` 看待==
2. 值类型赋值给 `object` 时,会发生==装箱==
3. 所以“能放进 `object`”不代表底层过程都一样
案例:
```csharp
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)`
判断两个引用是不是指向同一个对象
例子:
```csharp
int num = 123;
object obj = num;
Console.WriteLine(obj.ToString());
Console.WriteLine(obj.GetType());
Console.WriteLine(obj.Equals(123));
```
补充:
- `ToString()``Equals()``GetType()``GetHashCode()` 是最常见的基础成员
- `ReferenceEquals``object` 提供的静态方法
----
# 装箱(Boxing
概念:
装箱就是==把值类型转换成 `object` 或它实现的接口类型==
运行时会把这个值==复制一份==,包装成一个对象放到托管堆上
通常用法:
1. 把值类型当成对象处理
2. 把值类型传给接收 `object` 的 API
3. 把值类型放进某些非泛型容器里
语法:
```csharp
int num = 10;
object obj = num; // 隐式装箱
object obj2 = (object)num; // 显式写法,但一般没必要
```
案例:
```csharp
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` 里的值类型取出来,还原成原来的值类型==
拆箱是==显式转换==
语法:
```csharp
object obj = 123; // 装箱
int num = (int)obj; // 拆箱
```
案例:
```csharp
object obj = 100;
int num = (int)obj;
Console.WriteLine(num);
```
核心理解:
拆箱做的事不只是“强转一下”
它会先检查 `obj` 里面装着的是不是目标值类型
检查通过后,再把值复制出来
常见错误:
```csharp
object obj = 10;
short s = (short)obj; // 报错
```
原因:
`obj` 里装箱进去的真实类型是 `int`
拆箱时要求==类型先对上==
所以应该先拆成 `int`,再按需要继续转换
正确写法:
```csharp
object obj = 10;
short s = (short)(int)obj;
```
再补一个坑:
```csharp
object obj = null;
int num = (int)obj; // 运行时报错
```
注意:
1. ==拆箱一定是显式的==
2. ==拆箱时目标类型必须和装箱时的值类型匹配==
3.`null` 拆箱会报错
4. 类型不匹配时会抛出转换异常
----
# object 和装箱拆箱的关系
最核心的一句话:
==值类型之所以也能被当成“对象”来处理,就是因为有装箱和拆箱==
对比理解:
```csharp
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. 值类型转成接口类型时
示意:
```csharp
ArrayList list = new ArrayList();
list.Add(1); // 装箱
list.Add(2); // 装箱
int num = (int)list[0]; // 拆箱
```
更推荐:
```csharp
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](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/reference-types)
2. Microsoft Learn: [Boxing and Unboxing (C# Programming Guide)](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/types/boxing-and-unboxing)
3. Microsoft Learn: [Types - C# language specification](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/types)
4. Microsoft Learn: [Object.GetType Method](https://learn.microsoft.com/en-us/dotnet/api/system.object.gettype)
5. Microsoft Learn: [System.Object.ToString method](https://learn.microsoft.com/en-us/dotnet/fundamentals/runtime-libraries/system-object-tostring)
6. Microsoft Learn: [System.Object.Equals method](https://learn.microsoft.com/en-us/dotnet/fundamentals/runtime-libraries/system-object-equals)
#核心
#object
#装箱拆箱