C-Sharp | Java | Python | Swift | GO | WPF | Ruby | Scala | F# | JavaScript | SQL | PHP | Angular | HTML
Part A: An IEnumerable is returned from a query expression. A query that selects ints will be of type IEnumerable<int>.
Part B: On an IEnumerable variable, we can use the foreach-loop. This loop iterates with simple syntax.
Part C: We can apply many transformations to an IEnumerable instance, including the ToList and ToArray conversions.
LINQC# program that uses IEnumerable
using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static void Main()
{
// Part A: query expression.
IEnumerable<int> result = from value in Enumerable.Range(0, 2)
select value;
// Part B: loop over IEnumerable.
foreach (int value in result)
{
Console.WriteLine(value);
}
// Part C: we can use extension methods on IEnumerable.
double average = result.Average();
// ... Convert IEnumerable.
List<int> list = result.ToList();
int[] array = result.ToArray();
}
}
Output
0
1
Next: Display() receives an IEnumerable argument. We can pass Lists or arrays to it.
Also: We can implement IEnumerable on a type to provide support for the foreach-loop. This is done through the GetEnumerator method.
C# program that uses IEnumerable argument
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
Display(new List<bool> { true, false, true });
}
static void Display(IEnumerable<bool> argument)
{
foreach (bool value in argument)
{
Console.WriteLine(value);
}
}
}
Output
True
False
True
Foreach: We use IEnumerable and the foreach-loop to access, in sequence, all items in a 2D array. We can abstract the loop itself out.
Here: This example shows the yield contextual keyword in a method that returns IEnumerable<T>.
Generic: The return value is a generic IEnumerable collection of ints. We must specify the int in angle brackets.
Generic Class, MethodInt, uintC# program that uses array, yield keyword
using System;
using System.Collections.Generic;
class Program
{
static int[,] _grid = new int[15, 15];
static void Main()
{
// Initialize some elements in 2D array.
_grid[0, 1] = 4;
_grid[4, 4] = 5;
_grid[14, 2] = 3;
// Sum values in 2D array.
int sum = 0;
foreach (int value in GridValues())
{
sum += value;
}
// Write result.
Console.WriteLine("SUMMED 2D ELEMENTS: " + sum);
}
public static IEnumerable<int> GridValues()
{
// Use yield return to return all 2D array elements.
for (int x = 0; x < 15; x++)
{
for (int y = 0; y < 15; y++)
{
yield return _grid[x, y];
}
}
}
}
Output
SUMMED 2D ELEMENTS: 12
So: We can implement IEnumerable to fix this error on a class. This provides the GetEnumerator method.
C# program that causes GetEnumerator error
using System;
class Example
{
}
class Program
{
static void Main()
{
Example example = new Example();
// This does not compile: GetEnumerator is required.
foreach (string element in example)
{
Console.WriteLine(true);
}
}
}
Output
error CS1579: foreach statement cannot operate on
variables of type 'Example' because 'Example' does
not contain a public definition for 'GetEnumerator'
So: We forward the details of the implementation to the List. Our IEnumerable implementation relies on another.
Main: Here we call the Example class constructor, which populates the _elements field.
Foreach: The foreach-loop in the Main method implicitly (secretly) calls the GetEnumerator method. So "HERE" is written.
Result: The program compiles. The foreach loop refers to the List's Enumerator and loops over the elements of the List.
C# program that implements IEnumerable
using System;
using System.Collections;
using System.Collections.Generic;
class Example : IEnumerable<string>
{
List<string> _elements;
public Example(string[] array)
{
this._elements = new List<string>(array);
}
IEnumerator<string> IEnumerable<string>.GetEnumerator()
{
Console.WriteLine("HERE");
return this._elements.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this._elements.GetEnumerator();
}
}
class Program
{
static void Main()
{
Example example = new Example(
new string[] { "cat", "dog", "bird" });
// The foreach-loop calls the generic GetEnumerator method.
// ... It then uses the List's Enumerator.
foreach (string element in example)
{
Console.WriteLine(element);
}
}
}
Output
HERE
cat
dog
bird
Program: We test Enumerable.Range, which returns an IEnumerable collection. We enumerate its return value with foreach.
Range, Repeat, EmptyInfo: Other methods, like Enumerable.Repeat and Empty, are available. They can be useful in certain programs.
C# program that uses Enumerable.Range
using System;
using System.Linq;
class Program
{
static void Main()
{
// Get IEnumerable from Enumerable.Range and loop over it.
foreach (int value in Enumerable.Range(100, 2))
{
Console.WriteLine("RANGE(0, 2): {0}", value);
}
}
}
Output
RANGE(0, 2): 100
RANGE(0, 2): 101
Version 1: We loop over the 3 elements in an int array with for each, and sum them. No IEnumerable is involved.
Version 2: We use AsEnumerable to get an IEnumerable of the int array. Then we use foreach over the IEnumerable.
AsEnumerableResult: The IEnumerable foreach-loop is much slower. It is best to access arrays directly for most numeric operations.
C# program that tests IEnumerable performance
using System;
using System.Diagnostics;
using System.Linq;
class Program
{
const int _max = 1000000;
static void Main()
{
int[] values = { 10, 20, 30 };
// Version 1: loop over array directly.
var s1 = Stopwatch.StartNew();
for (int i = 0; i < _max; i++)
{
int sum = 0;
foreach (int value in values)
{
sum += value;
}
if (sum == 0)
{
return;
}
}
s1.Stop();
// Version 2: convert array to IEnumerable and loop over IEnumerable elements.
var s2 = Stopwatch.StartNew();
for (int i = 0; i < _max; i++)
{
int sum = 0;
var enumerable = values.AsEnumerable();
foreach (int value in enumerable)
{
sum += value;
}
if (sum == 0)
{
return;
}
}
s2.Stop();
Console.WriteLine(((double)(s1.Elapsed.TotalMilliseconds * 1000000) /
_max).ToString("0.00 ns"));
Console.WriteLine(((double)(s2.Elapsed.TotalMilliseconds * 1000000) /
_max).ToString("0.00 ns"));
}
}
Output
1.96 ns int[], foreach
25.77 ns IEnumerable int, foreach
Then: Select from the menu one of the options. The first is probably the best choice.
But: But if a single extension method, one receiving IEnumerable, can be implemented, our code base remains smaller.
Tip: A single extension can replace many specific methods. This can help keep programs small and easy to maintain.
Extension