Using generics

By Ludwig Stuyck (Ludwig.Stuyck@ctg.com)
Last update: 28 February 2007

G

enerics are one of the most useful improvements in the .NET 2.0 framework. In this article I start with pointing out the disadvantages of using the classical arrays and .NET collections, and then I show you how generics provide a nice and elegant way of creating flexible and performant strongly typed collections with sorting capabilities. I also explain the use of predicates to implement custom behavior, and how you can create your own generic classes. Along the way constraints, generic methods, properties and interfaces are explained. Then I demonstrate how you can data bind a generic collection to a DataGridView control and how to serialize/deserialize the collection. Finally I use the power of LINQ to query a generic collection.

Using arrays
Arrays provide a way to create strongly typed collections, for example:
int[] numbers = new int[] { 1, 2, 3, 4, 5 }; string[] names = new string[] { "Ludwig", "Leen" };

However, they are very limited: they can’t grow (they are rather static), and you don’t have any convenience methods (like sorting, iterating …). In some cases arrays will be sufficient, but mostly you need more flexibility. And more flexibility we get with the .NET collection classes, like ArrayList.

Creating a simple collection with ArrayList
You have probably already used an ArrayList to create a collection of objects. It’s a very simple and fast method, and it does the job, right? Let’s say, for example, you need to create a collection of numbers and calculate the sum.
Page 1 of 51

Ctg Technical Articles Create a little console application, call it Generics1, and add following code in the Main method:
using using using using System; System.Collections.Generic; System.Text; System.Collections;

namespace Generics1 { class Program { static void Main(string[] args) { // Create collection of numbers ArrayList numbers = new ArrayList(); numbers.Add(1); numbers.Add(5); // Calculate int totalSum foreach (int { totalSum } total sum = 0; number in numbers) += number;

Console.WriteLine(totalSum); } } }

It works perfectly, and the program will write the result (6) to the console.

But this is not very elegant code, and I’ll tell you why. First of all, an ArrayList is not strongly typed. And if you look at the signature of the Add method, you’ll see that it accepts a parameter of type object. So instead of adding integers to the collection, you can add every kind of object, for example, a string:
numbers.Add("some string");

This is a perfectly legal code, but when you run it, an InvalidCastException is thrown because in the loop it will try to add the string to a number. Of course, Using generic– By Ludwig Stuyck Page 2 of 51

Ctg Technical Articles we know that adding a string is not valid, but the compiler will allow it anyway: there’s no compile-time checking possible. Also, there’s a lot of casting going on: when you add a number to the collection, there’s an implicit upcast to an object; and visa versa: in the loop the objects are unboxed again to integers. Boxing and unboxing are very time-consuming operations and should be avoided, because they degrade performance. This effect of boxing/unboxing can be quite significant in scenarios where you must iterate large collections.

Creating a strongly typed collection
In version 1.1 of the .NET framework, we could make our own strongly typed collections by creating classes that inherit from existing framework collection classes (like ArrayList), or by creating classes that inherit from abstract classes (like CollectionBase or DictionaryBase). For example, let’s create a strongly typed collection for a business object Person. Create a new console application, call it Generics2, and add a new class called Person:
public class Person { private string name = string.Empty; public string Name { get { return name; } set { name = value; } } private string location = string.Empty; public string Location { get { return location; } set { location = value; } } private int age = 0; public int Age { get { return age; } set { age = value; } } public Person(string name, string location, int age) { this.name = name; this.location = location; this.age = age; } }

Using generic– By Ludwig Stuyck

Page 3 of 51

Ctg Technical Articles Then add a new class called PersonCollection and create the strongly typed collection:
using using using using System; System.Collections.Generic; System.Text; System.Collections;

