The IEnumerable Generic Interface

Introduction

We know how to create a LINQ statement by declaring a variable using the var keyword. The var keyword allows you to let the compiler figure out what type of value the statement would produce. To assist you with creating LINQ statements, the .NET Framework provides many interfaces and classes. The interfaces and the classes that implement them are created in the System.Linq namespace defined in the System.Core.dll assembly.

The Enumerable Class

In the .NET Framework, the language integrated query, LINQ, is implemented and supported by a class named Enumerable created in the System.Linq namespace defined in the System.Core.dll assembly. In fact, the LINQ is actually a "visual" or "real" way to use the Enumerable class. This means that, instead of creating a LINQ query, you can use the Enumerable class to query your collection. The problem is that, with Enumerable, you may have to write complex code that involves delegates and/or lambda expressions. As an alternative, the LINQ provides an easier way to create a query with easily recognizable words. Both techniques produce the same result(s).

An important aspect to know about LINQ is that, while the LINQ's role is to make your life easier, if you create a LINQ statement, when it executes, the compiler would actually translate your LINQ statement into an Enumerable expression. This means that when you use a LINQ statement, you are actually using an Enumerable object. To start, Enumerable is a static class:

public static class Enumerable

This means that we will never declare a variable of type Enumerable. We will simply and directly use it. Still, the Enumerable class has all the methods you need to query a collection.

The IEnumerable Collection Interface

As you may know already, a query is primarily one record or a collection of records. The primary classes that support collections in the NET Framework are defined in the System.Collection namespace. To allow the various collections to support iteration, the System.Collection namespace provides an interface named IEnumerable whose only method is named GetEnumerator:

IEnumerator GetEnumerator()

The IQueryable Interface

The LINQ came alive with the .NET Framework 3.5. To support the ability to query a collection class, a new interface named IQueryable was added to the System.Linq namespace:

public interface IQueryable : IEnumerable

When the System.Collection.IEnumerable interface was created in the .NET Framework 3.0, the LINQ was not yet implemented. Later on in the .NET Framework 3.5, to allow the System.Collection.Collection.IEnumerable interface to support LINQ querying, a new method named AsQueryable was added to it as an extension method. Its syntax is:

public static IQueryable AsQueryable(this IEnumerable source);

This method allows an interface and its class implementers to support LINQ.

The IEnumerable Generic Interface

As we have seen so far, a LINQ query consists of selecting one or more records from a list or collection. The list is treated as a collection of records. The lists and generic collections are primarily supported in the .NET Framework from a namespace named System.Collections.Generic. In that namespace, the main interface used to "scan" (or iterate through) a collection is a generic interface named IEnumerable. This interface is derived from its non-generic counterpart:

public interface IEnumerable<out T> : IEnumerable

To make it possible to iterate through a query, all the methods of the Enumerable class were added as extension methods to the IEnumerable<> generic interface. As a result, to decalre a variable for a query, you have various options. In many cases, you can declare the collection variable using the data type of the type of collection the query would produce. In previous sections, we declared the variables as arrays. Here is an example:

namespace SoloMusicStore
{
    public partial class Inventory : Form
    {
        public Exercise()
        {
            InitializeComponent();
        }

        private void Exercise_Load(object sender, EventArgs e)
        {
            string[] storeItems = new string[]
            {
                "Semi-Hollow-Body Electric Guitar",
                "Yamaha MX88 88-Key Weighted Action Synthesizer", 
                "Full Size 5-Piece Acoustic Drum Set",
                "32-Note Xylophone Wooden Glockenspiel",
                "4-String Bass Guitar, Right Handed",
                "Yamaha MX49 Music Production Synthesizer"
            };

            var inventory = from music
                            in storeItems
                            select music;
            
            foreach (var item in inventory)
                lbxStoreItems.Items.Add(item.ToString());
        }
    }
}

This would produce:

Because a query starts from a collection, you can declare the collection variable using IEnumerable<>. Inside < and >, pass the type of the values in the collection. Here is an example:

