Skip to content

Instantly share code, notes, and snippets.

@battleguard
Last active August 29, 2015 14:21
Show Gist options
  • Select an option

  • Save battleguard/a85d0dcc116d8b169ca8 to your computer and use it in GitHub Desktop.

Select an option

Save battleguard/a85d0dcc116d8b169ca8 to your computer and use it in GitHub Desktop.
Example Of Compiler Generated Code For Yield Return
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];
}
}
}
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();
}
}
}
}
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;
}
}
}
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