# 万物之父和装箱与拆箱
# 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
#装箱拆箱
