重用方法参数是不好的做法吗?


12

有时,我需要修改从方法本身内部传递到方法中的值。一个示例将在此处清除诸如此类的字符串:

void SanitizeName(string Name)
{
    Name = Name.ToUpper();

    //now do something here with name
}

这是完全无害的,因为该Name参数未通过引用传递。但是,如果由于某种原因,将来开发人员决定让ref传递所有值,则对字符串进行任何清理都会影响方法外部的值,这可能会带来不利的结果。

因此,我总是像这样创建本地副本,而不是重新分配参数本身:

void SanitizeName(string Name)
{
    var SanitizedName = Name.ToUpper();

    //now do something here with name
}

这样可以确保更改传递的值永远不会影响方法外的操作,但是我想知道我是否对此过于偏执。


1
是的,这是不好的做法;不,这不是无害的。这行Name = Name.ToUpper();代码使Name更改的价值更加难以理解。您的第二个示例不仅更具前瞻性,而且更容易推断其工作方式。
David Arno

2
但是呢if (param == NULL) param = default_value;
aragaer16年

我认为这不像是/否那么容易。
MrSmith42 '22

3
如果“将来的开发人员决定通过ref传递所有值”,那么我可能会对那个开发人员有一个参数,是否涉及参数重用;-)老实说,当一个人决定传递一个by ref未传递的值时,因此,出于某种原因将本地访问权转换为非本地访问权,他必须始终仔细检查后果。
布朗

2
我主要工作在一个范式中,我们从不重新分配任何变量。曾经 想象一个人在为是否应该重新分配一小部分变量而又不担心与其他变量混为一谈而感到困惑,这很有趣。
Karl Bielefeldt

Answers:


10

我认为这取决于您项目中的编码约定。

我个人让eclipse自动将final关键字添加到每个变量和参数中。这样一来,您就可以一眼看出是否重用了参数。

在我工作的项目中,我们不建议您重用参数,但是如果您只想调用例如.trim()或在某种null情况下设置默认值,则大多数情况下我们会重用参数,因为在这种情况下引入新变量的可读性较低而不是参数的重用。

您实际上不应该重用参数来存储完全不同的内容,因为名称将不再引用其内容。但这对每个变量的重新分配都是正确的,而不仅限于参数。

因此,与您的团队聚在一起,制定涵盖此问题的编码约定。


0

如果出于安全目的使用静态代码分析器,则可能会感到困惑,并认为您在使用之前尚未验证或清除输入参数变量。Name例如,如果在SQL查询中使用它,则可能声称存在SQL注入漏洞,这将使您花费大量时间进行解释。那很不好。另一方面,对已清理的输入使用一个单独命名的变量,而无需实际对输入进行清理,是使幼稚的代码分析器安静的一种快速方法(错误否定漏洞发现)。


在大多数情况下,您还可以使用某种注释或特殊注释来向代码分析器指示这是有意的,而不是未引起注意的风险。
MrSmith42 2016年

0

答案是100%取决于谁将阅读您的代码。他们觉得哪种风格最有帮助?

我发现最普遍的情况是避免将值重新分配给函数参数,因为太多的开发人员都对函数调用的工作原理有了心理模型,这些模型假定您从不执行此操作。调试器将打印您调用每个函数所使用的参数的值,可能会加剧此问题。如果您编辑参数,则此信息在技术上不正确,并且可能导致一些奇怪的挫败感。

话虽这么说,思维模式改变了。在您的特定开发环境中,可能希望name“此时是名称的最佳代表”。即使您一直在修改它们的值,也可能需要更明确地将您正在处理的变量链接到它们的参数。重用某些特定变量而不是创建更大的对象甚至可能在运行时具有很大的优势。毕竟,当您使用4GB字符串时,最好将您必须制作的额外副本的数量降至最低!


-1

我对您的代码示例有完全不同的问题:

您的方法名称为SanitizeName。在这种情况下,我希望它可以清除名称;因为这就是您告诉读者功能的内容。

您的功能应该做唯一一件事就是清理给定的名称。在不阅读您的代码的情况下,我期望以下几点:

string SanitizeName(string Name)
{
    //somehow sanitize the name
    return Result;
}

但是您暗示,您的方法所要做的不仅仅只是清理。那是代码的味道,应该避免。

您的问题不是关于:重用方法参数是不好的做法吗?重要的是:副作用和意外行为是否是不良做法?

答案很明显:是的!

由于Name参数未通过引用传递,因此这完全是无害的。但是,如果由于某种原因,将来开发人员决定通过ref传递所有值,则对字符串进行任何清理都会影响方法外的值,这可能会导致不利的结果。

您不返回任何内容就误导了读者。你的方法名清楚地表明,你正在的东西Name。那么,结果应该去哪里呢?通过您的函数签名void读取我使用的内容,Name但不会对id造成任何损害,也不会(明确地)告诉您结果。也许抛出了异常,也许没有。但Name没有改变。这是与方法名称相反的语义。

问题在于重用少于副作用。为避免产生副作用,请勿重用变量。如果您没有副作用,那就没有问题。


4
-1这不能回答原始问题。提供的代码只是用于显示当前问题的示例代码。请回答问题,而不是“攻击” /查看提供的示例代码。
Niklas H

1
@NiklasH这可以完美地回答问题:如果您在函数内部操作参数,并且正如TO所提到的,您不小心使用了引用而不是副本,则会产生副作用(如我所说),这很不好。为了防止这种情况,请指出您将通过仔细选择方法名称(考虑Ruby的“!”)和/或选择返回类型来更改变量。如果您不更改变量,则仅使用副本。
Thomas Junk 2016年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.