Last active
August 29, 2015 14:21
-
-
Save battleguard/a85d0dcc116d8b169ca8 to your computer and use it in GitHub Desktop.
Example Of Compiler Generated Code For Yield Return
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Collections.Generic; | |
| using System.Linq; | |
| namespace ConsoleApplication5 | |
| { | |
| public class SimpleYieldReturn | |
| { | |
| static void Run() | |
| { | |
| IEnumerable<int> enumerable = GetNumbers( new[] { 0, 1, 2 } ); | |
| IEnumerator<int> enumerator = enumerable.GetEnumerator(); | |
| while ( enumerator.MoveNext() ) | |
| Console.WriteLine( enumerator.Current ); | |
| } | |
| public static IEnumerable<int> GetNumbers( int[] items ) | |
| { | |
| yield return items[0]; | |
| yield return items[1]; | |
| yield return items[2]; | |
| } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Collections; | |
| using System.Collections.Generic; | |
| namespace ConsoleApplication5 | |
| { | |
| public class ReverseEngineeredYieldReturn | |
| { | |
| static void Run() | |
| { | |
| IEnumerable<int> numbers = Getnumbers( new int[] { 1, 2, 3 } ); | |
| IEnumerator<int> enumerator = numbers.GetEnumerator(); // to iterate we need to get the enumerator | |
| while ( enumerator.MoveNext() ) | |
| Console.WriteLine( enumerator.Current ); | |
| } | |
| public static IEnumerable<int> Getnumbers( int[] items ) | |
| { | |
| CustomNumberYieldReturn runner = new CustomNumberYieldReturn( -2 ); // create an enumerator for this specific case | |
| runner.OriginalNumbers = items; // pass in the array of numbers that you will be enumerating | |
| return (IEnumerable<int>)runner; // return just the IEnumerable since we want to hide the custom class methods | |
| } | |
| private sealed class CustomNumberYieldReturn : IEnumerator<int>, IEnumerable<int> | |
| { | |
| private int _currentNumber; // current number that will be returned | |
| private int _currentState; // state that the yield return state machine is in | |
| public int[] OriginalNumbers; | |
| private int[] _iteratingThroughNumbers; | |
| private readonly int _initialThreadId; | |
| public CustomNumberYieldReturn( int currentState ) | |
| { | |
| _currentState = currentState; | |
| _initialThreadId = Environment.CurrentManagedThreadId; | |
| } | |
| public bool MoveNext() | |
| { | |
| switch ( _currentState ) | |
| { | |
| case 0: | |
| _currentState = -1; | |
| _currentNumber = _iteratingThroughNumbers[0]; | |
| _currentState = 1; | |
| return true; | |
| case 1: | |
| _currentState = -1; | |
| _currentNumber = _iteratingThroughNumbers[1]; | |
| _currentState = 2; | |
| return true; | |
| case 2: | |
| _currentState = -1; | |
| _currentNumber = _iteratingThroughNumbers[2]; | |
| _currentState = 3; | |
| return true; | |
| case 3: | |
| _currentState = -1; | |
| break; | |
| } | |
| return false; | |
| } | |
| object IEnumerator.Current | |
| { | |
| get { return Current; } | |
| } | |
| public IEnumerator<int> GetEnumerator() | |
| { | |
| CustomNumberYieldReturn getNums; | |
| if ( Environment.CurrentManagedThreadId == _initialThreadId && _currentState == -2 ) | |
| { | |
| _currentState = 0; | |
| getNums = this; | |
| } | |
| else | |
| getNums = new CustomNumberYieldReturn( 0 ); | |
| getNums._iteratingThroughNumbers = OriginalNumbers; | |
| return getNums; | |
| } | |
| IEnumerator IEnumerable.GetEnumerator() | |
| { | |
| return GetEnumerator(); | |
| } | |
| public int Current | |
| { | |
| get { return _currentNumber; } | |
| } | |
| public void Dispose() | |
| { | |
| } | |
| public void Reset() | |
| { | |
| throw new NotImplementedException(); | |
| } | |
| } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Collections.Generic; | |
| using System.Linq; | |
| namespace ConsoleApplication5 | |
| { | |
| class DeferredYieldReturn | |
| { | |
| static void Run() | |
| { | |
| int amount = 20000; | |
| var enumerator = GetPrimes().GetEnumerator(); | |
| while ( --amount != 0 && enumerator.MoveNext() ) | |
| Console.WriteLine( enumerator.Current ); | |
| } | |
| static IEnumerable<int> GetPrimes() | |
| { | |
| for ( int num = 2; ; ++num ) | |
| { | |
| if ( IsPrime( num ) ) | |
| yield return num; | |
| } | |
| } | |
| static bool IsPrime( int number ) | |
| { | |
| if ( number == 1 ) | |
| return false; | |
| if ( number == 2 ) | |
| return true; | |
| int boundary = (int)Math.Floor( Math.Sqrt( number ) ); | |
| for ( int i = 2; i < boundary; ++i ) | |
| { | |
| if ( number % i == 0 ) | |
| return false; | |
| } | |
| return true; | |
| } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Collections; | |
| using System.Collections.Generic; | |
| namespace ConsoleApplication5 | |
| { | |
| public class ReverseEngineeredYieldReturnDeferred | |
| { | |
| static void Main() | |
| { | |
| // IEnumerable<int> numbers = GetPrimes(); | |
| // IEnumerator<int> enumerator = numbers.GetEnumerator(); | |
| IEnumerable numbers = GetPrimes(); | |
| IEnumerator enumerator = numbers.GetEnumerator(); | |
| int amount = 1000; | |
| while ( enumerator.MoveNext() && --amount != 0 ) | |
| Console.WriteLine( enumerator.Current ); | |
| } | |
| static bool IsPrime( int number ) | |
| { | |
| if ( number == 1 ) | |
| return false; | |
| if ( number == 2 ) | |
| return true; | |
| int boundary = (int)Math.Floor( Math.Sqrt( number ) ); | |
| for ( int i = 2; i < boundary; ++i ) | |
| { | |
| if ( number % i == 0 ) | |
| return false; | |
| } | |
| return true; | |
| } | |
| public static IEnumerable<int> GetPrimes() | |
| { | |
| CustomNumberYieldReturn runner = new CustomNumberYieldReturn( -2 ); | |
| return (IEnumerable<int>)runner; | |
| } | |
| private sealed class CustomNumberYieldReturn : IEnumerable<int>, IEnumerable, IEnumerator<int>, IEnumerator, IDisposable | |
| { | |
| private int _lastPrimeNumber; // current number that will be returned | |
| private int _currentState; // state that the yield return state machine is in | |
| private readonly int _initialThreadId; | |
| public int CurrentNumberCheckingForPrime; | |
| public int Current | |
| { | |
| get { return _lastPrimeNumber; } | |
| } | |
| object IEnumerator.Current | |
| { | |
| get { return Current; } | |
| } | |
| public CustomNumberYieldReturn( int currentState ) | |
| { | |
| _currentState = currentState; | |
| _initialThreadId = Environment.CurrentManagedThreadId; | |
| } | |
| public IEnumerator<int> GetEnumerator() | |
| { | |
| CustomNumberYieldReturn getNums; | |
| if ( Environment.CurrentManagedThreadId == _initialThreadId && _currentState == -2 ) | |
| { | |
| _currentState = 0; | |
| getNums = this; | |
| } | |
| else | |
| getNums = new CustomNumberYieldReturn( 0 ); | |
| return getNums; | |
| } | |
| IEnumerator IEnumerable.GetEnumerator() | |
| { | |
| return GetEnumerator(); | |
| } | |
| public bool MoveNext() | |
| { | |
| switch ( _currentState ) | |
| { | |
| case 0: | |
| _currentState = -1; | |
| CurrentNumberCheckingForPrime = 2; // initial prime number that is hard coded will always be the first return | |
| _currentState = 1; | |
| break; | |
| case 1: // need to check if the current number is prime | |
| _currentState = -1; | |
| goto incrementCurrentNumber; | |
| default: // iteration is now over so we no longer can move next | |
| return false; | |
| } | |
| checkForPrime: | |
| if ( IsPrime( CurrentNumberCheckingForPrime ) ) | |
| { | |
| _lastPrimeNumber = CurrentNumberCheckingForPrime; | |
| _currentState = 1; | |
| return true; | |
| } | |
| incrementCurrentNumber: | |
| ++CurrentNumberCheckingForPrime; | |
| goto checkForPrime; | |
| } | |
| void IDisposable.Dispose() | |
| { | |
| } | |
| void IEnumerator.Reset() | |
| { | |
| throw new NotImplementedException(); | |
| } | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment