Using the Enumerable Class methods and lambda expressions
This article presents nothing new at all, but sometimes it is nice to freshen your memory when it comes to smooth stuff available in the .NET Framework. I will give a couple of examples to select, count and look up elements in a collection of objects, both using regular functions and by using lambda expressions. The methods I will use are available when using .NET Framework 3.5.
The complete documentation is available on MSDN, in System.Collection.Generic Namespace documentation.
Introduction
I will use some kind of collection with objects of the following type:
class MyObject
{
public int id { get; set; }
public string descr { get; set; }
}
This is a simple class but still enough to show the things I want to show. The collections used will contain a small number of objects, so this will not at all be a matter of measuring performance. I bet the Microsoft guys implementing these methods know what they do.
Take a look at the class below, that will be extended with a couple of new methods for showing the examples. The exList and exArray are initialized in the EnumExamples constructor. I also added two methods to be used later on when showing the use of delegates.
public class EnumExamples
{
List<MyObject> exList;
MyObject[] exArray;
public EnumExamples()
{
exList = new List<MyObject>();
exList.Add(new MyObject() { descr = "Object 1 description", id = 1 });
exList.Add(new MyObject() { descr = "Object 2 description", id = 2 });
exList.Add(new MyObject() { descr = "Object 3 description", id = 3 });
exArray = exList.ToArray();
}
private bool IdGreaterThan(MyObject obj, int val)
{
return obj.id > val;
}
private bool DescrStartsWithValue(MyObject obj, string val)
{
return obj.descr.StartsWith(val);
}
}
Please note the Javascript object literal like construction when creating the objects, called object initializers in .NET.
OK, we’re ready to start showing off!
Examples
List<T> collection
First of all let’s look at some examples using the strongly typed list of objects. The objects in the list will be a couple of MyObject objects, added in the EnumExamples constructor.
Take a look at the method below, added to the EnumExamples class:
public void ListExamples()
{
bool anyResult;
// The Any method, used to find out if the collection contains any object at all
// or any object satisfying the specified criteria.
anyResult = exList.Any();
anyResult = exList.Any(match => match.descr.StartsWith("Object"));
anyResult = exList.Any(
delegate(MyObject obj) { return DescrStartsWithValue(obj, "Object"); });
List<MyObject> findAllResultList;
// The FindAll method returns a collection of objects satisfying the specified critera.
findAllResultList = exList.FindAll(match => match.id > 1);
findAllResultList = exList.FindAll(
delegate(MyObject obj) { return IdGreatetThan(obj, 1); });
MyObject firstResult;
// The First method returns the first object satisfying the specified criteria
firstResult = exList.First(match => match.id > 1);
firstResult = exList.First(delegate(MyObject obj) { return IdGreatetThan(obj, 1); });
try
{
MyObject singleResult;
// The Single method returns the one object satisfying the specified criteria
singleResult = exList.Single(match => match.id > 1);
singleResult = exList.Single(
delegate(MyObject obj) { return IdGreatetThan(obj, 1); });
}
catch (ArgumentNullException)
{ }
catch (InvalidOperationException)
{ }
}
- All methods are pretty straight forward as soon as one get it going with the lambda expressions and delegates.
- The last example, the Single method, is a little bit special. This method returns the ONE object satisfying the specified criteria, meaning that it will look through the whole collection and throw an exception if more than one object satisfies the criteria.
Note the delegate keyword in the example above, used to declare a named or an anonymous method. Please consult MSDN, delegate (C# Reference), for the complete documentation.
More examples will be stated below, using an array of MyObject objects.
T[] collection
The methods available on this collection are much the same as for the List<T> collection above. The following examples will therefore show some of the other methods.
public void ArrayExamples()
{
MyObject[] reverseResultArray;
IEnumerable<MyObject> reverseEnum;
// The Reverse method will return an IEnumerable.
reverseEnum = exArray.Reverse<MyObject>();
// The IEnumerable may be put in an array, using the ToArray<T> method.
reverseResultArray = reverseEnum.ToArray<MyObject>();
IEnumerable<MyObject> skipWhileResultEnum;
// The SkipWhile will return the remaining part of the collection,
// after excluding the first objects until the first positive hit.
// The skipWhileResultEnum will contain only the MyObject object with
// id not less than 2, e.g. the MyObject objects with id == 2 and id == 3.
skipWhileResultEnum = exArray.SkipWhile(match => match.id < 2);
IEnumerable<MyObject> takeWhileResultEnum;
// The TakeWhile method is somewhat the opposite of SkipWhile above.
// This means that the result of this method will contain
// the objects with id == 1 and id == 2.
takeWhileResultEnum = exArray.TakeWhile(
delegate(MyObject obj) { return !IdGreaterThan(obj, 2); });
}
I will not state more examples than this. I hope you get big picture using these methods together with the lambda expressions and delegates.
Summary
As I wrote in the beginning of this article, this is nothing revolutionary but still pretty important to have in mind when working with different kinds of collections.
Personally I think the methods added to the .NET 3.5 Framework with Linq and lambda expressions are really really nice. I think the code will be much easier to read and understand, since the names of the methods are somewhat self explaining.
Please have a good look at the documentation on System.Collection.Generic Namespace and System.Linq Namespace on MSDN.