按引用传递参数:哪种方式更易读/正确?

9

我有以下的类:

public class Person
{
     public String Name { get; set; }
}

我有一个方法,它接受PersonString作为参数:
public void ChangeName(Person p, String name)
{
     p.Name = name;
}

由于Person是通过引用传递的,因此它应该更改传递实例的Name

但是,这种方法是否比上面的方法更易读?

public Person ChangeName(Person p, String name)
{
     p.Name = name;
     return p;
}

1
从技术上讲,在这些例子中,p 没有被传递为引用。 - Amber
@Amber 怎么会呢?我非常确定那完全是错误的。 - Corey Sunwold
3
p 包含并传递了一个引用,但它不是“按引用传递” - 这两者之间有明显的区别。通过按引用传递(通过将参数声明为 ChangeName(ref Person p, ...)),可以允许像 p = foo 这样的语句完全改变调用者变量所指向的 Person,而不仅仅是当前指向的 Person 的内容。 - Amber
更多详细信息,请参见http://msdn.microsoft.com/en-us/library/0f66670z(v=vs.71).aspx的示例#4和#5。 - Amber
@Amber - 对的。对的。我搞砸了。 - Ritch Melton
8个回答

12

这样更易读吗?不是的。实际上,你可能会对它造成更多的伤害而不是好处。

通过返回一个Person对象,可能会让你认为它并没有修改传入的Person参数,而是基于p创建了一个新的Person对象,并更改了名称,这会导致某些人错误地认为p从未被修改。

无论如何,如果一个方法对其所属的类没有影响,那么它应该成为静态方法。这有助于你确信它不会影响其所在的类。只有在需要返回值时才让方法返回值。

所以,这是我对这个方法的建议:

public static void ChangeName(Person p, String name)
{
    p.Name = name;
}

1
我建议您使用以下其中一种以获得最佳可读性:
public static void ChangeName(Person p, String name)
{
    p.Name = name;
}

public static Person WithName(Person p, String name)
{
    return new Person(p) { Name = name };    
}

第二个方法将Person对象视为不可变的,并且不改变对象的状态。ChangeName函数显式地更改了输入对象的状态。我认为清楚区分这两种类型的方法非常重要。遵循的一个好的经验法则是,一个方法不应该同时改变对象的状态并返回一个对象。

1

这两种方法都没有对错之分。取决于你的程序需要什么。

很少需要返回传递给方法的参数,因为用户始终可以直接使用作为参数传递的变量。

然而,它为您提供了灵活性,以最终覆盖此实现,或将此实现传递到另一个接受具有类似签名的委托的函数中。然后,您可以传递其他不返回相同Person对象的实现。

只有在真正需要灵活性时才这样做。


1
首先,在第一个示例中,p并没有通过引用传递。你的第二种方法让人们相信它返回了一个新的引用,但实际上并不是这样。因此,我认为第二种方法并不比第一种更清晰。

0

我认为你的第二种方法不如YAGNI易读。但是如果你像这样改变它

public static class PersonExtensions 
{
public static Person ChangeName(this Person p, String name)
{
 p.Name = name;
 return p;
}

您将拥有一个针对流畅接口的扩展方法,类似于:

extensionmethod

new Person().ChangeName("Peter Smith").SendEmail().Subject("Test Mail").Receiver("....)

0

这里是理解按值/引用传递参数的权威参考。

看看代码,为什么不使用属性呢?

public string Name
{
   set {name = value;}
   get { return name; }
}

编辑:自动实现属性

public string Name
{
   set;
   get;
}

0
在你所描述的情况下,我会说都不需要。这个方法的作用并不是很清楚。只需使用对象并设置属性即可。将一个方法插入执行路径只会使理解变得更加复杂,并且会在 Person 对象及其基础值上创建另一个依赖项。
如果你正在问一个涉及代码设计之外的元问题,那么我可能没有理解到。

0
第一个更好,因为第二个可能会让你误以为p是不可变的。 但是,整个方法都是无用的,因为它只是调用了setter。为什么不直接调用setter呢?

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