private void ExerciseLoad(object sender, EventArgs e)
{
    IEnumerable<double> numbers = new double[] { 12.44, 525.38, 6.28, 2448.32, 632.04 };

    var number = from n in numbers select n;

    foreach (var member in number)
        lbxNumbers.Items.Add(member.ToString());
}

Because a query returns a collection, you can declare its variable as IEnumerable<>. Here is an example:

private void ExerciseLoad(object sender, EventArgs e)
{
    IEnumerable<double> numbers = new double[] { 12.44, 525.38, 6.28, 2448.32, 632.04 };

    IEnumerable<double> number = from n in numbers select n;

    foreach (var member in number)
        lbxNumbers.Items.Add(member.ToString());
}

In most cases, you should declare your query variable as var.

Introduction to the List Collection

All the LINQ variables we used in previous lessons were created as arrays. The System.Array class is defined in the System namespace of the System.Runtime.dll assembly. The System.Array class starts as follows:

public abstract class Array : ICloneable,
			      System.Collections.IList,
			      System.Collections.IStructuralComparable,
			      System.Collections.IStructuralEquatable

Notice that the System.Array class implements the IList interface. The IList derives from the System.Collections.ICollection interface defined in the System.Collections namespace of the System.Runtime.dll assembly:

public interface IList : System.Collections.ICollection

The System.Collections.ICollection interface is derived from the IEnumerable interface defined in the System.Collections namespace of the System.Runtime.dll assembly:

public interface ICollection : System.Collections.IEnumerable

It can be valuable to be aware of this hierarchy when you deal with LINQ statements in terms of querying records, iterating through a list, or creating conditions to select records. Being familiar with this hierarchy can also be valuable when you encounter other collections classes. For example, as you may know already, probably the most fundamental class that supports collections in the .NET Framework (since the 2.0 release) is the generic List<> class defined in the System.Collections.Generic interface. As a reminder, the System.Collections.Generic.List<> class starts as follows:

public class List<T> : System.Collections.Generic.ICollection<T>,
		       System.Collections.Generic.IEnumerable<T>,
		       System.Collections.Generic.IList<T>,
		       System.Collections.Generic.IReadOnlyCollection<T>,
		       System.Collections.Generic.IReadOnlyList<T>,
		       System.Collections.IList

As you can see, the System.Collections.Generic.List<> class implements the generic IEnumerable<> interface, which in turn is derived from the non-generic IEnumerable interface:

public interface IEnumerable<out T> : System.Collections.IEnumerable

This means that you can use the List<> class to declare a collection variable used in LINQ. After declaring the variable, you can create a LINQ statement as we saw for an array. Here is an example:

namespace Fundamentals
{
    public partial class Exercise : Form
    {
        public Exercise()
        {
            InitializeComponent();
        }

        private void Exercise_Load(object sender, EventArgs e)
        {
            var numbers = new List<double>();

            numbers.Add(12.44);
            numbers.Add(525.38);
            numbers.Add(6.28);
            numbers.Add(2448.32);
            numbers.Add(632.04);

            var number = from n
                         in numbers
                         select n;

            foreach (var member in number)
                lbxNumbers.Items.Add(member.ToString());
        }
    }
}

The Case for the String Class

In the .NET Framework, the String class starts as follows:

public sealed class String : IComparable, 
                             ICloneable,
                             IConvertible,
                             IComparable<string>,
                             IEnumerable<char>,
                             IEquatable<string>

As you can see, the String class implements:

Based on this, the String class holds a special position in LINQ. If you create a LINQ statement whose select expression produces a string value, the String class makes available its properties and methods so you can use them to refine your where statement.

Converting a Query to a Collection

Converting a LINQ Result to an Array

We have seen that a LINQ expression produces a list of values and, so far, the resulting list was stored in a variable created in a from clause. If you want, you can store the result of the LINQ expression in a specific (or external) variable. To support this, the Enumerable class is equipped with a method named ToArray. The syntax of the Enumerable.ToArray() method is:

