首先,对问题标题的道歉,为此找不到更好的答案。
我今天在应用程序中发现一个奇怪的行为。
我的数据访问层中有以下一种方法:
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和其他一些详细信息将更新,并返回order对象。我们正在updatedOrder
对象中接收对象(我们没有在任何地方使用它)。然后将orderdetails
对象传递给InsertOneAsync
方法,并将其插入数据库中。
一直以来,我都没有注意到它,但是应该将updatedOrder
作为参数传递给InsertOneAsync
方法,而不是orderDetails
。
但是它以某种方式起作用了,即Id和SubmittedOn
的详细信息在数据库中进行了更新。当我调试并看到时,orderDetails
对象也得到了更新(对我而言,这不应该这样做)。为什么以及如何发生。谁能解释一下。
PS:我知道关于c#及其工作方式可能会有一些非常基本的解释,但我确实需要知道。提前非常感谢!
答案 0 :(得分:1)
从docs.microsoft.com:
引用类型的变量不直接包含其数据。它 包含对其数据的引用。传递引用类型时 通过值参数,可以更改属于 引用的对象,例如类成员的值。
您正在将对orderDetails
对象的引用传递给GenerateOrderID
方法。因此,您在此方法中修改的对象仍然是同一对象。 GenerateOrderID
执行会更改此对象的状态。因此,当您将orderDetails
传递给InsertOneAsync
方法时,您传递的引用就是在GenerateOrderID
中修改的引用已更改的对象。
我猜您在想,当您传递orderDetails
时,您正在传递对象的副本-但这不是真的。您正在传递参考的副本。因此,如果您要为方法内部的order
引用分配某些内容,则orderDetails
方法引用中的WriteOrder
仍将引用旧对象。但是在这里,您正在更改要指向的对象的某些字段。
我建议阅读this。
答案 1 :(得分:1)
这里要了解的基本内容是,当我们将引用类型的对象传递给方法时,引用是通过值传递的。在您的代码中,没有创建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#中的引用类型,即类和接口对象,而不适用于值类型,例如int
,long
,struct
等>