为什么.NET中的'out'参数是个坏主意?

时间:2008-09-25 15:38:38

标签: .net

为什么.NET中的'out'参数不是一个好主意?

我最近被问过这个,但我没有真正的答案,除了它只是不必要地使应用程序复杂化。还有其他什么原因?

22 个答案:

答案 0 :(得分:60)

嗯,我认为这不是一个坏主意。 Dictionary<K, V>有一个TryGetValue方法,这是一个很好的例子,为什么输出参数有时是一件非常好的事情。

当然,你不应该过度使用这个功能,但根据定义,这不是一个坏主意。特别是在C#中,您必须在函数声明调用中记下out关键字,这使得它显而易见。

答案 1 :(得分:18)

他们是个好主意。因为有时您只想从一个方法返回多个变量,并且您不希望为此创建“重”类结构。包装类结构可以隐藏信息流的方式。

我用它来:

  • 通过一次通话返回密钥和IV数据
  • 将人名拆分为不同的实体(名字,中间名,姓名)
  • 拆分地址

答案 2 :(得分:14)

如果你关心通过采用不变性和消除副作用来编写可靠的代码,那么输出参数是一个绝对可怕的想法。它会强制您创建可变变量来处理它们。 (并不是C#支持只读方法级别的变量(至少在我使用的版本中,3.5))。

其次,它们通过强制开发人员设置和处理接收out值的变量来减少函数的组合性。这是令人讨厌的仪式。你不能只是轻松地使用它们来编写表达式。因此,调用这些函数的代码很快变成了一个大的命令性混乱,提供了许多隐藏错误的地方。

答案 3 :(得分:6)

Out - 参数在我看来是个坏主意。它们增加了副作用的风险并且难以调试。唯一好的解决方案是函数结果,这就是问题:对于函数结果,您必须为每个复杂结果创建元组或新类型。现在在c#中应该相当容易,使用匿名类型和泛型。

顺便说一句:我也讨厌副作用。

答案 4 :(得分:5)

问题的措辞是of the "Have you stopped hitting your wife?" variety - 它假设 out 参数一定是个坏主意。有些情况可能会滥用 out 参数,但是......

  • 它们实际上非常适合C#语言。它们类似于 ref 参数,除了保证方法为其赋值并且调用者不需要初始化变量。

  • 函数的正常返回值被推送到调用和退出它们的堆栈。当您提供 out 参数时,您将为该方法提供特定的内存地址以保留结果。这也允许多个返回值,但使用结构通常更有意义。

  • 它们非常适合TryParse模式,还提供其他内容的元数据,例如SQL-CLR,其中 out 参数映射到 out 参数存储过程签名。

答案 5 :(得分:4)

我会说你的回答是正确的;它通常是不必要的复杂功能,而且通常设计更简单。您在.NET中使用的大多数方法都不会改变它们的输入参数,因此使用一种使用语法的一次性方法有点令人困惑。代码变得不那么直观,并且在文档记录不佳的情况下,我们无法知道方法对输入参数的作用。

此外,带有out参数的方法签名将触发Code Analysis / FxCop违规,如果这是您关心的指标。在大多数的情况下,有一种更好的方法来实现使用“out”参数的方法的意图,并且可以重构该方法以返回有趣的信息。

答案 6 :(得分:4)

使用参数并不总是一个坏主意。通常对于尝试基于某种形式的输入创建对象的代码,提供带有out参数和布尔返回值的 Try 方法是个好主意,而不是强制方法使用者包装try catch全部阻止,更不用说更好的性能。 例如:

bool TryGetSomeValue(out SomeValue value, [...]);

这是一个外部参数是一个很好的想法的情况。

另一种情况是您希望避免在方法之间传递代价高昂的大型结构。 例如:

void CreateNullProjectionMatrix(out Matrix matrix);

此版本避免了昂贵的结构复制。

但是,除非出于特定原因需要外出,否则应该避免。

答案 7 :(得分:3)

嗯,没有明确的答案,但out参数的简单用例是“Int.TryParse(”1“,out myInt)”

XXX.TrayParse方法作业是,它将某种类型的值转换为另一种类型,它返回一个布尔标志来指示转换成功或失败,这是另一部分转换后的值的一部分,由该方法中的out参数携带。

这个TryParse方法是在.NET 2.0中引入的,以便克服这样一个事实:如果转换失败,XXX.Parse将通过异常,你必须在语句中放入try / catch。

所以基本上它取决于你的方法正在做什么,以及调用者期望的方法,如果你正在做一个返回某种形式的响应代码的方法,那么out参数可以用来执行方法返回的结果。

无论如何,微软在其设计指南中说“避免使用参数”,请查看这个msdn页面 http://msdn.microsoft.com/en-us/library/ms182131(VS.80).aspx

答案 8 :(得分:2)

我说我避免它的理由是因为最简单的方法是处理数据并返回一个逻辑数据。如果需要返回更多数据,它可能是进一步抽象或返回值形式化的候选者。

一个例外是如果返回的数据有些高级,比如可以为空的bool。它可以是真/假或未定义。 out参数可以帮助解决其他逻辑类型的类似想法。

我有时使用的另一个是当你需要通过一个不允许“更好”方法的界面获取信息时。比如使用.Net数据访问库和ORM。当您需要返回更新的对象图(在UPDATE之后)或新的RDBMS生成的标识符(INSERT)以及该语句影响了多少行时。 SQL在一个语句中返回所有这些,因此对方法的多次调用将不起作用,因为您的数据层,库或ORM仅调用一个通用INSERT / UPDATE命令,并且无法存储值以供以后检索。

从不使用动态参数列表或输出参数等理想做法并不总是实用的。再次,如果一个out参数是真正正确的方法,那么请三思而后行。如果是这样,那就去吧。 (但请务必记录好!)

答案 9 :(得分:2)

我不认为他们是。滥用它们是一个坏主意,但这适用于任何编码实践/技术。

答案 10 :(得分:1)

我不得不同意GateKiller。如果微软将它们用作基础库的一部分,我无法想象参数太糟糕了。但是,就像所有事情一样,最好适度。

答案 11 :(得分:1)

就像Tanqueray的家伙喜欢说的那样 - 一切都在适度。

我绝对会强调过度使用,因为它会导致“在c#中编写c”,就像用Python编写java一样(你不会接受使新语言变得特殊的模式和习语) ,而只是用你的旧语言思考并转换为新的语法)。尽管如此,如果它能帮助你的代码变得更优雅,更有意义,那就一定会熄灭。

答案 12 :(得分:1)

它们只是破坏了方法/函数的语义。一个方法通常应该采取一堆东西,并吐出一个东西。至少,这就是大多数程序员的想法(我想)。

答案 13 :(得分:1)

'out'很棒!

它生成一个清除语句,该参数包含该方法返回的值。

编译器还强制你初始化它(如果我们用作返回参数,它应该被初始化)。

答案 14 :(得分:0)

我认为主要原因是&#34; ...虽然返回值很常见且使用频繁,但正确应用 out ref参数需要中级设计和编码技巧。为普通观众设计的图书馆建筑师不应期望用户使用out或ref参数来掌握工作。&#34;

请参阅:http://msdn.microsoft.com/en-us/library/ms182131.aspx

了解详情

答案 15 :(得分:0)

无论如何,out变量都不错,如果我们需要从一个函数返回多个(特别是2个)变量,那么用完它确实是一件很酷的事情。有时,仅出于返回2个变量的目的而创建自定义对象的工作非常繁琐,这是最终的解决方案。

答案 16 :(得分:0)

.NET之外的某些语言将它们用作无用的宏,只是为程序员提供有关如何在函数中使用参数的信息。

答案 17 :(得分:0)

我没有看到提到的一点是out关键字也要求调用者指定输出。这很重要,因为它有助于确保调用者理解调用此函数将修改其变量。

这就是为什么我从不喜欢在C ++中使用引用作为out参数的原因之一。调用者可以轻松调用方法,而无需知道他的参数将被修改。

答案 18 :(得分:0)

我会说你给出的答案是关于最好的答案。如果可能的话,你应该总是设计远离out参数,因为它通常会使代码变得不必要复杂。

但几乎任何模式都是如此。如果不需要,请不要使用它。

答案 19 :(得分:0)

我认为在某些情况下它们是个好主意,因为它们允许从函数返回多个对象,例如:

DateTime NewDate = new DateTime();
if (DateTime.TryParse(UserInput, out NewDate) == false) {
    NewDate = DateTime.Now;
}

非常有用:)

答案 20 :(得分:0)

out关键字是必要的(请参阅SortedDictionart.TryGetValue)。它意味着通过引用传递,并告诉编译器以下内容:

int value;
some_function (out value);

没问题且some_function没有使用通常会出错的单位化值。

答案 21 :(得分:0)

我不认为有一个真正的原因,虽然我没有看到它经常使用(除了P/Invoke电话)。