I was trying to learn a bit about generics and the SelectMany function and delegates. The semantic function of the code below(as in what the functions are supposed to be doing), doesn't matter. Most of them do nothing meaningful and are just attempts to see if the issue of the function not starting, persists.
That's my question.. Why is it that the method named _SelectManyIteratora
doesn't start. Nor does _SelectManyIteratorb
. But _SelectManyIteratorc
does start.
As in, i'm calling the function, i'm not getting any compilation error, and the first line of the function, a simple WriteLine statement, is not executing!
I would have expected them all to start.
My interest is
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections;
namespace functionwontstart
{
class Program
{
static void Main(string[] args)
{
string[] arrstr1 = { "abc", "def", "ghi" };
string[] arrstr2= {"qrs","tuv","wxy"};
_SelectManyIteratora(arrstr1, x => arrstr2, (s1, s2) => s1 + s2);
_SelectManyIteratorb(arrstr1, x => arrstr2, (s1, s2) => s1 + s2);
_SelectManyIteratorc(arrstr1, x => arrstr2);
Console.ReadLine();
}
static IEnumerable<TResult> _SelectManyIteratora<TSource, TCollection, TResult>(IEnumerable<TSource> source, Func<TSource, IEnumerable<TCollection>> collectionSelector, Func<TSource, TCollection, TResult> resultSelector)
{
Console.Write("got this far"); // no!
foreach (TSource element in source)
foreach (TCollection subElement in collectionSelector(element))
yield return resultSelector(element, subElement);
}
static IEnumerable<TResult> _SelectManyIteratorb<TSource, TCollection, TResult>(IEnumerable<TSource> source, Func<TSource, IEnumerable<TCollection>> collectionSelector, Func<TSource, TCollection, TResult> resultSelector)
{
Console.Write("got this far"); // no!
TSource ts = source.ElementAt(0);
TCollection tc = collectionSelector(ts).ElementAt(0);
yield return resultSelector(ts, tc);
}
static IEnumerable<int> _SelectManyIteratorc<TSource, TCollection>(IEnumerable<TSource> source, Func<TSource, IEnumerable<TCollection>> collectionSelector)
{
Console.Write("got this far"); // yes
return new List<int>();
}
} //class
} //namespace
Those methods are iterators - they use yield return
. They execute in a special way... the code only gets executed as you iterate over the result.
So if you change the calling code to:
foreach (var item in _SelectManyIteratora) { }
then you'll see the method being executed. Until you start iterating over the return value, none of the code in the method executes. Each time the code hits a yield return
statement, control will return to the code that's iterating over it, until that code asks for the next item - at which point it will jump back into the method, just after the yield return
statement, with all the local variables in the same state as they were before.
For more details:
See more on this question at Stackoverflow