Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What causes this list to be passed by reference when called one way, but by value another?

Tags:

c#

I was making a simple test for running a validation method and came across this strange situation.

public IEnumerable<int> ints (List<int> l)
{
 if(false)yield return 6;
 l.Add(4);
}


void Main()
{
 var a = new List<int>();
 var b = new List<int>();
 for( int i = 0; i < 4; i++ ){
  a.Add(i);
  b.Add(i);
 }
 a.AddRange(ints(a));
 ints(b);
 Console.WriteLine(a);
 Console.WriteLine(b);
}

Once this code runs, a will contain [0,1,2,3,4]. However, b will contain [0,1,2,3]. Why did calling the method as an argument in AddRange allow the list to be passed by reference? Or if that didn't happen, what did?

like image 555
Travis J Avatar asked Jun 26 '13 21:06

Travis J


1 Answers

ints(b) call does not enumerate IEnumerable, so code never reaches l.Add(4) line, unlike in AddRange case which enumerates all items to add them to the list.

To see it called for b case enumerate result manually:

ints(b).ToList();

IEnumerable<T> implemented via functions are not executing body of the function before enumeration starts - the code is actually transformed by compiler into class with states to support true lazy evaluation of enumerable (details can be found in multiple articles, i.e. Iterator Pattern demystified - link provided by Tim Schmelter).

like image 166
Alexei Levenkov Avatar answered Oct 10 '22 04:10

Alexei Levenkov