Why does generic list indexer show two behaviors

Viewed 62
static void Main(string[] args)
{
   var vs = new List<Person> { new Person(1) };
   vs[0].IncrementAge();

   Console.WriteLine(vs[0].Age);  // output: 1
}

struct Person
{
   public int Age { get; set; }

   public Person(int age) : this()
   {
      Age = age;
   }

   public int IncrementAge()
   {
      Age++;
      return Age;
   }
}

I understand why we get a result like it. The list indexer returns a copy of the element. That is okay.

My question is that why we don't get the same result in the following code? because I changed the value of a copy of an element:

static void Main(string[] args)
{

   var vs = new List<int> { 1 };
   vs[0] = 2;

   Console.WriteLine(vs[0]);     // output: 2, **why not 1?**
}

Why does overwriting the entire value of a copy of an element affect list? I want to know how this code works in the background.

2 Answers

In this line:

vs[0].IncrementAge();

you retrieve the value at index 0, which creates a copy of the struct. In the copy, the Age gets incremented, and the copy is then lost. It is not saved back into the list.

In this context, vs[0] is translated to calling a getter method which returns a value. It would be the same as (pseudocode):

vs.get_Item(0).IncrementAge();

On the contrary, here:

vs[0] = 2;

you replace the value at position 0 with a new one. That's why it's changed in the list.

In this context, vs[0] is translated to calling a setter method which stores the provided value into the list's internal data structure. It would be the same as (pseudocode):

vs.set_Item(0, 2);

The array indexer returns a reference to the array element and the array value will be changed but the list value will not. The list indexer returns a copy of the element. The member function is called on this temp object. So, the original list member is not changed at all.

Related