Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Question about yield return statement

Tags:

c#

.net

Take the example here:

 public static IEnumerable<BigInt> EvenNumbers(IEnumerable<BigInt> numbers)  
 {  
     foreach (BigInt number in numbers)  
     {  
         if (number % 2 == 0)  
         {  
             yield return number;  
         }  
     }  
 }  

This will return only the values which match the criteria (n % 2 == 0). But what is the difference between yield return number; and return number;?

If I say yield return number, will it return each number to the calling function and so on? Where can I find some details on what goes on behind the scenes?

Thanks

like image 542
GurdeepS Avatar asked Sep 15 '25 17:09

GurdeepS


1 Answers

"return" simply won't work here (since it would try to return a BigInt, and the method declares an IEnumerable<BigInt>. Jon Skeet has a good write-up of iterator blocks (what this is) in the free chapter 6 of C# in Depth (then buy the whole book - it really is worth it ;-p).


edit - here's a very rough version of what you would have to do in order to write this yourself; note that it doesn't quite do the same, but achieves the goal. I think you'll agree that the yield return version is easier!

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
static class Program
{
    static void Main()
    {
        IEnumerable<int> source = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
        foreach (int value in EvenNumbers(source))
        {
            Console.WriteLine(value);
        }
    }

    public static IEnumerable<int> EvenNumbers(IEnumerable<int> numbers)
    {
        return new EvenEnumerable(numbers);
    }
    class EvenEnumerable : IEnumerable<int>
    {
        private readonly IEnumerable<int> numbers;
        public EvenEnumerable(IEnumerable<int> numbers) {
            this.numbers = numbers;
        }
        public IEnumerator<int> GetEnumerator()
        {
            return new EvenEnumerator(numbers);
        }
        IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
    }
    class EvenEnumerator : IEnumerator<int>
    {
        private readonly IEnumerable<int> numbers;
        public EvenEnumerator(IEnumerable<int> numbers)
        {
            this.numbers = numbers;
        }
        private int current;
        void IEnumerator.Reset() { throw new NotSupportedException(); }
        public int Current { get { return current; } }
        object IEnumerator.Current { get { return Current; } }
        IEnumerator<int> iter;
        public bool MoveNext()
        {
            if (iter == null) iter = numbers.GetEnumerator();
            while (iter.MoveNext())
            {
                int tmp = iter.Current;
                if (tmp % 2 == 0)
                {
                    current = tmp;
                    return true;
                }
            }
            return false;
        }
        public void Dispose()
        {
            if (iter != null)
            {
                iter.Dispose();
                iter = null;
            }
        }
    }
}
like image 181
Marc Gravell Avatar answered Sep 17 '25 08:09

Marc Gravell