[英]Object getting updated which is passed as a parameter to a method in c#
我今天在我的应用程序中观察到了一个奇怪的行为。 我的数据访问层中有如下方法之一:
public async Task<Order> WriteOrder(Order orderDetails)
{
try
{
Order updatedOrder = GenerateOrderID(orderDetails);
Task insertOrder = orderCollection.InsertOneAsync(orderDetails); // updatedOrder was supposed to be passed here.
// inserts values into Database.
}
}
private Order GenerateOrderID(Order order)
{
try
{
order.Id = Guid.NewGuid().ToString();
order.SubmittedOn = DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss");
return order;
}
catch(Exception ex)
{
throw;
}
}
public class Order
{
[DataMember(Name = "id")]
public string Id { get; set; }
[DataMember(Name = "submittedOn")]
public string SubmittedOn { get; set; }
// some other Data Memebers
}
说明:
WriteOrder
方法正在接收orderDetails
作为输入参数,然后我将它传递给GeneratedOrderId
方法,在那里更新 Id 和其他一些细节并返回订单对象。 我们在updatedOrder
对象中接收对象(我们没有在任何地方使用)。 然后将orderdetails
对象传递给InsertOneAsync
方法并插入到数据库中。
一直以来我都没有注意到它,但我应该将updatedOrder
作为参数传递给InsertOneAsync
方法,而不是orderDetails
。
但不知何故它正在工作,即 Id 和SubmittedOn
详细信息在数据库中得到更新。当我调试并看到时, orderDetails
对象也得到更新(根据我的说法,这是不应该的)。 为什么以及如何发生这种情况?
这里要理解的基本事情是,当我们将引用类型的对象传递给方法时,引用是按值传递的。 在您的代码中,没有创建Order
的新对象的位置。
因此,无论您在何处更改属性值,都会更新同一对象的状态。 内存中只有一个对象,并且您有指向相同引用的不同副本。
这意味着在以下方法调用中:
private Order GenerateOrderID(Order order)
order
变量持有相同的对象,该对象由调用者端的orderDetails
指向。 引用的两个副本,但指向内存中的同一对象。
如果您在私有方法中创建Order
新对象,则方法中的一个小变化将完全改变行为。 然后你会看到传递的对象没有得到更新。 看:
private Order GenerateOrderID(Order order)
{
try
{
order = new Order(); // note this line
order.Id = Guid.NewGuid().ToString();
order.SubmittedOn = DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss");
return order;
}
catch(Exception ex)
{
throw;
}
}
现在我们有一个新对象,我们可以设置它的状态。 现在updatedOrder
和orderDetails
都是对不同对象的引用,并且改变一个的状态不会导致改变另一个。
请注意,这适用于 c# 中的引用类型,即类和接口对象,不适用于值类型 lile int
、 long
、 struct
等
来自 docs.microsoft.com:
引用类型的变量不直接包含其数据; 它包含对其数据的引用。 当您按值传递引用类型参数时,可以更改属于被引用对象的数据,例如类成员的值。
您正在将orderDetails
对象的引用传递给GenerateOrderID
方法。 所以你在这个方法中修改的对象仍然是同一个对象。 GenerateOrderID
执行更改此对象的状态。 因此,当您将orderDetails
传递给InsertOneAsync
方法时,您传递的引用会引用您在GenerateOrderID
中修改的已更改对象。
我猜您在想,当您传递orderDetails
,您传递的是对象的副本 - 但事实并非如此。 您正在传递引用的副本。 所以,如果你分配的东西到order
的方法的参考里面, orderDetails
中WriteOrder
方法引用仍将引用旧的对象。 但是在这里,您正在更改指向的对象的某些字段。
我建议阅读此内容。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.