BlackWaspTM

This web site uses cookies. By using the site you accept the cookie policy.This message is for compliance with the UK ICO law.

LINQ
.NET 3.5+

LINQ Generation Operators

The sixteenth part of the LINQ to Objects tutorial considers the generation operators. Language-Integrated query provides three such standard query operators that generate new enumerable sequences based upon simple parameter values.

Generation Operators

Language-Integrated Query (LINQ) provides three standard query operators that fall into the category of generation operator. This means that the method returns a new sequence that implements the IEnumerable<T> interface without requiring that a similar sequence is provided beforehand. This allows the creation of some common types of sequence, array or collection using a single expression, rather than creating lists manually and populating them using loops.

In this article we will look at the generation operators and provide simple examples of their usage.

Range

The first, and possibly the most commonly used, generation operator is Range. This is a static method of the Enumerable class that creates a set of sequential integers. The method has two parameters. The first specifies the value that will be the first item in the resultant data. The second parameter determines the number of integers that will be generated. If, for example, the start value is ninety-one and the number of elements is ten, the new sequence will contain all of the integers from ninety-one to one hundred:

var range = Enumerable.Range(91, 10); // 91, 92, 93, 94, 95, 96, 97, 98, 99, 100

The Range method takes advantage of deferred execution so the returned value is an IEnumerable<int> that contains the details required to build the sequence, rather than the data itself. This improves efficiency and performance when combined with other operators, such as in the following example. Here the Select operator is used with the range to obtain the first eight powers of two:

var powers = Enumerable.Range(1, 8).Select(x => Math.Pow(2, x));

// 2, 4, 8, 16, 32, 64, 128, 256

You can convert the return value of the Range method, and of the other generation operators that we will see, to an array or list using a conversion operator. The following code creates an array of integers containing the values between one and one hundred in a single line of code:

int[] oneToOneHundred = Enumerable.Range(1, 100).ToArray();

Repeat

The Repeat operator creates a sequence of values of a specified length. Every item in the new sequence has the same value, which is specified using an argument of the method and that may be of any type. As with Repeat, this method uses deferred execution. We can demonstrate the use of Repeat by executing the following code, which creates a set of five matching strings.

var repeated = Enumerable.Repeat("Hello", 5);

// "Hello", "Hello", "Hello", "Hello", "Hello"

Care must be taken with the Repeat operator when creating sequences of reference types. When you create such a list, each item has the same reference. If you modify a property of one of the items in the sequence, every other item will reflect that change. To demonstrate, add the following class to your test project:

class Test
{
    public int Value { get; set; }
}

We can now create an array containing several Test objects, as follows:

var testObjects = Enumerable.Repeat(new Test(), 5).ToArray();

If we modify the Value property of any of the five Test objects, the property will change in all of the other objects, as each is a reference to the same underlying memory. Below we modify the value of the first element of the array and output the value of the fourth object.

testObjects[0].Value = 99;
Console.WriteLine(testObjects[3].Value);    // 99

If you wish to create a sequence of reference types where each is a different object, you must add an extra step. This is shown in the sample below. Here a sequence of arbitrary values is created using the Repeat method; all of the items contain zero but this is unimportant. The Select operator is used to create a new Test object for each of the elements without actually using any of the zero values. The result is that each value causes a new instance of Test to be generated:

var testObjects = Enumerable.Repeat(0, 5).Select(x => new Test()).ToArray();

testObjects[0].Value = 99;
Console.WriteLine(testObjects[0].Value);    // 99
Console.WriteLine(testObjects[3].Value);    // 0

Empty

The simplest of the three generation operators is Empty. As the name suggests, this method returns an empty, or zero-length, sequence of values. No standard parameters are used by the method but the type T of the resultant IEnumerable<T> must be provided as a type parameter:

var empty = Enumerable.Empty<Test>();
24 October 2010