Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Wrong variable getting updated

I have been struggling with something that I found out to be very weird. Obviously, C# behaves this way but I was wondering how to prevent it. My code is very long so I've made a small example of my dilemma:

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);
        }
    }
}

In the code above, my printings say:

10
20
40
80

Those values is to me right, but they should be stored in the bankclass and not in the object that are used as a reference in Insert(). Why is the p1-object getting updated?!

like image 432
user3360860 Avatar asked Feb 27 '14 14:02

user3360860


4 Answers

Person is a class, i.e. reference type. When you are inserting person to m_Customers list, you are actually creating new reference to same person instance, and adding this reference to list (list hold references to person instances). So, your program have one instance of person and six references to this instance. It does not matter which reference you will use to update person's money - your single instance will be updated at the end.

enter image description here

I also suggest you to read MSDN article Value and Reference Types

like image 154
Sergey Berezovskiy Avatar answered Oct 17 '22 22:10

Sergey Berezovskiy


The p1 object is getting updated becaused Person is a reference type. This means that when you pass the object to methods, it's actually a reference TO the object which is being passed i.e. The p1 object is the exact same instance as the Person you've added to the bank. Therefore, if you update the Person in the Bank (which you do when you call the Insert method) the p1 object is also updated.

If you want to prevent this behaviour, you would have to create a new Person object within your loop. If you set the new Person object's properties to the same values each time, the Person in the bank will be updated, but not the Person object in your loop.

Alternatively you could change the Insert method so that instead of

m_Customers.Add(p_Person);

you use

m_Customers.Add(new Person{ Name = p_Person.Name, Money = p_Person.Money });
like image 44
thudbutt Avatar answered Oct 17 '22 23:10

thudbutt


It seems you are always looping the same person:

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

The above code will insert p1 4 times.

like image 40
Davin Tryon Avatar answered Oct 17 '22 22:10

Davin Tryon


In your Insert method you verify if the person already exists in the lists m_Customers, if exists, you update the money.

In your Form1 Class you need to create people of different names, if the name is the same, the money will be updated.

Try to create people inside for statement and diferent names like this:

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);
        }
    }
like image 39
Only a Curious Mind Avatar answered Oct 17 '22 21:10

Only a Curious Mind