当一个对象从方法中返回时,是创建了一个新实例还是引用了原来的实例?

6

可能重复:
返回引用类型的方法会返回引用还是克隆副本?

我的一位同事说,当一个方法返回以下对象时,将创建一个新的实例/副本而不是返回引用:

public CustomerEntity Customer { get; set; }

public CustomerEntity GetCustomer() {
    Customer = new CustomerEntity();
    return Customer;    
}

这是正确的吗?我的测试似乎表明情况不同,但我不确定如何确认。他担心将数据复制到新对象时的开销。

为了保险起见,在以下哪些方法/场景中会创建新对象?在哪些情况下调用类会访问对原始对象的引用或副本?假设'CustomerEntity'是一个非常大的对象。

public class CustMan {
public CustomerEntity GetCustomer() {
    Customer = new CustomerEntity();
    return Customer
}

public void FillCustomer(CustomerEntity customer)
{
    customer = new CustomerEntity();
    // Calling class: 
    // CustomerEntity ce = new CustomerEntity(); 
    // l_custMan.FillCustomer(ce);  WriteLine(ce.Name);   
}

public void LoadCustomer()
{
    Customer = new CustomerEntity();
    // Calling Class access customerEntity via l_custMan.CustomerEntity
}
}

澄清:我的同事认为使用“Load”方法比使用“Get”方法更好。
l_custMan.Load();
CustomerEntity = l_custMan.Customer;

vs.

CustomerEntity = l_custMan.GetCustomer();

8
你的同事是错误的。只是返回一个引用(尽管是引用的副本)。他混淆了这种情况和值类型,后者会被完全复制。 - dlev
3个回答

8
一个同事说,当一个方法返回以下对象时,会创建一个新的实例/副本,而不是返回引用:
你的同事是错误的。对于引用类型的返回类型,总是会进行复制,只是复制的是引用。
我可以更加明确:
假设 ReturnType 是一个引用类型,并且给定:
public ReturnType M() {
    // some code
    return E;
}

当表达式E求值得到一个实例I的时候,你想知道是否会创建I的副本并将其引用返回给调用者,还是直接将引用I返回给调用者。答案是直接返回对I的引用。
对于传递到方法中的引用类型参数(除非它们被标记为refout),情况也是如此:总是会创建副本,只是传递的是引用的副本。
*:他可能被C++的某些知识所迷惑,C++需要明确返回引用。

+1:比我疲惫而含糊的胡言乱语更好地总结了这种情况 :) - Binary Worrier
我喜欢使用术语“按值返回对象引用”(或对于参数,“按值传递对象引用”)。我更愿意将存储在类类型变量中的东西称为“实例ID”,而不是“对象引用”,以避免过载术语“引用”(它还可以指传递给ref参数的内容),并明确发生了什么。如果汽车修理厂的工人收到一份工作订单,上面写着“将1G574X8号汽车涂成蓝色”,工人会知道... - supercat
寻找具有指定VIN的汽车并将其涂成蓝色。工人不需要返回一张用蓝色墨水涂过VIN的纸条,也不需要创建一个与旧车相似但是是蓝色的新车。向函数传递参数就像将数字复制到新的工作订单上;它会复制数字,但不会复制汽车。 - supercat

0

虽然你的方法只返回了一个引用,但它似乎很奇怪:

public CustomerEntity GetCustomer() {
    Customer = new CustomerEntity();
    return Customer;    
}

这个名称表明它返回一个字段,但实际上它创建了一个新对象,覆盖了一个属性,然后返回一个引用,因此每次都会创建一个对象。

该方法应该是这样的:

public CustomerEntity GetCustomer() {
    return Customer;    
}

但这是多余的,因为您的属性已经有getter了。

我假设CustomerEntity是一个类,而不是一个结构体,对于结构体会创建一个副本


我明白这个名字可能会让人感到困惑。我的意图是寻找最佳方法来填充一个对象并在调用类中使用该对象。'GetCustomer' 方法将创建一个新实例,从数据库中填充数据,然后将其返回给调用对象。 - davewilliams459

-1

您将返回对象的引用。若要创建“新”的副本,您需要创建一个全新的实体。

public CustomerEntity GetCustomer() {
    CustomerEntity toReturn = new CustomerEntity();
    return toReturn ;    
}

如果 CustomerEntity 是一个值类型,会怎样? - Binary Worrier
它仍然将对toReturn的引用复制回调用者。这就是问题最根本的问法。 - jason
我猜我可能误解了问题。我以为OP在问是否会返回一个“新的”或“对现有对象的引用”。答案是:返回对现有对象的引用。 - tribe84
1
@tribe84:这个问题应该这样考虑:假设ReturnType是一个引用类型,给定public ReturnType M() { // some code; return returnType; }。那么returnType的引用副本是否被创建并返回了一个指向它的引用,还是直接返回了returnType的引用? - jason
也许提问者并不了解这个区别。抱歉,但是一个好的SO答案不应该对问题做任何假设。 - Binary Worrier
显示剩余2条评论

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