在方法内更改参数值,这是一种反模式吗?

13

所以就像这样

public void MyMethod(object parameter)
//....
    BuildSomething(parameter);
    BuildLayers(parameter);
    BuildOtherStuff(parameter);
}

public void BuildSomething(object parameter)
{
//...
    parameter.SomeProperty = "sadsd";
//...
}

如果这是一个反模式,它叫什么名字?
问题(可能)在于您正在隐式更改 参数 并使用更改后的值。
我只想知道这个反模式称为什么

谢谢


3
只要方法名能够清楚表达其功能,我认为这样就可以了。 - sll
@sll 这就是它的缺陷所在。它要么没有说明它的功能,要么方法名字太长像BuildSomethingwithLayersBuiltFromOtherStuff。 - Tony Hopkinson
3个回答

21

这是一个副作用

通常情况下,这些都不是好的编程实践,被认为是代码异味,因为它使得代码难以理解和推理。

然而,这种模式有时会很有用。

C#将refout关键字规范化,特别是为了表明该方法具有副作用。


4
@knaki02 我不这么认为... 定义非常清楚:如果一个函数或表达式除了返回值之外,还修改了某些状态或与调用函数或外部世界有可观察的交互作用,则称其具有副作用。 - Leonardo
据我所见,参数的改变是与外部世界发生可观察交互的事实。 - roundcrisis
1
除了返回值之外,还有什么其他的?void方法不会返回任何值。 - knaki02
5
这是一种副作用,因为它改变了参数,并且并不清楚这是否是该方法的本意。不要管一些学者所说的,void DoSomethingTo(arg) 并不等同于 DoSomethingWith(arg)。 - Tony Hopkinson
返回void结果并不意味着副作用,就像非void返回类型并不意味着纯度一样。只是碰巧void只包含一个值(NULL),因此它不包含运行时信息(不像布尔值包含1位)。传递void的一个有用场景是实现一个参数化类型的接口(即使用存在类型)。例如,我们的接口可能以“Config”类型为参数,并要求我们实现一个函数“getConfig:void-> Config”;如果我们的实现不可配置,我们可以使用void作为Config。 - Warbo
理论上讲,void是一种返回值。它的类型只包含一个值,并且类似于F#中的unit。但在C#中,你不能将其赋值给任何东西。从纯函数的角度来看,返回void的方法没有意义或者说非常无聊,相当于没有代码。只有当它具有某些副作用时才有用。正如这个答案所表明的那样,副作用可能很棘手,它们是命令式代码在不知道整个系统或大部分系统的情况下难以跟踪的原因之一。 - sara

0

我有不同的观点。

尽管更改参数值可能会在调试过程或代码可读性方面引入一些小问题,但我认为将这种做法称为“反模式”是没有意义的。

基于像Java或C#这样的现代OO语言设计,我支持这样一个想法:如果更改参数值是丑陋的、错误的或不可推荐的,那么它们应该定义类型参数为实例的副本,而不是引用

并且我不同意Oded所说的,我认为refout关键字只应在您真正想要完全替换整个实例值的情况下使用。仅仅使用其中一个关键字告诉“嘿,伙计,执行堆栈中的参数值可能会发生变化”对我来说听起来有点粗心。如果您的客户之一看到函数签名并真正相信他可以替换整个东西呢?(在不期望的行为情况下)。


根据操作者的示例,我更愿意看到基于ref或out的MyObject DoSomethingWith(MyObject oldObj);因为这样会更清晰。作为一个维护编码人员,我讨厌副作用。如果它是一个out或ref,他们可以替换整个东西,他们知道,代码应该能够处理。在我的经验中,不相信方法会改变参数是一个更大的问题,它只应该改变传递给它的参数类。 - Tony Hopkinson
这让我感觉到教条主义和装神弄鬼。http://en.wikipedia.org/wiki/Argument_from_authority - Warbo

0
假设parameter的类型不是真正的object,而是一个包含可写属性或字段SomeProperty的类类型,那么当方法进入时,parameter的值将是某个对象的标识(比如说,自程序开始以来创建的第459,192个对象)。据我所知,该参数的值(指它所引用的对象的标识)在整个方法中将保持不变。
改变传入参数的值(例如说parameter = someOtherObject)可能是一种代码异味,除非该方法足够小,以至于很明显发生了什么。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接