There's something in the behaviour of IEnumerables-IEnumerators created by an Iterator method in C# that is quite confusing. Let's start by the behaviour of JavaScript generators, that is the expected one for me, and let's see then the oddities of the C# version.
In JavaScript, a generator function returns a generator object, an object that is both an iterable and an iterator. So when asking it for an iterator (via [Symbol.iterator]) it returns itself. Because of this, if we try to iterate multiple times our iterable, the iteration will only happen the first time. During this first iteration the iterable-iterator object reaches its end, so next iterations will do nothing.
function* getCountries(){ yield "France"; yield "Belgium"; yield "Portugal"; } let countriesGenOb = getcountries(); let countriesIterator1 = countriesGenOb[Symbol.iterator](); console.log(countriesGenOb === countriesIterator1 ? "same object" : "different object"); //same object console.log("- first iteration:"); for (let country of countriesGenOb){ console.log(city); } //France //Belgium //Portugal console.log("-------------"); console.log("- second iteration:"); //no iteration is done, countriesGenOb[Symbol.iterator] is returning the same object //that was already iterated to the end in the previous loop //very interesting, this behaviour is different from C#, here the generator object (this is both iterable and iterator) is returning itself, rather than a copy for (let country of countriesGenOb){ console.log(city); } //Nothing gets printed let countriesIterator2 = countriesGenOb[Symbol.iterator](); let countriesIterator3 = countriesGenOb[Symbol.iterator](); console.log(countriesGenOb === countriesIterator2 ? "Same reference" : "Different reference"); //same reference console.log(countriesGenOb === countriesIterator3 ? "Same reference" : "Different reference"); //same reference
The behaviour in C# is different and surprising. An Iterator method returns an object that implements both IEnumerable and IEnumerator, but we can iterate it multiple times. This is like that because it seems that when we call GetEnumerator on and IEnumerable-IEnumerator that has already been enumerated, it does not return a reference to the same object, but to a new object implementing also IEnumerable and IEnumerator.
var countries = GetCountries(); Console.WriteLine(countries is IEnumerable<-- CSharp and JavaScript current sources F:\Main\MyWebCreatures\deploytonenyures\SourceCode\GeneratorsIterators_IterateMultipleTimes -->); //True Console.WriteLine(countries is IEnumerator ); //True Console.WriteLine(countries == countries.GetEnumerator() ? "Same reference" : "Different reference"); //Same reference //the Iterator method is returning an IEnumerable/IEnumerator object, but the thing is that calling to GetEnumerator returns a new instance, rather than the object itself //Because of that the 2 loops do a whole iteration, and enumerator1 and 2 are different objects. Console.WriteLine("- first iteration:"); foreach(string country in countries) Console.WriteLine(country); //France //Belgium //Portugal Console.WriteLine("-----------------"); Console.WriteLine(countries == countries.GetEnumerator() ? "Same reference" : "Different reference"); //Different reference Console.WriteLine("- second iteration:"); foreach(string country in countries) Console.WriteLine(country); //France //Belgium //Portugal Console.WriteLine("-----------------"); var enumerator1 = countries.GetEnumerator(); Console.WriteLine((enumerator1 == countries) ? "Same reference" : "Different reference"); //Different reference var enumerator2 = countries.GetEnumerator(); Console.WriteLine((enumerator1 == enumerator2) ? "Same reference" : "Different reference"); //Different reference
No comments:
Post a Comment