.NET Collection Management with C# 3.0

Generics in C#, enable you to define classes, interfaces, delegates or methods with placeholders for parameterized types used within. This allows you to define classes that use a generic type, and define the type at the time of instantiation or method calls. This makes your code strongly typed, but makes maintenance easier.
Prasanna describes the improvements in .NET v3.5

Using C# 3.0 to manage a collection of objects

This article looks into some of the new features in C# 3.0 and introduces Linq in managing a collection of objects within a generic List

Introduction

A couple of years ago, I wrote an article entitled “.NET Collection Management” for Simple-Talk. The purpose of that article was to introduce generics and to show how generics can be used to manage a collection of strongly typed objects within a generic List using C# 2.0. Generics allow us to write code without binding the code to a particular type, and at the same time ensures we can use strongly typed objects. I thought I’d revisit the article to see how much my code would be simplified and improved in C# 3.0, and introduce some of the new features in C# 3.0.

Let us define an Employee class that we will be using throughout the examples in this article. The Employee class has the properties Name and Salary.

We have omitted the implementation of the properties because their implementation is very simple.  You set a value to a private field and get the value from a private field. So we are going to let the compiler implement the properties for us. This is a feature called “Automatic Properties” that saves a few lines of code and improves the readability of the code when the property implementation is very simple.

Next we will define and use a collection of Employee objects using a List<T>.

In this code, we have used a special syntax in initializing the property values at the time of creating Employee objects. This is a feature called “Property Initialization” that provides a very easy way of initializing one or more properties when creating an object.

Sorting a List

We can use the Comparison delegate and pass it into the Sort method of List<Employee>. In the following code we will use an anonymous method to pass the instance of a Comparison delegate to do the sorting operation. The anonymous method simplifies the call to the Sort method since we do not need to define a separate method.

We could have written this code in C# 2.0. But in C# 3.0 we can further simplify the implementation by using Lambda expressions for method implementations. Lambda expression is an inline method implementation that is translated to an instance of a delegate by the compiler. These expressions use the syntax “(parameter 1, parameter 2 …) => method implementation”. Lambda expressions allow us to define methods on the fly with a simpler syntax compared to anonymous methods. So the above code can be simplified by using the Lambda expression syntax as follows:

By using the Lambda expression, I have omitted defining the type for emp1 and emp2. Since the Sort method accepts an instance of a Comparison delegate for Employee objects, the compiler is intelligent enough to understand that emp1 and emp2 has to refer to Employee objects. The expression “(emp1, emp2) => emp1.Salary.CompareTo(emp2.Salary)” will be translated to an instance of the Comparison delegate.

Another way of sorting the generic List is by using the static method Enumerable.OrderBy. This method will return an ordered collection of Employee objects

The OrderBy method is an extension method. An “Extension method” is a new feature in C# 3.0 that allows you to call a static method belonging to a class as if it is an instance method  belonging to an object. This also allows us to extend types which normally we might not be able to extend. So the OrderBy method can be called as if it is an instance method because it is an extension method. The compiler would replace it as a call to the static Enumerable.OrderBy extension method:

Searching a List

The generic List has the methods Find or FindAll to search for one or more objects within the List. Both these methods accept an instance of the Predicate delegate as a parameter. The Predicate delegate instance can be defined by creating a method or an anonymous method or a lambda expression.

We can also use the Enumerable.Where extension method to search within the generic List. The following code segment returns a collection of Employee objects where the Salary property value is greater than 1000.

There are many operations that are available through extension methods that can be performed on objects within a List. Most of these operations require looping through the objects within the collection. But with the use of extension methods, we can perform these operations without the need to loop through the collection.

For example let us assume we want to retrieve the maximum Salary amount within the collection of Employee objects within List<Employee>. We can use the Max extension method as show in the below code:

Similarly we can use many other operations such as Min, Sum, and Count that are available.

List Conversion

Converting a List of one type to a List of another type is very simple. We can still use the Converter delegate that was available in C# 2.0. Another way of converting the type of a List is to use the Enumerable.Select extension method.

This method call would return a collection of employee names. However, let’s assume that we want to convert the collection of Employee objects into a collection of objects that has the name of the employee and a boolean value indicating whether the employee has a salary over 1000. We would need to create a new type as a class or a structure that has a string property and a boolean property. C# 3.0 supports a new feature called “Anonymous Types” that allows us to define types on the fly.

We’ve defined a new type that has the properties Name and BigSalary. Another thing that you might have noticed here is the use of the new keyword “var”. This is a new feature called “Type Inference”.  Type inference is used when we do not know the name of the type of the variable and we require the compiler to help us out in inserting the name of the type. This is used with anonymous types, since the compiler defines the type anonymously.

Linq

We went through sorting, searching, performing operations and converting a collection of Employee objects in a generic List. The extension methods OrderBy and Where returns an IEnumerable of the type that we use within the generic List – in this instance the Employee type. The extension method Select return an IEnumerable of the type we want to convert the employee objects to. We can combine these extension methods to search, sort and convert the objects within the generic List

This is where Linq comes in. Linq stands for Language INtegrated Query and provides a SQL like syntax for accomplishing what we did in the above code.

This code uses Linq to query the collection of Employee objects. The syntax is very similar to SQL except that  the select clause is at the end of the query expression. It makes sense because the process of converting the objects within the generic List would be the last step. Each expression in the Linq statement followed by the where, orderby and select keywords are lambda expressions. These lambda expressions are used to make method calls to the extension methods as shown in the above examples.

Conclusion

This article looks at the capabilities of the new features in C# 3.0 that helps to better handle collection of objects. It also introduces language integrated query and how it helps in managing collections.