C#之ref与out
一句话总结:ref传入前必须赋值(读+写),out传入前不需要赋值(只写)。
最直观对比
1 | void Foo(ref int x) |
调用时:
1 | int a = 5; |
本质都是引用传递
默认的参数传递:void test(int x)传的是值(拷贝)
而 ref / out :void Test(ref int x)传的是变量本身(地址/引用)
1 | 普通参数: |
ref篇
必须初始化、方法中可读可改、传入的是已有变量
1 | using System; |
直接修改原变量
为什么必须初始化?因为方法里可能会读取它 x += 10; // 先读再写 如果没初始化,就是未定义行为
out篇
不需要初始化、方法内必须赋值、用来“返回多个值”
1 | void GetValues(out int x, out int y) |
调用
1 | int a, b; |
为什么必须在方法里赋值?因为调用方没给初始值:
1 | int a; // 未初始化 |
如果方法不赋值 → a 还是垃圾
典型场景:int.TryParse("123", out int result);
若成功,则result有值,失败则 result = 0
例:
1 | void Divide(int dividend, int divisor, out int quotient, out int remainder) { |
q 和 r 无需初始化,但方法内必须赋值
对比
| 特性 | ref | out |
|---|---|---|
| 是否必须初始化 | ✅ 必须 | ❌ 不需要 |
| 方法内是否必须赋值 | ❌ | ✅ 必须 |
| 是否可读 | ✅ | ⚠️(必须先赋值后才能读) |
| 语义 | 输入 + 输出 | 只输出 |
| 常见用途 | 修改变量 | 返回多个值 |
ref 和 out 本质都是: 传地址
区别只是:
编译器的规则约束不同
out 多一个“必须赋值检查”
此外,不能通过ref与out区分重载方法,因为二者视为相同签名
1 | void func(ref int i){} // 会编译错误 |
ref适合大型结构体的复制开销,out适合多返回值场景。