修改作为参数传递到修改类中的对象的正确方法

The correct way to modify an object that is being passed as a parameter into the modifying class

提问人:BrightonDev 提问时间:9/27/2012 最后编辑:one noaBrightonDev 更新时间:11/15/2023 访问量:821

问:

以下 2 条建议中,修改由接受该对象作为参数的类修改的对象上的属性的最佳方法是什么?

  1. 让类对对象进行处理,并返回一个值,然后将该值分配给该对象

或。

  1. 使用 ref 关键字传递对象,并让类在不实际返回任何内容的情况下修改对象。

例如,我有一个 Person 对象,其中包含“名字”和“姓氏”以及 2 种不同的创建全名的方法。

哪个是最好的方法?

public static void Main()
{
    Person a = new Person {  FirstName = "John", LastName = "Smith" };
    Person b = new Person { FirstName = "John", LastName = "Smith" };

    NameProcesser np = new NameProcesser();

    // Example A
    a.FullName = np.CreateFullNameA(a);

    // Example B
    np.CreateFullNameB(ref b);
}

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string FullName { get; set; }
}


public class NameProcesser
{
    public string CreateFullNameA(Person person)
    {
        return person.FirstName + " " + person.LastName;
    }

    public void CreateFullNameB(ref Person person)
    {
        person.FullName = person.FirstName + " " + person.LastName;
    }
}
C# 参数传递 引用

评论


答:

0赞 Dave Doknjas 9/27/2012 #1

两者都不需要 - 你也不需要 'ref' - 只需使用:

public void CreateFullNameB(Person person) 
{ 
    person.FullName = person.FirstName + " " + person.LastName; 
} 
3赞 Robert Harvey 9/27/2012 #2

你不需要 .只需修改方法中的对象即可。ref

当引用类型作为参数传递时,它是“按引用”传递的,而不是按值传递的。因此,当你修改它时,你实际上是在修改原始对象。仅当传递值类型(如 .refint

我在引号中说“通过引用”,因为实际发生的事情是指向原始对象的内部“指针”正在通过值传递。

评论

0赞 BrightonDev 9/27/2012
感谢您的快速回复罗伯特。我明白你说不需要 Ref 的意思了。因此,在修改类中修改对象比返回字符串然后修改对象更可取。
0赞 BrightonDev 9/27/2012
请参阅我的评论以打耳光。这只是一个例子。在我的实际代码中,该对象将具有一个属性,其值取决于 Web 服务调用和其他处理代码,因此 getter 不适合。
0赞 Robert Harvey 9/27/2012
@RuneFS:是的,这有点奇怪。我只是不想被那些在每天早餐时阅读 C# 规范的人打耳光。
0赞 STO 9/27/2012 #3

首先,将该方法分成其他类的唯一原因是该方法是否具有数据库或网络访问等依赖项。否则,这个简单的方法应该是类的属性。Person

此外,将整个对象传递给方法的唯一原因是当对象数据在该方法中被广泛使用时。否则,最好将 FirstName 和 LastName 作为参数传递并返回结果。

类不需要使用 modifier 传递来修改其内容。仅当方法想要将参数与对新实例的引用一起分配时,才需要 ref。ref

在示例中,您描述了如果从两个选项中进行选择,则返回值会更好,因为它可以减少耦合并将逻辑与数据表示分开。但是,如果一个实体的属性很少可以更新,那么传递对象会更好。

评论

0赞 Rune FS 9/27/2012
将 and object 作为参数而不是类传递
0赞 BrightonDev 9/27/2012
嗨,STO,是的,修改方法确实具有依赖关系,并且需要对象中的多个值。
0赞 STO 9/27/2012
很好,所以它有依赖关系,那么它是分离的方法,而不是 Person 类的一部分。是否可以在不了解以下信息的情况下应用项目方法的业务逻辑:如果是,那么您可能不应该使用 Person 作为参数。然后结果 - 结果可以在 Person 类之外使用 - 如果是,返回标量值可能更好,否则您可以更新作为参数传递的 person。Person
0赞 BrightonDev 9/27/2012
嗨,STO,是的,我明白你的意思。谢谢。
1赞 s.m. 9/27/2012 #4

第一件事

你提到的事实表明你错过了一个基本概念;也就是说,根据定义,可以访问对对象的引用的代码可以访问实际对象。ref

使用参数的唯一可能使用方案是,当您要将该引用设置为其他对象或 .refnull

如果你不使用(甚至就此而言,请参阅此处的区别),您实际上是在按值传递您的参数,这意味着创建了它的副本。refout

这意味着两件事,具体取决于参数是类型(如 int、long、float 等)还是引用类型(引用任何类的实例)。

如果参数是值类型,则将创建该参数的副本。然后,您的方法可以执行任何它想要的事情,因为副本仅限于该方法的作用域。

但是,如果参数是引用类型(就像您的参数一样),则只会复制引用本身:基础对象是相同的。这就是最大的区别所在。但是请记住,您在方法中可用的引用仍然是原始引用的副本,这意味着您可以将其设置为 ,将其设置为另一个对象,简而言之,您可以对它执行任何您喜欢的事情:一旦方法返回,该引用将消失,原始引用将保持不变。Personnull

话虽如此

正如其他人告诉你的那样,真的没有必要使用 .ref

此外,只要你处理的是一些琐碎的情况,比如连接名字和姓氏,我就会让对象自己来做(就像 Slapout 所做的那样)。

如果出现这种需要,以后总有时间将责任分开。

还要考虑的是,为这样一个微不足道的任务设置一个单独的类也可能被认为是违反直觉的。 假设这是手头的代码:

var p = new Person() { FirstName = "John", LastName = "Smith"} ;

Console.WriteLine(p.FullName);

当我这样做时,我完全期望在任何时候都能返回一些有意义的东西(即“约翰·史密斯”)。FullName

相反,使用您的这两种方法,如果我忘记(并且我会)打电话会发生什么?CreateFullName

如果您确实需要将给定的关注点移动到单独的类中,请将其隐藏在属性的方法中。get

这样一来,人们就不需要知道你编写的类的基础,而且它仍然是可测试的。

评论

0赞 BrightonDev 9/27/2012
感谢您(以及这里的所有其他人)的及时和翔实的回复。