public static TSource[] ToArray<TSource>(this IEnumerable<TSource> source;)

To store the results of an IEnumerable<> list in an array, declare the array variable and assign the resulting list to it. You can then use that new array variable for the results of the query. Here is an example:

namespace Numerotation
{
    public partial class Exercise : Form
    {
        public Exercise()
        {
            InitializeComponent();
        }

        private void Exercise_Load(object sender, EventArgs e)
        {
            IEnumerable<string> @class = new[] { "True Positive", "True Negative", "False Positive", "False Negative" };

            IEnumerable<string> classifications = from cls in @class select cls;

            string[] array = classifications.ToArray();

            foreach (var member in array)
                txtClassification.Text = txtClassification.Text + member.ToString() + Environment.NewLine;
        }
    }
}

This would produce:

Although Enumerable.ToArray() is a generic method, you don't need to specify the parameter type, whicn in this case is <double>.

In the above code, we declared a variable to store the array-converted query. This can be necessary if you are planning to use such a result in some calculations. If not, you can convert the quary statement directly where it is created. To do this, put the query statement in parentheses and call the ToArray() method the closing parentheses. Here is an example:

namespace BinaryClassification
{
    public partial class Exercise : Form
    {
        public Exercise()
        {
            InitializeComponent();
        }

        private void Exercise_Load(object sender, EventArgs e)
        {
            IEnumerable<string> @class = new[] { "True Positive", "True Negative", "False Positive", "False Negative" };

            string[] array = (from cls in @class select cls).ToArray();

            foreach (var member in array)
                txtClassification.Text = txtClassification.Text + member.ToString() + Environment.NewLine;
        }
    }
}

After converting a query to an array and storing the result in an array variable, the variable now holds an array and you can use that variable to access the members of the Array, which is the parent of every array variable you declare in your application.

Converting a Query Result to a Generic List

An array is just one type of list. It follows some rules on indexes, positions, etc. In some cases, once you have created a query, you may want to use it as a classic list. To assist you with this, the Enumerable class is equipped with a method named ToList. Its syntax is:

public static List<TSource> ToList<TSource>(this IEnumerable<TSource> source);

Based on this, to convert a query to a List<> generic type of object, you can declare a List<> variable, assign a query to it, and call the ToList() method on it. Once you have performed this conversion, you can use the variable as a List<> object. This means that you can access the members of the List<> class to perform the desired operations, such as adding new items or sorting the list. Here are examples:

namespace Numerotation
{
    public partial class Exercise : Form
    {
        public Exercise()
        {
            InitializeComponent();
        }

        private void Exercise_Load(object sender, EventArgs e)
        {
            IEnumerable<string> storeItems = new string[]
            {
                "Semi-Hollow-Body Electric Guitar",
                "Yamaha MX88 88-Key Weighted Action Synthesizer",
                "Full Size 5-Piece Acoustic Drum Set",
                "32-Note Xylophone Wooden Glockenspiel",
                "4-String Bass Guitar, Right Handed",
                "Yamaha MX49 Music Production Synthesizer"
            };

            var inventory = from music
                            in storeItems
                            select music;

            foreach (var item in inventory)
                lbxStoreItems.Items.Add(item.ToString());

	    // Converting a query to a List<>
            List<string> items = inventory.ToList();

	    // Access the members of a List<>
            items.Add("16-key flute Nickel-plated");
            items.Add("JD-XI 37-Key Interactive Analog/Digital Crossover Synthesizer");
            items.Sort();

            foreach (var item in items)
                lbxInventory.Items.Add(item.ToString());
        }
    }
}

This would produce:

Converting a Query Result to a Generic List

Converting a Query Result to a Dictionary Type

A dictionary is a type of list where each item is made of a combination of a key and a value. To let you convert a query result to a dictionary type of list, the Enumerable class is equipped with a method named ToDictionary.

A Query as an Object

Introduction

