引用类型传参传递的是引用的副本,可修改对象属性但不能改变外部变量指向;ref允许替换原引用,out要求方法初始化新对象;string因不可变性行为类似值类型。

引用类型本身在传参时传递的是“引用的副本”,不是对象本身,也不是值的副本。这意味着你能在方法内修改对象的属性,但不能让外部变量指向新对象——除非用 ref 或 out 显式改变变量本身的引用。
引用类型默认传参:改内容,不改引用
调用方法时,类实例(如 Person、List<T>)作为参数传入,实际传递的是该引用的一个拷贝。这个拷贝和原始变量指向同一块堆内存,因此:
- 可以修改对象内部状态(比如
person.Name = "张三"、list.Add(10)),外部可见 - 但若在方法内重新赋值(如
person = new Person()或list = new List<int>()),只会影响参数副本,不影响原始变量
这就是为什么常见误区是“引用类型就是引用传递”——它只是共享对象,不是共享变量。
用 ref 强制替换引用本身
当你需要让方法彻底接管变量的指向(比如替换整个集合、切换实体实例),就得用 ref:
- 调用前必须初始化(哪怕只是
var p = new Person();) - 方法内可读原引用、也可赋新对象:
person = new Person { Name = "李四" }; - 调用后,原始变量将指向新对象
典型场景:工厂方法返回新实例并覆盖旧引用;或需在多个分支中动态替换不同子类实例。
用 out 专注构造与初始化
out 对引用类型同样适用,语义更明确:调用方不关心初始值,方法负责“给一个全新的对象”:
- 允许传未赋值变量:
Person p; CreatePerson(out p); - 方法内必须且只能赋一次值:
p = new Person();(不能读p.Name,因它可能为 null) - 适合封装对象创建逻辑,尤其配合 Try-模式(如
TryCreateConfig(out Config cfg))
string 是特例:不可变引用类型
string 虽属引用类型,但因不可变性,行为接近值类型:
- 默认传参时,
s = "new"实际是新建字符串并让参数副本指向它,原变量不变 - 要用
ref string才能让外部变量指向新字符串 -
out string常用于解析场景(如从日志行提取多个字段),强调“输出结果”,不依赖输入值
本质上,string 的特殊性源于其设计契约,而非语法例外——所有引用类型的语义规则依然成立,只是它的“内容不可改”放大了引用替换的必要性。

















