C#中的ref和out:新手常犯的5大错误及如何避免

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

C#中的ref和out:你必须赢下的修饰符之战

\n\n

如果你曾经用C#编写过需要返回两个或三个值而不是一个值的代码,你肯定遇到过ref和out关键字。乍一看,它们似乎在做同一件事——允许方法修改传入的变量。但魔鬼,一如既往,藏在细节中。在Stack Overflow上,问题"'ref'和'out'关键字有什么区别?"已经获得了数十万次浏览。为什么?因为混淆它们是最常见的新手陷阱之一(即使是经验丰富的开发者在快速编写代码时也会中招)。

\n\n

在这篇文章中,我们不会仅仅列出枯燥的定义。我们将分析开发人员在使用ref和out时犯下的5大真实错误,并展示如何避免它们。你将了解何时使用每个修饰符,以及为什么out不仅仅是“懒惰的ref”。我们开始吧!

\n\n

快速了解核心:ref和out的理念

\n\n

想象一下你给朋友寄一个包裹。ref就像你给了朋友一把你公寓的钥匙,并说:“拿走我的东西,你可以修改它,但要放回原处。”朋友必须从你这里拿到钥匙(变量必须在调用前初始化)。

\n\n

out就像你说:“这是一个空盒子,往里面装点东西然后还给我。”你给朋友一个空容器,他必须把它装满。你不必事先在里面放任何东西。

\n\n

这是主要区别:ref要求变量在传递前已初始化,而out允许传递未初始化的变量,但保证方法会为其赋值。

\n\n

错误#1:混淆初始化

\n\n

最常见的失误。开发人员试图将已初始化的变量传递给out——这不是错误,但失去了意义。或者,反过来,将未初始化的变量传递给ref——然后收到编译错误。

\n\n

代码示例(错误):

\n
public void Process(ref int x)\n{\n    x = x * 2;\n}\n\n// 使用\nint number; // 错误!变量未初始化\nProcess(ref number); // CS0165: 使用了未赋值的局部变量"number"\n
\n\n

正确做法:

\n
int number = 10; // 必须初始化\nProcess(ref number);\nConsole.WriteLine(number); // 20\n
\n\n

使用out的示例(正确):

\n
public void Initialize(out int value)\n{\n    value = 42; // 必须赋值\n}\n\nint result; // 可以不初始化!\nInitialize(out result);\nConsole.WriteLine(result); // 42\n
\n\n

结论:如果需要修改现有值——使用ref。如果方法应该“从零开始”创建一个新值——使用out。

\n\n

错误#2:忘记给out参数赋值

\n\n

C#编译器很严格:如果你将参数声明为out,你必须在退出方法前(在所有代码路径中)为其赋值。这不是一个bug,而是一个特性,可以保护你免受未定义行为的影响。

\n\n

代码示例(错误):

\n
public bool TryParse(string input, out int result)\n{\n    if (int.TryParse(input, out result))\n    {\n        return true;\n    }\n    // 忘记在失败情况下给result赋值!\n    // 编译器会报错:CS0177\n    return false;\n}\n
\n\n

正确做法:

\n
public bool TryParseSafe(string input, out int result)\n{\n    if (int.TryParse(input, out var parsed))\n    {\n        result = parsed;\n        return true;\n    }\n    result = 0; // 始终赋值\n    return false;\n}\n
\n\n

建议

博客

书籍推荐