对象得到更新,该对象作为参数传递给C#中的方法

时间:2019-01-28 11:07:23

标签: 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和其他一些详细信息将更新,并返回order对象。我们正在updatedOrder对象中接收对象(我们没有在任何地方使用它)。然后将orderdetails对象传递给InsertOneAsync方法,并将其插入数据库中。

一直以来,我都没有注意到它,但是应该将updatedOrder作为参数传递给InsertOneAsync方法,而不是orderDetails
但是它以某种方式起作用了,即Id和SubmittedOn的详细信息在数据库中进行了更新。当我调试并看到时,orderDetails对象也得到了更新(对我而言,这不应该这样做)。为什么以及如何发生。谁能解释一下。

PS:我知道关于c#及其工作方式可能会有一些非常基本的解释,但我确实需要知道。提前非常感谢!

2 个答案:

答案 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;
    }
}

现在我们有了一个新的对象,我们将其设置为状态。现在updatedOrderorderDetails都引用了不同的对象,更改一个对象的状态不会导致更改另一个对象。

注意,这适用于c#中的引用类型,即类和接口对象,而不适用于值类型,例如intlongstruct