You can still make this function faster and gain another second if you don't use `IEnumerable` and an enumerator but for example a `List<int>`.

Like this (based on [@EBrown][1]'s code):

 public static List<int> Primes(int upperLimit)
 {
 var result = new List<int>();

 if (upperLimit < 2)
 {
 throw new ArgumentException("Upper Limit be must greater than or equal to 2.");
 }

 result.Add(2);

 if (upperLimit == 2)
 {
 return result;
 }

 // Check odd numbers for primality
 const int offset = 3;

 Func<int, int> toNumber = index => (2 * index) + offset;
 Func<int, int> toIndex = number => (int)((number - offset) * 0.5);

 var bits = new bool[toIndex(upperLimit) + 1];

 var upperSqrtIndex = toIndex((int)Math.Sqrt(upperLimit));

 for (var i = 0; i <= upperSqrtIndex; i++)
 {
 // If this bit has already been turned off, then its associated number is composite. 
 if (bits[i]) { continue;}

 var number = toNumber(i);
 
 // The instant we have a known prime, immediately yield its value.
 result.Add(number);
 
 // Any multiples of number are composite and their respective bits should be turned off.
 for (var j = toIndex(number * number); (j > i) && (j < bits.Length); j += number)
 {
 bits[j] = true;
 }
 }
 // Output remaining primes once bit array is fully resolved:
 for (var i = upperSqrtIndex + 1; i < bits.Length; i++)
 {
 if (!bits[i])
 {
 result.Add(toNumber(i));
 }
 }

 return result;
 }

Here are two profiler screenshots:

@EBrown's optimized method:
[![Enumerator][2]][2]

Without enumerator:
[![List][3]][3]

Original method:
[![Original][4]][4]

Tested code:

 for (int i = 0; i < 3; i++)
 {	
 	//var primes1 = Primes(100000000);
 	var primes1 = Primes1(100000000).ToList();	
 //var primes1 = PrimesOriginal(100000000).ToList();
 }


 [1]: http://codereview.stackexchange.com/users/73844/ebrown
 [2]: https://i.sstatic.net/Me2xg.png
 [3]: https://i.sstatic.net/g8dZH.png
 [4]: https://i.sstatic.net/X3Bgu.png