As mentioned above, a LINQ query is in fact an object of type IEnumerable<>. As a result, every operation we have performed so far produces an IEnumerable<> object. For example, so far, we have learned to create LINQ variables as arrays or IEnumerable<> objects.

Returning a Query

Instead of processing a query locally, you can hand the job to a function or method that would return the query. To create a method that returns a query, specify its return type as IEnumerable<>. Make sure you specify the desired parameter type in the <> operator. In the body of the method, create a (the) LINQ statement(s) as you see fit. Before the method closes, you can return a variable that holds a LINQ expression. Here is an example:

namespace Exercises
{
    public partial class Exercise : Form
    {
        public Exercise()
        {
            InitializeComponent();
        }

        private IEnumerable<double> Produce()
        {
            var numbers = new double[] { 12.44, 525.38, 6.28, 2448.32, 632.04 };

            var values = from n
                         in numbers
                         select n;

            return values;
        }

        private void Exercise_Load(object sender, EventArgs e)
        {
            var result = Produce();

            foreach (var member in result)
                lbxNumbers.Items.Add(member.ToString());
        }
    }
}

In the above example, we first declare a variable and used that variable as the return value of the function. This can be necessary if you are planning to use the query or variable many times. If you will need the query only once, you can create it directly where it is returned. Here is an example:

namespace Exercises
{
    public partial class Exercise : Form
    {
        public Exercise()
        {
            InitializeComponent();
        }

        private IEnumerable<double> Produce()
        {
            return from n
                   in new double[] { 12.44, 525.38, 6.28, 2448.32, 632.04 }
                   select n;
        }

        private void Exercise_Load(object sender, EventArgs e)
        {
            var result = Produce();

            foreach (var member in result)
                lbxNumbers.Items.Add(member.ToString());
        }
    }
}

Passing a Query

Because a LINQ expression is primarily a value, it can be passed as argument to a function. To proceed, start a function. in its parentheses, create an IEnumerable<> parameter. In the body of the function, you can ignore the argument. Otherwise, treat the argument as a LINQ expression. Here is an example:

namespace Exercises
{
    public partial class Exercise : Form
    {
        public Exercise()
        {
            InitializeComponent();
        }

        private IEnumerable<double> Produce()
        {
            return from n
                   in new double[] { 12.44, 525.38, 6.28, 2448.32, 632.04 }
                   select n;
        }

        private void Present(IEnumerable<double> result)
        {
            foreach (var member in result)
                lbxNumbers.Items.Add(member.ToString());
        }

        private void Exercise_Load(object sender, EventArgs e)
        {
            var result = Produce();

            Present(result);
        }
    }
}

Remember that you declare a variable if you are planning to use a value many times. If not, you can omit the variable. From our example, you can call the function directly where its value is needed. Here is an example:

namespace Exercises
{
    public partial class Exercise : Form
    {
        public Exercise()
        {
            InitializeComponent();
        }

        private IEnumerable<double> Produce()
        {
            return from n
                   in new double[] { 12.44, 525.38, 6.28, 2448.32, 632.04 }
                   select n;
        }

        private void Present(IEnumerable<double> result)
        {
            foreach (var member in result)
                lbxNumbers.Items.Add(member.ToString());
        }

        private void Exercise_Load(object sender, EventArgs e)
        {
            Present(Produce());
        }
    }
}

As a result, if you have a function that expects a LINQ expression as argument, if you not planning to use that expression many times, you can pass it directly to the function you are calling. Here is an example:

namespace Exercises
{
    public partial class Exercise : Form
    {
        public Exercise()
        {
            InitializeComponent();
        }

        private void Present(IEnumerable<double> result)
        {
            foreach (var member in result)
                lbxNumbers.Items.Add(member.ToString());
        }

        private void Exercise_Load(object sender, EventArgs e)
        {
            Present(from n
                    in new double[] { 12.44, 525.38, 6.28, 2448.32, 632.04 }
                    select n);
        }
    }
}

Previous Copyright © 2008-2023, FunctionX, Inc. Tuesday 15 November 2022 Next