错误的变量得到更新

时间:2014-02-27 14:26:57

标签: c# race-condition

我一直在努力寻找一些我发现非常奇怪的东西。显然,C#表现得这样,但我想知道如何防止它。我的代码很长,所以我做了一个我的困境的小例子:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApplication4
{
    public partial class Form1 : Form
    {
        private List<Person> m_Persons = new List<Person>();
        public Form1()
        {
            InitializeComponent();

            Person p1 = new Person();
            p1.Name = "Jack";
            p1.Money = 10;
            m_Persons.Add(p1);

            Bank ph = new Bank();
            for (int i = 0; i < 4; i++)
            {
                ph.Insert(p1);
                Console.WriteLine(p1.Money);
            }
        }
    }

    class Person
    {
        public string Name { get; set; }
        public int Money { get; set; }
    }

    class Bank
    {
        private List<Person> m_Customers = new List<Person>();
        public void Insert(Person p_Person)
        {
            int index = m_Customers.FindIndex(item => item.Name == p_Person.Name);
            if (index > -1)
                m_Customers.ElementAt(index).Money += p_Person.Money;
            else
                m_Customers.Add(p_Person);
        }
    }
}

在上面的代码中,我的印刷品说:

10
20
40
80

这些值对我来说是对的,但是它们应该存储在bankclass中,而不是存储在Insert()中用作引用的对象中。为什么p1-object会更新?!

4 个答案:

答案 0 :(得分:6)

Person是一个类,即引用类型。当您将人员插入m_Customers列表时,实际上是在为同一个人实例创建新的引用,并将此引用添加到列表中(list hold 引用到人物实例)。因此,您的程序有一个person实例和六个对此实例的引用。使用哪个参考资料来更新人的钱并不重要 - 您的单个实例将在最后更新。

enter image description here

我还建议您阅读MSDN文章Value and Reference Types

答案 1 :(得分:3)

p1对象正在更新,因为Person是引用类型。这意味着当您将对象传递给方法时,它实际上是对正在传递的对象的引用,即p1对象与您添加到的Person完全相同。银行。因此,如果您更新银行中的Person(在调用Insert方法时执行此操作),则p1对象也会更新。

如果要防止此行为,则必须在循环中创建新的Person对象。如果您每次将新的Person对象的属性设置为相同的值,则会更新银行中的Person,但不会更新循环中的Person对象。< / p>

或者,您可以更改Insert方法,而不是

m_Customers.Add(p_Person);

你使用

m_Customers.Add(new Person{ Name = p_Person.Name, Money = p_Person.Money });

答案 2 :(得分:1)

似乎你总是在哄同一个人:

for (int i = 0; i < 4; i++)
{
    ph.Insert(p1);
    Console.WriteLine(p1.Money);
}

以上代码将插入p1 4次。

答案 3 :(得分:1)

在您的Insert方法中,验证此人是否已存在于列表m_Customers中(如果存在),您可以更新资金。

Form1班级中,您需要创建不同姓名的人,如果名称相同,则会更新资金。

尝试在for语句中创建人员,并使用不同的名称:

public Form1()
    {
        InitializeComponent();

        Bank ph = new Bank();
        for (int i = 0; i < 4; i++)
        {
            Person p = new Person();
            p.Name = "Jack" + i;
            p.Money = 10;
            m_Persons.Add(p);

            ph.Insert(p);
            Console.WriteLine(p.Money);
        }
    }