Skip to main content

ref与out

在C#中,refout都是用于按引用传递参数的关键字,允许方法内部修改外部变量的值,但它们在使用场景和语义上有显著区别。


核心概念

ref(引用传递)

  • 用于双向传参,既可将外部变量的值传入方法,也可将方法内的修改带回调用方。
  • 调用前必须初始化变量,否则编译错误。
  • 方法内部可修改或不修改参数值。

out(输出参数)

  • 用于单向输出,主要目的是让方法返回多个值。
  • 调用前无需初始化变量,但方法内部必须赋值,否则编译错误。
  • 进入方法时参数值会被清空,即使外部已赋值也会被忽略。

适用场景

  • ref:适用于需要传入并修改外部变量的场景,如交换、增量更新。
  • out:适用于纯输出场景,如解析、多返回值方法。
  • 口诀ref有进有出,out只出不进。

主要区别

特性refout
初始化要求调用前必须初始化变量调用前无需初始化
方法内赋值要求可不赋值(保留原值)必须赋值(否则编译错误)
语义“修改现有值”“输出新值”
编译器验证不强制检查内部赋值强制要求方法内赋值
典型场景交换变量值、大型结构体高效修改返回多个值(如TryParse模式)

代码示例

ref示例(变量交换)

void Swap(ref int a, ref int b) {
int temp = a;
a = b;
b = temp;
}

int x = 10, y = 20;
Swap(ref x, ref y); // x=20, y=10
  • 关键点xy必须提前初始化。

out示例(返回多个值)

void Divide(int dividend, int divisor, out int quotient, out int remainder) {
quotient = dividend / divisor;
remainder = dividend % divisor;
}

int q, r;
Divide(10, 3, out q, out r); // q=3, r=1
  • 关键点qr无需初始化,但方法内必须赋值。

注意事项

  1. 重载冲突
  • 不能仅通过refout区分重载方法,因为编译器视二者为相同签名。
void Method(ref int i) { }  // 编译错误:与下方法冲突
void Method(out int i) { i = 0; }
  1. 属性限制
  • 属性(Property)不能作为refout参数传递,因为它们不是变量。
  1. 性能考虑
  • ref适合避免大型值类型(如结构体)的复制开销;out适合多返回值场景。