Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Generic ListHelper Class - .NET 4.5

0.00/5 (No votes)
15 Jul 2015 1  
This tip will show how to sort a list of a particular class type from a SqlDataReader object by dynamically creating a lambda expression to carry out the process of sorting the list.

Introduction

This is a continuation of the update to my previous article, Generically Populate List of Objects from SqlDataReader. The information posted in this tip is intended primarily to add the ability to sort a list of objects based on a given property within the class.

Background

In the 'parent' article to this, I created a generic routine that will populate a list of objects from a SqlDataReader object using reflection to dynamically create a lambda expression to create instances of a class and populate them from the SqlDataReader. This worked well, but in using that list as a data source for my various data views, I quickly found there was something lacking -- the ability to quickly sort the list based on a property within the class.

We often allow the sorting of the list by clicking on the column header within whatever control we are using to display data. So, the requirements for the sorting became:

  • Use the models within C# to allow generic ('<T>') functionality
  • Sorting should allow for sorting by a single property of the class
  • Sorting should allow for both ascending or descending order

For the purposes of this article, I'm using the Employee table within the Northwind SQL Server sample database. Apart from creating the database, all of the code is available in the download package.

Using the ListHelper Class to Sort

There are basically three steps necessary:

  1. Create a data model that represents an individual item in the list
  2. Populate the list using the CreateList() function
  3. Sort the list using the SortList() function

Here is my data model for the Employee. As you can see, there is nothing special about the data model. It does allow for various data types to be tested, as well as nullable data types.

[Serializable]
public class Employee
{
	public int EmployeeID { get; set; }
	public string LastName { get; set; }
	public string FirstName { get; set; }
	public string Title { get; set; }
	public DateTime? BirthDate { get; set; }
	public DateTime? HireDate { get; set; }
	public string City { get; set; }
}

Executing the query and populating a list based on this data model is really quite simple. Once the list is populated, you can sort it quite easily.

var query = "select * from Employees order by LastName, FirstName";
var cmd = new SqlCommand(query, conn);
using (var reader = cmd.ExecuteReader())
{
	var listHelper = new GenericPopulator.ListHelper<Employee>();
	var employeeList = listHelper.CreateList(reader);
	employeeList = listHelper.SortList(employeeList, "LastName", true);
	
	rptEmployees.DataSource = employeeList;
	rptEmployees.DataBind();

	reader.Close();
}

Explanation of the SortList() Function

In order to dynamically sort a list based on a data model, you must use Reflection and dynamically generate a lambda expression. From our example above, attempting to sort based on the LastName property of the Employee class would require the following LINQ statement:

	employeeList = employeeList.AsQueryable().OrderBy(e => e.LastName).ToList();

The SortList() function will dynamically generate the lambda expression to use. Once the dynamic lambda is generated, it will sort the list using simple LINQ functions. Unfortunately, the nature of LINQ means that you must call a separate function to sort in ascending versus descending order.

public List<T> SortList(List<T> listToSort, string propertyName, bool ascending)
{
	// verify that the propertyName is valid
	var propertyNames = typeof(T).GetProperties().ToList().Select(p => p.Name).ToList();
	if (!propertyNames.Contains(propertyName))
		throw new ArgumentOutOfRangeException("There is no property named: " + propertyName);

	// create an expression representing the 'item' in the list
	var paramExpression = Expression.Parameter(typeof(T), "item");
	
	// create an expression that represents the property 
	// of the class on which the sort is determined
	var propertyExpression = Expression.Convert
	(Expression.Property(paramExpression, propertyName), typeof(object));
	
	// create the actual lambda expression to perform the sort
	var lambdaExpression = Expression.Lambda<Func<T, 
		object>>(propertyExpression, paramExpression);

	if (ascending)
		return listToSort.AsQueryable().OrderBy(lambdaExpression).ToList();
	else
		return listToSort.AsQueryable().OrderByDescending(lambdaExpression).ToList();
}

Points of Interest

Eat My Own Dog Food

Please understand that, while there was some research and experimentation for this project, the result was useful. This method of generically populating and sorting lists is used within my company on a regular basis now.

Download Package

Inside the download package, you will find the complete, usable code for the functionality described here.

Custom Attributes

This version allows for custom attributes on the properties of the data model. These custom attributes are basically present to allow you to have different property names and column names (EmployeeID property populated from Employee_ID column).

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here