我可以修改一个已传递的方法参数吗?

13
我的直觉告诉我不应该做以下的事情。我没有收到任何关于此的警告。
void test(DateTime d)
{
 d = d.AddDays(2);
//do some thing with d
 }

或者这样更合适
 void test(DateTime d)
 {
 DateTime _d = d.AddDays(1);
//do some thing with _d
 }

出于某种原因,我总是像第二个例子那样处理传递的参数。 但我不确定这是否真的有必要...也许这只是多余的代码。
我并不认为调用方法会使用修改后的值。 有人有什么意见吗?
3个回答

25

除非参数是 refout 参数,否则对于参数的值的更改对调用者不可见。

如果您更改由参数引用的引用类型对象,则情况并非如此。例如:

public void Foo(StringBuilder b)
{
    // Changes the value of the parameter (b) - not seen by caller
    b = new StringBuilder();
}

public void Bar(StringBuilder b)
{
    // Changes the contents of the StringBuilder referred to by b's value -
    // this will be seen by the caller
    b.Append("Hello");
}

最后,如果参数通过引用传递,那么更改 就会 被看到:

public void Baz(ref StringBuilder b)
{
    // This change *will* be seen
    b = new StringBuilder();
}

了解更多信息,请参阅我的有关参数传递的文章


5
您可以更改它,但更改不会返回给调用者。
如果是值类型 -> 发送对象的副本
如果是引用类型 -> 将通过值发送对象引用的副本。以这种方式可以更改对象的属性,但不能更改引用本身 - 调用方无论如何都看不到更改。
如果发送 ref -> 可以更改引用。
在C++中,您可以使用const来防止更改,但C#没有这个。这只是为了防止程序员错误地尝试更改它 - 具体取决于const的使用位置。

那要看具体情况。在这个非常特定的例子中,由于DateTime是一个结构体,并具有值语义,所以是真的。其他参数,具有引用语义的,会将该更改反映回调用者。 - Harper Shelby
@Harper:如果原始问题中更改参数的值,而不是更改由参数值引用的对象,则不会发生这种情况。请参阅我的答案,了解这两者之间的区别示例。 - Jon Skeet
@Harper,foo = ... 只有在特定的 ref(或 out)参数时才会反映在结构体或类的调用站点上。您对引用类型成员所做的更改将会反映出来,但您对引用本身所做的更改则不会。 - Anthony Pegram
@Jon Skeet:好的,我去掉了第三个选项。人们认为C++很令人困惑! - Harper Shelby

0

如果您想要访问原始值,请使用第二种方法。

如果您不关心原始值,您可以使用任何一种方法(但我可能仍然会使用第二种方法)。

无论哪种方式,您都不会损害其他人的值(即使重新分配值,它也不会返回给调用者)。


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