简体   繁体   中英

C# Class as other class variable, scope of live

I created a small piece of code in order to test part of my project. It is working however I have some questions...

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace testtodel
{
    class Program
    {
        private class BucketItems
        {
            private List<Item> ItemList;
            private Item item;

            public BucketItems()
            {
                //item = new Item();
                ItemList = new List<Item>();
            }

            public void AddBucketItem(int _Start, int _End)
            {
                    item = new Item();
                    item.SetItem(_Start, _End);
                    ItemList.Add(item);
            }

            public void PrintItemList()
            {
                for (int i = 0; i < ItemList.Count(); i++)
                {
                    Console.WriteLine("Item: " + i.ToString() + " S: " + ItemList[i].Start.ToString() + " E: " + ItemList[i].End.ToString() + " D: " + ItemList[i].Range.ToString());
                }
            }
        }

        private class Item
        {
            public int Range { get; set; }
            public int Start { get; set; }
            public int End { get; set; }

            public void SetItem(int _Start, int _End)
            {
                Start = _Start;
                End = _End;
                Range = _End - _Start;
            }
        }

        static void Main(string[] args)
        {
            BucketItems bucketItems = new BucketItems();
            bucketItems.AddBucketItem(0, 100);
            bucketItems.AddBucketItem(200, 300);
            bucketItems.AddBucketItem(700, 1000);
            bucketItems.PrintItemList();
            Console.ReadLine();
        }
    }
}

The thing which I do not fully understand is related to line

item = new Item();

As you can see in code there are 2 lines like that, one commented and one uncommented.

  • Part_1: When code is executed as it is now, it will create a new instance of 'Item' class each time when 'AddBucketItem' method is called, then 'Item.SetItem' will set 'Start', 'End', 'Range' within 'item' variable and this will be added to 'ItemList'.

  • Part_2: When I will comment exisiting 'item = new Item();' line and uncomment other one then I will expect the following. When new instance of BucketItem class is created it will also create a new instance of 'Item' as this is defined in the 'BucketItem' constructor. Then, when 'AddBucketItem' method is called, an 'item' varaible will be set by 'item.SetItem' and then, added to ItemList. This is ok for the first iteration. However if I will call 'AddBucketItem' method again, with new 'Start' and 'End' parameters, this will also change already added ItemList[0].

  • Questions:

  • Why each call in Part_2 is changing also all elements which were already added to ItemList? The only explanation is that all elements from list are storing a reference to 'item' variable and when this variable is changed by changing (Start, End, Duriation) it wil also change all ItemList. But I don't know if this is correct explanation and if it is I don't know why it is behaving like this. Hovever I am assuming that answer is different becasue the following example will fill the list as expected even when I am doing exactly the same thing as in 'Part2'.. I have variable, I am changing value of variable, I am adding this variable to list.

      int new_val; List<int> _lst = new List<int>(); for (int i = 0; i < 10; i++) { new_val = i; _lst.Add(new_val); } for (int i = 0; i < _lst.Count(); i++) { Console.WriteLine("ListIdx: " + i.ToString() + " Value: " + _lst[i].ToString()); } 

    Can someone please put some more light on my issue?

In your example, new_val is int which is value type .
At the same time, in the first code snippet, Item is a class, which is reference type .

If you use approach described in Part_2 , then you actually operate with one object. So, your ItemList contains N items, which are all the same object.

In Part_1 , every time you call AddBucketItem , you create a new object and append it to your list. In Part_2 , everytime you call AddBucketItem , you modify the single original Item object.

You may want to read some information on value types and reference types on MSDN:
https://msdn.microsoft.com/en-us/library/4d43ts61(v=vs.90).aspx

You need to understand that in C#, objects are passed by reference and primitive types are passed by value.

Therefore, your understanding for the AddBucketItem example is correct. The Item object is only created once in the BucketItems constructor. When you call AddBucketItem() , you are modifying the original instance and adding its reference into the list. So in the end, you have a list with individual item all pointing to the same object instance.

For the 2nd example you provide, it behaves differently because for int type, which is a primitive data type, the value passed into the Add() function is a copy of the integer, not a reference.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM