Yield in c#

Published Monday, February 25, 2008 3:47 AM

i've been trying to explain the keyword yield to a friend of mine for more than an hour and he did not get it.

but finally when i typed in this example he finally did

   1: class enu :IEnumerable
   2:   {
   3:       public IEnumerator GetEnumerator()
   4:       {
   5:           yield return 1;
   6:           yield return 2;
   7:           yield return 3;
   8:       }
   9:   }

 

it actually means that when you are enumerating this object it will return a different value/object on every iteration

so the next time i revised this sample it was way easier to grasp the multiple returns

   1: public class enu :IEnumerable
   2:  {
   3:      int _index=0;
   4:      int[] numbers = { 1, 2, 3, 4, 5 };
   5:      public IEnumerator GetEnumerator()
   6:      {
   7:          yield return numbers[_index];
   8:          _index++;
   9:      }
  10:  }

 

now that i've gone this far i have to say that the enumerator here returns are not of a specific type nothing in the previous code specifies that the return type is an int

so..

after C# 2.0 has introduced generics this would work fine

 

   1: public class enu :IEnumerable<int>
   2:  {
   3:      int _index=0;
   4:      int[] numbers = { 1, 2, 3, 4, 5 };
   5:      public IEnumerator GetEnumerator()
   6:      {
   7:          yield return numbers[_index];
   8:          _index++;
   9:      }
  10:  
  11:      IEnumerator<int> IEnumerable<int>.GetEnumerator()
  12:      {
  13:          yield return numbers[_index];
  14:          _index++;
  15:      }
  16:  }

 

note that this new Interface IEnumerable<T> needs both methods to be implemented

 

Filed under: ,

Comments

# DotNetKicks.com said on Monday, February 25, 2008 8:42 AM

You've been kicked (a good thing) - Trackback from DotNetKicks.com

# Michael Sync said on Sunday, March 02, 2008 10:41 PM

>>i've been trying to explain the keyword yield to a friend of mine for more than an hour and he did not get it. but finally when i typed in this example he finally did

Your friend said he got it after listening your explanation for 1 hour?  maybe, he is tried of listening.. :) cuz I'm not sure why he suddenly understand about "yield" when he saw those sample codes.

# Vijay Santhanam said on Sunday, March 02, 2008 11:27 PM

Good example.

Maybe the hour long explanation was an exaggeration and hard for said listener to understand without seeing some code.

You should also describe what the compiler does with yield, cos that's what makes it strange and cool in my opinion. In one line in you're in a foreach loop, then the next Step over will put u inside another method. So strange.

# Jakub Sturc said on Monday, March 03, 2008 1:14 AM

hi,

what is the output of following line (considering the third implementation)?

foreach (var e in new enu()) Console.WriteLine(e);

just 1. i don't think it was the intent.

# greg1 said on Monday, March 03, 2008 4:34 AM

kicked..

# Jon Skeet said on Monday, March 03, 2008 8:35 AM

I've recently written an article about iterator blocks which I would personally find clearer than this explanation. I know, I'm biased - but it gives people alternatives :)

I've provided the article link as the URL for this comment.

# Wöchentliche Rundablage: ASP.NET MVC, ASP.NET, Windows Live, Silverlight 2, LINQ, C# 3.0, CardSpace… | Code-Inside Blog said on Monday, March 03, 2008 11:21 AM

Pingback from  W&ouml;chentliche Rundablage: ASP.NET MVC, ASP.NET, Windows Live, Silverlight 2, LINQ, C# 3.0, CardSpace&#8230; | Code-Inside Blog

# Antão said on Wednesday, March 05, 2008 8:33 AM

Did you test this? It doesn't iterate. The output is just 1...

It should be something like this:

   public class enu : IEnumerable

   {

       int[] numbers = { 1, 2, 3, 4, 5 };

       public IEnumerator GetEnumerator()

       {

           foreach(int i in numbers)

               yield return i;

       }

   }

# Jon Hanna said on Wednesday, March 05, 2008 9:24 AM

Okay, so let's start by fixing the bug. It should be something like :

do

{

   yield return numbers[_index];

}while(++_index != numbers.Length);

so that we don't get an index error after _index exceeds the bounds.

You say "note that this new Interface IEnumerable<T> needs both methods to be implemented". This is true, but because IEnumerator<T> extends IEnumerator you can do so just by using:

public class enu : IEnumerable<int>

{

   int _index=0;

   int[] numbers = { 1, 2, 3, 4, 5 };

   IEnumerator IEnumerable.GetEnumerator()

   {

       return GetEnumerator();

   }

   public IEnumerator<int> GetEnumerator()

   {

       do

       {

           yield return numbers[_index];

       }while(++_index != numbers.Length);

   }

}

This class has two advantages over your example. Firstly the implementation of the non-generic form simply re-uses the generic form, with all the advantages re-use gives us.

Secondly, because it is the generic (and more narrowly typed) form that is defined publicly and the non-generic that is defined by refering to the interface, this is now more flexible for someone who explicitly calls GetEnumerator(). Before this would have returned an IEnumerator and only usable as this, now it returns an IEnumerator<int> and usable as that or by implicitly casting to IEnumerator - the best of both worlds.

Even better though can be the following, since the only thing this class does is implement IEnumerator<int> for the range in question we can make use of the fact that iterator blocks can not only return IEnumerator or IEnumerator<T> but also can return IEnumerable<T> or IEnumerable. Hence for this example we could use a method like:

public IEnumerable<int> enu()

{

   int index=0;

   int[] numbers = { 1, 2, 3, 4, 5 };

   do

   {

       yield return numbers[index];

   }while(++index != numbers.Length);

}

Then instead of using foreach(int x in new enu()) we use foreach(int x in enu()). The lack of a full class definition (in the code, of course the runtime creates a new class for us) can nicely reduce the mental complexity of the code. It can also be very useful since this method would have full access to private members of whatever class it was defined in (if that isn't appropriate it can be defined as static).

# amir.magdy said on Saturday, March 08, 2008 6:32 AM

yep ur right it'll break once it gets to the end of array

i was trying to make my sample as easy as possible

thank you

Leave a Comment

(required) 
(required) 
(optional)
(required) 

This Blog

Syndication