public class PersonCollection : CollectionBase { public Person this[int index] { get { return (Person)List[index]; } set { List[index] = value; } } public int Add(Person person) { return List.Add(person); } public void Insert(int index, Person person) { List.Insert(index, person); } public void Remove(Person person) { List.Remove(person); } public bool Contains(Person person) { return List.Contains(person); } // Add other type-safe methods here }

Now we can use our strongly typed collection as follows:
using System; using System.Collections.Generic; using System.Text; namespace Generics2 {

Using generic– By Ludwig Stuyck

Page 4 of 51

Ctg Technical Articles
class Program { static void Main(string[] args) { // Create some persons Person person1 = new Person("Ludwig Stuyck", "Zaventem", 33); Person person2 = new Person("Leen Rans", "Zaventem", 25); // Create collection and add customers PersonCollection persons = new PersonCollection(); persons.Add(person1); persons.Add(person2); // Write persons to console foreach (Person person in persons) { Console.WriteLine("{0}, {1}, {2}", person.Name, person.Location, person.Age); } } } }

As you see, we can only add objects of type Person to the person’s collection. If we would add another type of object, the compiler would give an error. So we have created a strongly typed collection that only accepts Person objects; however, there’s still a lot of casting going on in our PersonCollection class. As expected, the output is:

Generics
Time to introduce a new feature of .NET framework 2.0: generics. Generics in C# support defining algorithms and defer the data type until the point of use. They are a type of data structure that contains a code that remains the same; however, the data type of the parameters can change with each use. So in general, it’s a code template that can be applied to use the same code, using various types. They are also called parameterized types or parametric polymorphism. Generics have a number of important advantages:

Using generic– By Ludwig Stuyck

Page 5 of 51

Ctg Technical Articles

Type safety: generic classes work with a well-determined object type. Binary code reuse: generic code is generated at run-time, so different usages of a generic type reuse most of the time the same JIT-code. Performance: type checking is done at compile time, not at run-time; and boxing/unboxing of values is unnecessary, so generics are a lot faster. Clarity: constraints make it clear what type of object a generic type can handle. Let’s explain this further with an example. Create a new console application and call it Generics3. Again, add the business object Person that we defined earlier. Then, in the Main method, create a collection of Person objects as follows:
using System; using System.Collections.Generic; using System.Text; namespace Generics3 { class Program { static void Main(string[] args) { // Create some persons Person person1 = new Person("Ludwig Stuyck", "Zaventem", 33); Person person2 = new Person("Leen Rans", "Zaventem", 25); // Create collection and add persons List<Person> persons = new List<Person>(); persons.Add(person1); persons.Add(person2); // Write customers to console foreach (Person person in persons) { Console.WriteLine("{0}, {1}, {2}", person.Name, person.Location, person.Age); } } } }

And the result is:

Using generic– By Ludwig Stuyck

Page 6 of 51

Ctg Technical Articles

As you see, we can define a strongly typed list in first line:
List<Person> persons = new List<Person>();

You can immediately see the huge advantage because we don’t have to write our custom collection classes (like PersonCollection) anymore! Moreover, there’s no need for casting objects. We could in the same way define and use a collection that holds integers:
// Create collection and add numbers List<int> numbers = new List<int>(); numbers.Add(1); numbers.Add(5); // Calculate int totalSum foreach (int { totalSum } sum = 0; number in numbers) += number;

Console.WriteLine(totalSum);

Finding an object in a List<> collection
Suppose we want to find a specific person in the persons list. We can easily do so thanks to predicates. A predicate represents the method that defines a set of criteria and determines whether the specified object meets those criteria. Let’s see how it works in the following example. First, we create a PersonNameFilter class that implements a method FilterByName. This class contains a name variable that contains the name of the customer that we want to find.
public class PersonNameFilter {

Using generic– By Ludwig Stuyck

Page 7 of 51

Ctg Technical Articles
private string name = string.Empty; public PersonNameFilter(string name) { this.name = name; } public bool FilterByName(Person person) { return person.Name.Equals(name); } }

This class is then used to look for a specific person:
// Create some persons Person person1 = new Person("Ludwig Stuyck", "Zaventem", 33); Person person2 = new Person("Leen Rans", "Zaventem", 25); // Create collection and add persons List<Person> persons = new List<Person>(); persons.Add(person1); persons.Add(person2); // Create a new person name filter, that will look // for the specified name PersonNameFilter personNameFilter = new PersonNameFilter("Ludwig Stuyck"); // Create a new predicate, that uses the FilterByName method // to determine whether the person has been found Predicate<Person> filterByName = new Predicate<Person>(personNameFilter.FilterByName); // Find the person in the collection Person foundPerson = persons.Find(filterByName);

When the Find method is called, the FilterByName method is executed for each person in the collection, until the expression in the method returns true. When the method returns true, the current Person object will be returned by the Find method. When the method never returns true (so the person that is searched for is not in the collection), then the Find method will return null.

Finding an object collection in a List<> collection
Suppose we need to look for persons that live in Zaventem. We create a new class PersonLocationFilter, which contains a method FilterByLocation:
public class PersonLocationFilter

Using generic– By Ludwig Stuyck

Page 8 of 51

Ctg Technical Articles
{ private string location = string.Empty; public PersonLocationFilter(string location) { this.location = location; } public bool FilterByLocation(Person person) { return person.Location.Equals(location); } }

And again we can use the Find method to look for the persons that lives in Zaventem:
// Create a new person location filter, that will look for the specified location PersonLocationFilter personLocationFilter = new PersonLocationFilter("Zaventem"); // Create a new predicate, that uses the FilterByLocation method // to determine whether the person has been found Predicate<Person> filterByLocation = new Predicate<Person>(personLocationFilter.FilterByLocation); // Find the person in the collection Person foundPerson = persons.Find(filterByLocation);

However, there is more than one person living in Zaventem, and we want to find them all. We can do so by using the FindAll method:
List<Person> foundPersons = persons.FindAll(filterByLocation);

This method will return a collection of Person objects, instead of a single Person object. When the FindAll method is executed, the FilterByLocation method is executed for each person in the collection. Every time the FilterByLocation method returns true, the current Person object is added to the resulting collection.

Iterating a list to perform operations
Suppose you want to find the oldest person in the collection. You could do it like this:
int oldestAge = 0; foreach (Person person in persons) { if (person.Age > oldestAge) oldestAge = person.Age;

Using generic– By Ludwig Stuyck

Page 9 of 51

Ctg Technical Articles
} Console.WriteLine("{0}", oldestAge);

However, there’s a new, more object oriented way of doing this. First, create a class PersonAgeCalculator that is responsible for the calculation, as follows:
public class PersonAgeCalculator { private int oldestAge = 0; public int OldestAge { get { return oldestAge; } set { oldestAge = value; } } public void CalculateOldestAge(Person person) { if (person.Age > oldestAge) oldestAge = person.Age; } }

And then, create an Action object and pass it on to the ForEach method of the person collection:
// Create a new person age calculator PersonAgeCalculator personAgeCalculator = new PersonAgeCalculator(); // Create a new action, that corresponds to the // CalculateOldestAge method Action<Person> action = new Action<Person>(personAgeCalculator.CalculateOldestAge); // Execute the action for each person in the collection persons.ForEach(action); Console.WriteLine("{0}", personAgeCalculator.OldestAge);

Sorting generic lists
Sorting a generic list can be done by calling the Sort method on the list. However, to make this work, the objects in the list must know how to compare themselves. In our example, the Person objects need to know how to compare each other. We can do so by implementing the IComparable interface, meaning we have to implement the CompareTo method:
public class Person : IComparable { private string name = null; public string Name {

Using generic– By Ludwig Stuyck

Page 10 of 51

Ctg Technical Articles
get { return name; } set { name = value; } } private string location = null; public string Location { get { return location; } set { location = value; } } private int age = 0; public int Age { get { return age; } set { age = value; } } public Person(string name, string location, int age) { this.name = name; this.location = location; this.age = age; } public int CompareTo(object obj) { Person person = (Person)obj; return this.name.CompareTo(person.Name); } }

As you see, the Person class knows now that it has to compare the Name property if two objects are compared. Now we can use the Sort method:
static void Main(string[] args) { // Create some persons Person person1 = new Person("Leen", "Steenokkerzeel", 32); Person person2 = new Person("Ludwig", "Steenokkerzeel", 29); Person person3 = new Person("Paulien", "Zaventem", 2); // Create collection and add persons List<Person> persons = new List<Person>(); persons.Add(person1); persons.Add(person2); persons.Add(person3); // Write persons to console foreach (Person person in persons) { Console.WriteLine("{0}, {1}, {2}", person.Name, person.Location, person.Age);

Using generic– By Ludwig Stuyck

Page 11 of 51

Ctg Technical Articles
} Console.WriteLine(); // Sort collection persons.Sort(); // Write sorted persons to console foreach (Person person in persons) { Console.WriteLine("{0}, {1}, {2}", person.Name, person.Location, person.Age); } }

The output is:

So sorting works. There is still room for some improvement here. Notice that there was still casting needed in the CompareTo method, when we implemented the IComparable interface. Indeed, the IComparable interface forces us to implement the CompareTo method, which takes an object as a parameter:
public int CompareTo(object obj) { // Cast object back to a Person first Person person = (Person)obj; return this.name.CompareTo(person.Name); }

As we have said before, we should avoid casting, and that’s what we’ll do next. The solution to this problem is generic interfaces. Instead of implementing the IComparable interface, we will implement its generic counter part, the IComparable<Person> interface:
public class Person : IComparable<Person> { private string name = null;

Using generic– By Ludwig Stuyck

Page 12 of 51

Ctg Technical Articles
public string Name { get { return name; } set { name = value; } } private string location = null; public string Location { get { return location; } set { location = value; } } private int age = 0; public int Age { get { return age; } set { age = value; } } public Person(string name, string location, int age) { this.name = name; this.location = location; this.age = age; } public int CompareTo(Person person) { return this.name.CompareTo(person.Name); } }

As a consequence, the CompareTo method does not have an object parameter anymore, but a parameter of type Person, avoiding any casting.

Extending sorting
In the previous example we implemented sorting. But, we did not have the possibility to specify on which property the sort should be done. It would be nice if we could sort the collection by another property. First of all, we will create our own custom implementation of IComparer. We’ll add a new class PersonComparer, that implements the generic interface IComparer<Person>. This class knows about Person objects, and knows how to sort them. But before we do that, create an enumeration with supported comparison types:
// Enumeration of comparison types public enum PersonComparisonType {

Using generic– By Ludwig Stuyck

Page 13 of 51

Ctg Technical Articles
Name, Location, Age };

And now, implement the PersonComparer class:
public class PersonComparer : IComparer<Person> { private PersonComparisonType comparisonType = PersonComparisonType.Name; public PersonComparisonType ComparisonType { get { return comparisonType; } set { comparisonType = value; } } public PersonComparer(PersonComparisonType comparisonType) { this.comparisonType = comparisonType; } public bool Equals(Person lhs, Person rhs) { return this.Compare(lhs, rhs) == 0; } // Tell the Person objects to compare themselves public int Compare(Person lhs, Person rhs) { return lhs.CompareTo(rhs, comparisonType); } }

The idea is to pass an instance of this class to the Sort method of the List. In the class we implemented the method Compare, and here we use a new method CompareTo of the Person objects to do the comparison, passing the ComparisonType. So we will add this method to the Person class.
public class Person : IComparable<Person> { private string name = null; public string Name { get { return name; } set { name = value; } } private string location = null; public string Location { get { return location; }

Using generic– By Ludwig Stuyck

Page 14 of 51

Ctg Technical Articles
set { location = value; } } private int age = 0; public int Age { get { return age; } set { age = value; } } public Person(string name, string location, int age) { this.name = name; this.location = location; this.age = age; } public int CompareTo(Person person) { return this.name.CompareTo(person.Name); } // Special implementation to be called by custom comparer public int CompareTo(Person person, PersonComparisonType comparisonType) { switch (comparisonType) { case PersonComparisonType.Name: return this.name.CompareTo(person.Name); case PersonComparisonType.Age: return this.age.CompareTo(person.Age); case PersonComparisonType.Location: return this.location.CompareTo(person.Location); } return 0; } }

Depending on the passed comparison type, the correct properties are compared to each other. Now we can use the PersonComparer class to sort the collection, for example using age:
static void Main(string[] args) { // Create some persons Person person1 = new Person("Leen", "Steenokkerzeel", 32); Person person2 = new Person("Ludwig", "Steenokkerzeel", 29); Person person3 = new Person("Jonathan", "Zaventem", 7); // Create collection and add persons List<Person> persons = new List<Person>(); persons.Add(person1);

Using generic– By Ludwig Stuyck

Page 15 of 51

Ctg Technical Articles
persons.Add(person2); persons.Add(person3); // Write persons to console foreach (Person person in persons) { Console.WriteLine("{0}, {1}, {2}", person.Name, person.Location, person.Age); } Console.WriteLine(); // Sort collection using age PersonComparer personComparer = new PersonComparer(PersonComparisonType.Age); persons.Sort(personComparer); // Write sorted persons to console foreach (Person person in persons) { Console.WriteLine("{0}, {1}, {2}", person.Name, person.Location, person.Age); } }

And the output is:

Extending sorting once more
In the previous example we could already set the property we wanted to sort on, but the items are always sorted in an ascending way. Maybe you want this to be descending… Let’s implement this. First, create a SortOrderType enumeration:
// Enumeration of sorder order types public enum SortOrderType { Ascending, Descending };

Using generic– By Ludwig Stuyck

Page 16 of 51

Ctg Technical Articles

Add a SortOrder property to the PersonComparer class, and use this property in the Compare method to determine the comparison method:
public class PersonComparer : IComparer<Person> { private PersonComparisonType comparisonType = PersonComparisonType.Name; public PersonComparisonType ComparisonType { get { return comparisonType; } set { comparisonType = value; } } private SortOrderType sortOrder = SortOrderType.Ascending; public SortOrderType SortOrder { get { return sortOrder; } set { sortOrder = value; } } public PersonComparer(PersonComparisonType comparisonType) { this.comparisonType = comparisonType; } public bool Equals(Person lhs, Person rhs) { return this.Compare(lhs, rhs) == 0; } // Tell the Person objects to compare themselves public int Compare(Person lhs, Person rhs) { switch (sortOrder) { case SortOrderType.Ascending: default: return lhs.CompareTo(rhs, comparisonType); case SortOrderType.Descending: return rhs.CompareTo(lhs, comparisonType); } } }

Now you can use the SortOrder property to set the sort order:
static void Main(string[] args) { // Create some persons Person person1 = new Person("Leen", "Steenokkerzeel", 32); Person person2 = new Person("Ludwig", "Steenokkerzeel", 29);

Using generic– By Ludwig Stuyck

Page 17 of 51

Ctg Technical Articles
Person person3 = new Person("Jonathan", "Zaventem", 7); // Create collection and add persons List<Person> persons = new List<Person>(); persons.Add(person1); persons.Add(person2); persons.Add(person3); // Write persons to console foreach (Person person in persons) { Console.WriteLine("{0}, {1}, {2}", person.Name, person.Location, person.Age); } Console.WriteLine(); // Sort collection using age PersonComparer personComparer = new PersonComparer(PersonComparisonType.Age); personComparer.SortOrder = SortOrderType.Descending; persons.Sort(personComparer); // Write sorted persons to console foreach (Person person in persons) { Console.WriteLine("{0}, {1}, {2}", person.Name, person.Location, person.Age); } }

Generic classes
You can also create your own generic classes. Generic classes encapsulate operations that are not specific to any particular data type. As an example, let’s create our own generic class Tree. This tree will represent an in-memory hierarchical representation of objects of type T. Create a new console application and call it Generics4. Add the Person class again and then define a generic class Tree as follows:
public class Tree<T> { }

If we want to use this tree (of course, the Tree class does not do anything yet) in our code, we could create an instance as follows:
static void Main(string[] args) {

Using generic– By Ludwig Stuyck

Page 18 of 51

Ctg Technical Articles
// Create the generic tree that will work with Person objects Tree<Person> personHierarchy = new Tree<Person>(); }

Let’s implement the tree now. A tree consists out of tree nodes that can work with this type T, so we’ll need a TreeNode class, which is also a generic class:
public class TreeNode<T> { }

The top of the tree hierarchy is a root node, so we’ll add a RootNode property to the Tree class, so this is a generic property:
public class Tree<T> { private TreeNode<T> rootNode = default(TreeNode<T>); public TreeNode<T> RootNode { get { return rootNode; } set { rootNode = value; } } }

Note the default () operator, which returns the default value of a type. It can be used to initialize an object to its default value. We can now set the root property as follows:
static void Main(string[] args) { // Create the generic tree that will work with Person objects Tree<Person> personHierarchy = new Tree<Person>(); // Create a tree node object, that will work with Person objects TreeNode<Person> grandFatherNode = new TreeNode<Person>(); // Set root property of tree to the grandFather tree node personHierarchy.RootNode = grandFatherNode; }

Each tree node we create, has to have a reference to a particular object of type T. Therefore, we will add a Tag property to the TreeNode class, this also is a generic property:
public class TreeNode<T> { private T tag = default(T);

Using generic– By Ludwig Stuyck

Page 19 of 51

Ctg Technical Articles
public T Tag { get { return tag; } set { tag = value; } } }

So the Tag property of a tree node points to an object of type T. Now, if we create such a tree node, it would be handy if we could immediately pass its assigned object of type T. So we’ll add a constructor to the TreeNode class with one parameter:
public class TreeNode<T> { private T tag = default(T); public T Tag { get { return tag; } set { tag = value; } } public TreeNode(T tag) { this.tag = tag; } }

This forces us to assign an object of type T to a tree node each time we create a tree node. So we need to modify our code a little bit to be able to pass a Person object when we create a tree node:
static void Main(string[] args) { // Create the generic tree that will work with Person objects Tree<Person> personHierarchy = new Tree<Person>(); // Create a person object Person grandFather = new Person("Louis", "Zaventem", 92); // Create a tree node that is assigned to the person object TreeNode<Person> grandFatherNode = new TreeNode<Person>(grandFather); // Set root property of tree to the grandFather tree node personHierarchy.RootNode = grandFatherNode; }

Using generic– By Ludwig Stuyck

Page 20 of 51

Ctg Technical Articles Right, this works… Now we will rewrite the Tree class a bit, so that it creates tree nodes for us. Therefore we will add a method CreateNode to the Tree class that will create and return a tree node for us. This is a generic method:
public class Tree<T> { private TreeNode<T> rootNode = default(TreeNode<T>); public TreeNode<T> RootNode { get { return rootNode; } set { rootNode = value; } } public TreeNode<T> CreateNode(T tag) { return new TreeNode<T>(tag); } }

So now, instead of creating the tree node ourselves, we will use the new method we have just created:
static void Main(string[] args) { // Create the generic tree that will work with Person objects Tree<Person> personHierarchy = new Tree<Person>(); // Create a person object Person grandFather = new Person("Louis", "Zaventem", 92); // Let the tree create and return a tree node (assigned to the // person object we just created, and assign this tree node to // the root node personHierarchy.RootNode = personHierarchy.CreateNode(grandFather); }

There’s something missing: our tree has a root node, but a root node should have child nodes. So add a property Nodes to the TreeNode class, and this should be a list of tree nodes:
public class TreeNode<T> { private T tag = default(T); public T Tag { get { return tag; } set { tag = value; } } private List<TreeNode<T>> nodes = new List<TreeNode<T>>(); public List<TreeNode<T>> Nodes

Using generic– By Ludwig Stuyck

Page 21 of 51

Ctg Technical Articles
{ get { return nodes; } set { nodes = value; } } public TreeNode(T tag) { this.tag = tag; } }

Now we can add some more nodes to our tree:
static void Main(string[] args) { // Create the generic tree that will work with Person objects Tree<Person> personHierarchy = new Tree<Person>(); // Create person objects Person grandFather = new Person("Louis", "Zaventem", 92); Person son1 = new Person("Michael", "Ukkel", 65); Person son2 = new Person("Jan", "Leuven", 62); Person daughter = new Person("Jennifer", "Zaventem", 57); Person grandson = new Person("Kobe", "Steenokkerzeel", 26); Person grandDaughter = new Person("Eowyn", "Steenokkerzeel", 23); // Let the tree create and return a tree node (assigned to the // person object we just created, and assign this tree node to // the root node personHierarchy.RootNode = personHierarchy.CreateNode(grandFather); // Create child nodes and add them to the tree // son1 is child of root node TreeNode<Person> treeNodeSon1 = personHierarchy.CreateNode(son1); personHierarchy.RootNode.Nodes.Add(treeNodeSon1); // son2 is child of root node TreeNode<Person> treeNodeSon2 = personHierarchy.CreateNode(son2); personHierarchy.RootNode.Nodes.Add(treeNodeSon2); // daughter is child of root node TreeNode<Person> treeNodedaughter = personHierarchy.CreateNode(daughter); personHierarchy.RootNode.Nodes.Add(treeNodedaughter); // grandson is child of daughter TreeNode<Person> treeNodegrandson = personHierarchy.CreateNode(grandson); treeNodedaughter.Nodes.Add(treeNodegrandson); // granddaughter is child of daughter TreeNode<Person> treeNodegrandDaughter = personHierarchy.CreateNode(grandDaughter);

Using generic– By Ludwig Stuyck

Page 22 of 51

Ctg Technical Articles
treeNodedaughter.Nodes.Add(treeNodegrandDaughter); }

We have now created a tree with a root node, this root node has three child nodes, and one of the child nodes has two child nodes. Each node is assigned to an object of type Person. So what we have created is this hierarchy: Louis +-- Michael +-- Jan +-- Jennifer +-- Kobe +-- Eowyn Note that we can easily reuse the Tree to work with other types. For example, we could create a tree that works with strings, Customer or any other type. And that’s the whole idea of using generics: write once, use many.

Derivation constraints
We want to implement sorting capability in our tree. Sorting simply means that we need to sort each child node collection in the tree. But before we do this, first write some code to display the tree hierarchy to the console:
static void Main(string[] args) { // Create the generic tree that will work with Person objects Tree<Person> personHierarchy = new Tree<Person>(); // Create person objects Person grandFather = new Person("Louis", "Zaventem", 92); Person son1 = new Person("Michael", "Ukkel", 65); Person son2 = new Person("Jan", "Leuven", 62); Person daughter = new Person("Jennifer", "Zaventem", 57); Person grandson = new Person("Kobe", "Steenokkerzeel", 26); Person grandDaughter = new Person("Eowyn", "Steenokkerzeel", 23); // Let the tree create and return a tree node (assigned to the // person object we just created, and assign this tree node to // the root node personHierarchy.RootNode = personHierarchy.CreateNode(grandFather); // Create child nodes and add them to the tree // son1 is child of root node TreeNode<Person> treeNodeSon1 = personHierarchy.CreateNode(son1); personHierarchy.RootNode.Nodes.Add(treeNodeSon1);

Using generic– By Ludwig Stuyck

Page 23 of 51

Ctg Technical Articles

// son2 is child of root node TreeNode<Person> treeNodeSon2 = personHierarchy.CreateNode(son2); personHierarchy.RootNode.Nodes.Add(treeNodeSon2); // daughter is child of root node TreeNode<Person> treeNodedaughter = personHierarchy.CreateNode(daughter); personHierarchy.RootNode.Nodes.Add(treeNodedaughter); // grandson is child of daughter TreeNode<Person> treeNodegrandson = personHierarchy.CreateNode(grandson); treeNodedaughter.Nodes.Add(treeNodegrandson); // granddaughter is child of daughter TreeNode<Person> treeNodegrandDaughter = personHierarchy.CreateNode(grandDaughter); treeNodedaughter.Nodes.Add(treeNodegrandDaughter); string spaces = string.Empty; PrintNode(personHierarchy.RootNode, spaces); } public static void PrintNode(TreeNode<Person> node, string spaces) { Console.WriteLine(spaces + node.Tag.Name); spaces += " "; foreach (TreeNode<Person> childNode in node.Nodes) { PrintNode(childNode, spaces); } }

The result looks like:

Now we’re ready to implement sorting. It would be nice if we could just say to the Tree object that it should sort its nodes. So we’ll add a Sort method to the Tree class. This method will then call the Sort method of the root node, which will cause a recursive sorting mechanism: the root node will sort its child nodes

Using generic– By Ludwig Stuyck

Page 24 of 51

Ctg Technical Articles collection and for each child node, it will call the Sort method again (recursive method). However, there’s a problem. A tree node does not now how to sort its collection of tree nodes. Therefore we need to make sure that the TreeNode class implements the IComparable interface, because when we do so, it forces us to implement the CompareTo method in the TreeNode class. In this method, the comparison method of the objects of type T will be called, which means that each Tag property has to be compared. In our case, it means that each Person has to be compared. The Person class knows how to compare itself, because we have already implemented the IComparable interface previously. The first step is to make sure that tree nodes know how they have to compare to each other, by implementing the IComparable<TreeNode<T>> generic interface:
public class TreeNode<T> : IComparable<TreeNode<T>> { private T tag = default(T); public T Tag { get { return tag; } set { tag = value; } } private List<TreeNode<T>> nodes = new List<TreeNode<T>>(); public List<TreeNode<T>> Nodes { get { return nodes; } set { nodes = value; } } public TreeNode(T tag) { this.tag = tag; } public int CompareTo(TreeNode<T> treeNode) { return this.tag.CompareTo(treeNode.Tag); } }

As we have used the generic interface IComparable<TreeNode<T>>, we don’t need any casting in the CompareTo method. Next, as we’ve said, the tree should have a Sort method, that will call the root code Sort method:

Using generic– By Ludwig Stuyck

Page 25 of 51

Ctg Technical Articles

public class Tree<T> { private TreeNode<T> rootNode = default(TreeNode<T>); public TreeNode<T> RootNode { get { return rootNode; } set { rootNode = value; } } public TreeNode<T> CreateNode(T tag) { return new TreeNode<T>(tag); } public void Sort() { rootNode.Sort(); } }

Evidently, the TreeNode class should also have a Sort method, which will first sort its child nodes collection, and then call itself again for each child node:
public class TreeNode<T> : IComparable<TreeNode<T>> { private T tag = default(T); public T Tag { get { return tag; } set { tag = value; } } private List<TreeNode<T>> nodes = new List<TreeNode<T>>(); public List<TreeNode<T>> Nodes { get { return nodes; } set { nodes = value; } } public TreeNode(T tag) { this.tag = tag; } public void Sort() { nodes.Sort(); foreach (TreeNode<T> node in nodes) { node.Sort(); } }

Using generic– By Ludwig Stuyck

Page 26 of 51

Ctg Technical Articles

public int CompareTo(TreeNode<T> treeNode) { return this.tag.CompareTo(treeNode.Tag); } }

This won’t compile yet, because we take for granted that the type T implements the IComparable interface. Imagine we would use the tree with an object type that cannot compare itself (it does not implement IComparable…) then we would have major problems, because sorting would not work. So our tree should enforce user to use a type T that implements the IComparable interface: we have to add a constraint to the Tree class:
public class Tree<T> where T : IComparable<T> { … }

By doing this, we say that the type T must implement the IComparable<T> interface; and therefore are sure that this type T knows how to compare itself; and sorting can work correctly. Still one more thing to do: the type T defined in the Tree class is also used in the TreeNode class. So we also need to make sure that the type T in the TreeNode class implements the IComparable<T> interface:
public class TreeNode<T> : IComparable<TreeNode<T>> where T : IComparable<T> { … }

Let’s test our code:
static void Main(string[] args) { // Create the generic tree that will work with Person objects Tree<Person> personHierarchy = new Tree<Person>(); // Create person objects Person grandFather = new Person("Louis", "Zaventem", 92); Person son1 = new Person("Michael", "Ukkel", 65); Person son2 = new Person("Jan", "Leuven", 62); Person daughter = new Person("Jennifer", "Zaventem", 57); Person grandson = new Person("Kobe", "Steenokkerzeel", 26); Person grandDaughter = new Person("Eowyn", "Steenokkerzeel", 23);

Using generic– By Ludwig Stuyck

Page 27 of 51

Ctg Technical Articles
// Let the tree create and return a tree node (assigned to the // person object we just created, and assign this tree node to // the root node personHierarchy.RootNode = personHierarchy.CreateNode(grandFather); // Create child nodes and add them to the tree // son1 is child of root node TreeNode<Person> treeNodeSon1 = personHierarchy.CreateNode(son1); personHierarchy.RootNode.Nodes.Add(treeNodeSon1); // son2 is child of root node TreeNode<Person> treeNodeSon2 = personHierarchy.CreateNode(son2); personHierarchy.RootNode.Nodes.Add(treeNodeSon2); // daughter is child of root node TreeNode<Person> treeNodedaughter = personHierarchy.CreateNode(daughter); personHierarchy.RootNode.Nodes.Add(treeNodedaughter); // grandson is child of daughter TreeNode<Person> treeNodegrandson = personHierarchy.CreateNode(grandson); treeNodedaughter.Nodes.Add(treeNodegrandson); // granddaughter is child of daughter TreeNode<Person> treeNodegrandDaughter = personHierarchy.CreateNode(grandDaughter); treeNodedaughter.Nodes.Add(treeNodegrandDaughter); // Write person hierarchy to console string spaces = string.Empty; PrintNode(personHierarchy.RootNode, spaces); Console.WriteLine(); // Sort hierarchy personHierarchy.Sort(); // Write sorted person hierarchy to console spaces = string.Empty; PrintNode(personHierarchy.RootNode, spaces); }

And the output is:

Using generic– By Ludwig Stuyck

Page 28 of 51

Ctg Technical Articles

To be complete, here’s the entire code:
using using using using System; System.Collections.Generic; System.Text; System.Collections;

namespace Generics { class Program { static void Main(string[] args) { // Create the generic tree that will work // with Person objects Tree<Person> personHierarchy = new Tree<Person>(); // Create person objects Person grandFather = new Person("Louis", "Zaventem", 92); Person son1 = new Person("Michael", "Ukkel", 65); Person son2 = new Person("Jan", "Leuven", 62); Person daughter = new Person("Jennifer", "Zaventem", 57); Person grandson = new Person("Kobe", "Steenokkerzeel", 26); Person grandDaughter = new Person("Eowyn", "Steenokkerzeel", 23); // Let the tree create and return a tree node // (assigned to the person object we just created, // and assign this tree node to the root node personHierarchy.RootNode = personHierarchy.CreateNode(grandFather); // Create child nodes and add them to the tree // son1 is child of root node TreeNode<Person> treeNodeSon1 =

Using generic– By Ludwig Stuyck

Page 29 of 51

Ctg Technical Articles
personHierarchy.CreateNode(son1); personHierarchy.RootNode.Nodes.Add(treeNodeSon1); // son2 is child of root node TreeNode<Person> treeNodeSon2 = personHierarchy.CreateNode(son2); personHierarchy.RootNode.Nodes.Add(treeNodeSon2); // daughter is child of root node TreeNode<Person> treeNodedaughter = personHierarchy.CreateNode(daughter); personHierarchy.RootNode.Nodes.Add(treeNodedaughter); // grandson is child of daughter TreeNode<Person> treeNodegrandson = personHierarchy.CreateNode(grandson); treeNodedaughter.Nodes.Add(treeNodegrandson); // granddaughter is child of daughter TreeNode<Person> treeNodegrandDaughter = personHierarchy.CreateNode(grandDaughter); treeNodedaughter.Nodes.Add(treeNodegrandDaughter); // Write person hierarchy to console string spaces = string.Empty; PrintNode(personHierarchy.RootNode, spaces); Console.WriteLine(); // Sort hierarchy personHierarchy.Sort(); // Write sorted person hierarchy to console spaces = string.Empty; PrintNode(personHierarchy.RootNode, spaces); }

public static void PrintNode( TreeNode<Person> node, string spaces) { Console.WriteLine(spaces + node.Tag.Name); spaces += " "; foreach (TreeNode<Person> childNode in node.Nodes) { PrintNode(childNode, spaces); } } public class Tree<T> where T : IComparable<T> { private TreeNode<T> rootNode = default(TreeNode<T>); public TreeNode<T> RootNode { get { return rootNode; }

Using generic– By Ludwig Stuyck

Page 30 of 51

Ctg Technical Articles
set { rootNode = value; } } public TreeNode<T> CreateNode(T tag) { return new TreeNode<T>(tag); } public void Sort() { rootNode.Sort(); } } public class TreeNode<T> : IComparable<TreeNode<T>> where T : IComparable<T> { private T tag = default(T); public T Tag { get { return tag; } set { tag = value; } } private List<TreeNode<T>> nodes = new List<TreeNode<T>>(); public List<TreeNode<T>> Nodes { get { return nodes; } set { nodes = value; } } public TreeNode(T tag) { this.tag = tag; } public void Sort() { nodes.Sort(); foreach (TreeNode<T> node in nodes) { node.Sort(); } } public int CompareTo(TreeNode<T> treeNode) { return this.tag.CompareTo(treeNode.Tag); } } public class Person : IComparable<Person> { private string name = null; public string Name

Using generic– By Ludwig Stuyck

Page 31 of 51

Ctg Technical Articles
{ get { return name; } set { name = value; } } private string location = null; public string Location { get { return location; } set { location = value; } } private int age = 0; public int Age { get { return age; } set { age = value; } } public Person(string name, string location, int age) { this.name = name; this.location = location; this.age = age; } public int CompareTo(Person person) { return this.name.CompareTo(person.Name); } } public class PersonCollection : CollectionBase { public Person this[int index] { get { return (Person)List[index]; } set { List[index] = value; } } public int Add(Person person) { return List.Add(person); } public void Insert(int index, Person person) { List.Insert(index, person); }

Using generic– By Ludwig Stuyck

Page 32 of 51

Ctg Technical Articles

public void Remove(Person person) { List.Remove(person); } public bool Contains(Person person) { return List.Contains(person); } // Add other type-safe methods here } } }

Constructor constraints
Suppose you want to instantiate a new generic object inside a generic class. You have to be sure that the type that is passed actually has a public default constructor. You can enforce this by using the new()constraint. Let’s have a look at the following generic class:
public class GenericCollection<T> { T instance = new T(); }

When you try to compile this, you’ll see that there’s a compiler error ‘Cannot create an instance of the variable type 'T' because it does not have the new () constraint’. So the compiler is not sure that type T has a public default constructor, because we have not enforced it. We can do so as follows:
public class GenericCollection<T> where T : new() { T instance = new T(); }

Reference/Value Type Constraints
It’s possible to specify that a generic type has to be a reference type (a class) by using the class keyword, or a value type (such as an int, bool, enum, struct, …) by using the struct keyword. Example:
public class GenericCollection<T> where T : class

Using generic– By Ludwig Stuyck

Page 33 of 51

Ctg Technical Articles
{ }

Other generic collections
We’ve used the generic List<> collection in our previous examples, but there are other generic collection types that can be used out of the box. SortedList<> Represents a sorted list. Queue<> Represents a first-in, first-out collection. Stack<> Represents a last-in, first-out collection. Dictionary<> Represents a collection that associates a key to a value. SortedDictionary<> Represents a sorted collection that associates a key to a value. LinkedList<> Represents a double linked list.

Generics and databinding
Databinding is an important feature in windows and web programming. In this part I’ll demonstrate how you can implement databinding of a generic collection with a Windows Form DataGridView control, but of course this technique will work with other controls too. In .NET 2.0 databinding has become rather easy to do, as you will see.

Create the business object
To start, create a new Windows Forms project and call it Generics5. Add the Person class again:
public class Person { private string name = string.Empty; public string Name

Using generic– By Ludwig Stuyck

Page 34 of 51

Ctg Technical Articles
{ get { return name; } set { name = value; } } private string location = string.Empty; public string Location { get { return location; } set { location = value; } } private int age = 0; public int Age { get { return age; } set { age = value; } } public Person(string name, string location, int age) { this.name = name; this.location = location; this.age = age; } }

Now don’t forget to build the project at this point – otherwise the Person class will not show up in the following step.

Register class as a data source
The next thing we need to do is to register the Person class so that our project recognizes it as a data source. Select Data | Add New Data Source… in the Visual Studio 200 menu:

Then select Object, because we are going to add our custom type as a data source.

Using generic– By Ludwig Stuyck

Page 35 of 51

Ctg Technical Articles

Click the Next button, and the following window will appear:

Using generic– By Ludwig Stuyck

Page 36 of 51

Ctg Technical Articles

Select the Person class, and click the Finish Button. As you will see, Visual Studio has added a DataSources folder to the project with a Person.datasource configuration file, which is used to store generic object data source configuration information:

Create a DataGridView and its columns
To display the data, drop a DataGridView control called dataGridView on the form. In the Load event of the form we’ll add code to create a collection and bind it to the grid. First, create some Person objects:
// Create some Person person1 Person person2 Person person3 persons = new Person("Ludwig Stuyck", "Zaventem", 33); = new Person("Leen Rans", "Zaventem", 25); = new Person("Paulien Rans", "Rotselaar", 2);

Then, create a collection of these persons by using a BindingList generic collection:
// Create a collection of persons BindingList<Person> persons = new BindingList<Person>(); persons.Add(person1); persons.Add(person2); persons.Add(person3);

Now create a BindingSource object and set its data source to the collection we just created:
// Create a binding source and set its datasource to the collection BindingSource bindingSource = new BindingSource(); bindingSource.AllowNew = true; bindingSource.DataSource = persons;

Next, run the application: Using generic– By Ludwig Stuyck Page 37 of 51

Ctg Technical Articles

With this little piece of code we already have setup databinding! You can modify and delete a field in the grid and it will be reflected in the data source (and vice versa). However, if you now try to add a new row, you will get an error ‘Constructor on type not found’. This is because we have no default constructor in our Person class, so we’ll add it:
public class Person { public Person() { } … }

And now you can add rows too.

Adding a BindingNavigator
Drop a BindingNavigator control to the form and call it bindingNavigator, and set the DockState of the DataGridView to Fill:

Using generic– By Ludwig Stuyck

Page 38 of 51

Ctg Technical Articles

Then, set the datasource of the BindingNavigator to the BindingSource object we created:
// Set binding source of navigator bindingNavigator.BindingSource = bindingSource;

Now run the application again. You will have full navigation support:

Adding sorting functionality
BindingList gives us out of the box add, delete and modify functionality. However, to allow sorting in the grid we need to extend the BindingList class and implement sorting ourselves. Add a new class, call it CustomBindingList and make it inherit from the generic BindingList<T>:

Using generic– By Ludwig Stuyck

Page 39 of 51

Ctg Technical Articles
using using using using System; System.Collections.Generic; System.Text; System.ComponentModel;

namespace Generics5 { public lass CustomBindingList<T> : BindingList<T> { } }

To indicate that the BindingList supports sorting, we override the SupportsSortingCore method:
public class CustomBindingList<T> : BindingList<T> { protected override bool SupportsSortingCore { get { return true; } } }

Of course, now we still have to implement the actual sorting mechanism. To do that, we need to override the ApplySortCore method. In this method we have to sort the internal collection (which is of type List) using the specified property and direction. Sorting a List comes down to calling the Sort method of the List, which takes an IComparer object as a parameter. So what we will have to do is to create our own generic class that implements the IComparer interface and allows us to sort any property – well, we actually don’t have to do it ourselves anymore because such generic property comparer has already been written by Rockford Lhotka from Microsoft (http://www.lhotka.net), so add a class called PropertyComparer and implement it as follows:
public class PropertyComparer<T> : System.Collections.Generic.IComparer<T> { // PropertyComparer builds on a comparison algorithm based built // by Rockford Lhotka and turns it into a generic property // comparer for any type. private PropertyDescriptor _property; private ListSortDirection _direction; public PropertyComparer(PropertyDescriptor property, ListSortDirection direction) { _property = property; _direction = direction;

Using generic– By Ludwig Stuyck

Page 40 of 51

Ctg Technical Articles
} #region IComparer<T> public int { // Get object object Compare(T xWord, T yWord) property values xValue = GetPropertyValue(xWord, _property.Name); yValue = GetPropertyValue(yWord, _property.Name);

// Determine sort order if (_direction == ListSortDirection.Ascending) { return CompareAscending(xValue, yValue); } else { return CompareDescending(xValue, yValue); } } public bool Equals(T xWord, T yWord) { return xWord.Equals(yWord); } public int GetHashCode(T obj) { return obj.GetHashCode(); } #endregion // Compare two property values of any type private int CompareAscending(object xValue, object yValue) { int result; // If values implement IComparer if (xValue is IComparable) { result = ((IComparable)xValue).CompareTo(yValue); } // If values don't implement IComparer but are equivalent else if (xValue.Equals(yValue)) { result = 0; } // Values don't implement IComparer and are not equivalent, // so compare as string values else result = Value.ToString().CompareTo(yValue.ToString()); // Return result return result; }

Using generic– By Ludwig Stuyck

Page 41 of 51

Ctg Technical Articles

private int CompareDescending(object xValue, object yValue) { // Return result adjusted for ascending or descending sort // order ie multiplied by 1 for ascending or -1 for // descending return CompareAscending(xValue, yValue) * -1; } private object GetPropertyValue(T value, string property) { // Get property PropertyInfo propertyInfo = value.GetType().GetProperty(property); // Return value return propertyInfo.GetValue(value, null); } }

Now we can use this PropertyComparer in our ApplySortCore method:
public class CustomBindingList<T> : BindingList<T> { private bool isSorted = false; private PropertyDescriptor sortProperty = null; private ListSortDirection sortDirection = ListSortDirection.Ascending; protected override void ApplySortCore( PropertyDescriptor property, ListSortDirection direction) { // Get list to sort List<T> items = this.Items as List<T>; if (items != null) { PropertyComparer<T> propertyComparer = new PropertyComparer<T>(property, direction); items.Sort(propertyComparer); isSorted = true; } else { isSorted = false; } sortProperty = property; sortDirection = direction; } protected virtual bool SupportsSortingCore { get { return true; }

Using generic– By Ludwig Stuyck

Page 42 of 51

Ctg Technical Articles
} }

After a sort we need to let the bound controls know that sort order has changed, which is a list-wide change. We do this by calling the OnListChanged method after the sorting algorithm:
protected override void ApplySortCore(PropertyDescriptor property, ListSortDirection direction) { // Get list to sort List<T> items = this.Items as List<T>; if (items != null) { PropertyComparer<T> propertyComparer = new PropertyComparer<T>(property, direction); items.Sort(propertyComparer); isSorted = true; } else { isSorted = false; } sortProperty = property; sortDirection = direction; this.OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1)); }

Next thing to do is to override the IsSortedCore property, to make sure that the bound controls know that sorting is done:
protected override bool IsSortedCore { get { return isSorted; } }

And we do the same thing for SortDirectionCore and SortPropertyCore:
protected override ListSortDirection SortDirectionCore { get { return sortDirection; } } protected override PropertyDescriptor SortPropertyCore { get { return sortProperty; } }

Using generic– By Ludwig Stuyck

Page 43 of 51

Ctg Technical Articles

When sorting is removed, we also need to set the internal state to reflect this by overriding the RemoveSortCore method:
protected override void RemoveSortCore() { isSorted = false; }

We’re almost there. Of course, we now need to use our CustomBindingList as a data source for our grid:
// Create some Person person1 Person person2 Person person3 persons = new Person("Ludwig Stuyck", "Zaventem", 33); = new Person("Leen Rans", "Zaventem", 25); = new Person("Paulien Rans", "Rotselaar", 2);

// Create a collection of persons CustomBindingList<Person> persons = new CustomBindingList<Person>(); persons.Add(person1); persons.Add(person2); persons.Add(person3); // Create a binding source and set its datasource to the collection BindingSource bindingSource = new BindingSource(); bindingSource.AllowNew = true; bindingSource.DataSource = persons; dataGridView.DataSource = bindingSource; // Set binding source of navigator bindingNavigator.BindingSource = bindingSource;

And if you now start the application, and click on a column, it will be sorted:

Using generic– By Ludwig Stuyck

Page 44 of 51

Ctg Technical Articles

Adding searching functionality
As with sorting, we also have to implement our own searching mechanism into our custom binding list. First, override the SupportsSearchingCore method, to indicate that the BindingList supports searching:
protected override bool SupportsSearchingCore { get { return true; } }

Next we have to override FindCore and implement our own searching mechanism: we have to look in the internal collection for a specific property holding a specific value. To do this, we’ll use the predicate-technique discussed previously in this article:
protected override int FindCore(PropertyDescriptor property, object key) { if (property == null) { // No property specified return -1; } // Get list to search List<T> items = this.Items as List<T>; PropertyValueFilter<T> propertyValueFilter = new PropertyValueFilter<T>(property, (string)key); Predicate<T> filterByValue = new Predicate<T>(propertyValueFilter.FilterByValue); return items.FindIndex(filterByValue); }

As you see, it uses a PropertyValueFilter class that acts as a predicate, so add a class called PropertyValueFilter and implement it as follows:
public class PropertyValueFilter<T> { private string value = string.Empty; private PropertyDescriptor property = null; public PropertyValueFilter( PropertyDescriptor property, string value) { this.value = value; this.property = property; }

Using generic– By Ludwig Stuyck

Page 45 of 51

Ctg Technical Articles

public bool FilterByValue(T t) { string v = (string)property.GetValue(t); return value.Equals(v); } }

In fact, we now have done all that is necessary to support searching, so let’s search! Add a TextBox to the bindingNavigator control and call it toolStripSearchNameTextBox. Also add a Button and call it toolStripSearchButton. Double click on the button to start implementing it’s Click event handler:
private void toolStripSearchButton_Click(object sender, EventArgs e) { int index = bindingSource.Find("Name", toolStripSearchNameTextBox.Text); if (index > -1) { foreach (DataGridViewRow row in dataGridView.Rows) { row.Selected = false; } dataGridView.Rows[index].Selected = true; } }

Note: move the definition of the bindingSource to a class level definition to make it accessible in the event handler. Now start the application, type in a name in the text box, click the button and if the name is in the grid, its row will be selected:

Using generic– By Ludwig Stuyck

Page 46 of 51

Ctg Technical Articles

Serializing and deserializing a generic collection
Sometimes it would be handy if we have the possibility to persist a collection to a file in order to retrieve it later. This is quite simple to achieve, as a matter a fact we will implement it in our CustomBindingList so that it works for every type. Add a Save and Load method in the CustomBindingList class:
public void Save(string filename) { BinaryFormatter formatter = new BinaryFormatter(); using (FileStream fileStream = new FileStream(filename, FileMode.Create)) { formatter.Serialize(fileStream, (List<T>)this.Items); } } public void Load(string filename) { this.ClearItems(); if (File.Exists(filename)) { BinaryFormatter formatter = new BinaryFormatter();

Using generic– By Ludwig Stuyck

Page 47 of 51

Ctg Technical Articles
using (FileStream fileStream = new FileStream(filename, FileMode.Open)) { ((List<T>)this.Items).AddRange( (IEnumerable<T>)formatter.Deserialize(fileStream)); } } this.OnListChanged(new ListChangedEventArgs( ListChangedType.Reset, -1)); }

Don’t forget to add the following two using statements on top:
using System.Runtime.Serialization.Formatters.Binary; using System.IO;

One more thing: in order to be able to serialize a collection of objects, the object itself should be marked as serializable. So modify the Person class and decorate it with the Serializable attribute:
[Serializable] public class Person { public Person() { } … }

Generics and LINQ
LINQ (Language Integrated Query) brings the power of queries into C#. For the example I have used the CTP of may 2006. Create a new LINQ console application and call it Generics6:

Using generic– By Ludwig Stuyck

Page 48 of 51

Ctg Technical Articles

Add a new class called Person, as we did in previous examples. Now we will write code to create a collection of Person objects:
using using using using using using System; System.Collections.Generic; System.Text; System.Data.DLinq; System.Xml.XLinq; System.Query;

namespace Generics6 { class Program { static void Main(string[] args) { // Create some persons Person person1 = new Person("Ludwig Stuyck", "Zaventem", 33); Person person2 = new Person("Leen Rans", "Zaventem", 25); Person person3 = new Person("Paulien Rans", "Rotselaar", 2); // Create a collection of persons

Using generic– By Ludwig Stuyck

Page 49 of 51

Ctg Technical Articles
List<Person> persons = new List<Person>(); persons.Add(person1); persons.Add(person2); persons.Add(person3); } } }

Now let’s use LINQ to query this collection and find out what persons live in Zaventem:
// Find all persons who live in Zaventem var q = from c in persons where c.Location == "Zaventem" select c; foreach(var val in q) { Console.WriteLine("{0},{1}, {2}", val.Name, val.Location, val.Age); }

The result is:

About this article
Copyright © 2006 CTG. ALL RIGHTS RESERVED. Duplication is prohibited without written permission. Thanks to Pascal Desmet, Jort Marievoet, Bart Kuppens, Olivier Van Hege, Dick Bevernage, Annelies Aerts and James Curran.

About Ctg
CTG was founded in 1966 in the USA and expanded to Europe in 1976. Our IT professionals deliver our services through a network of ISO-certified sites in North America and Europe. CTG Europe provides services in Belgium, Luxembourg, France, and the United Kingdom. Using generic– By Ludwig Stuyck Page 50 of 51

Ctg Technical Articles

To succeed in today's business world, companies need to use cutting-edge technology. CTG empowers its clients to rapidly leverage today's innovative IT and Web technology across their enterprises. Website: http://www.ctg.com

Using generic– By Ludwig Stuyck

Page 51 of 51