Click here to Skip to main content
Email Password   helpLost your password?

Introduction

If you work with .NET and commercial applications, you probably have many objects to represent your business entities, like Customers, Employees, Products and so on.

When retrieving data from a data store (like a database, for example), we usually ask for the data in a specific order, so that the underlying engine can do the work to order it for us, and then we populate our objects in the correct order.

There are cases however, that for some reason we may need to rearrange objects in memory, either because we can't afford to go back to the data store (web services can be very slow for example) or because its simpler than changing an existing library to do this.

Sorting items by property in .NET is relatively easy, but doing a "sql-like" sort involving multiple properties in different directions is not a trivial task.

As I always get people asking me how to do it, I dediced to write this article to give an insight about the sort methods available in .NET and introduce you to my classes where you can sort objects by properties using a sql-like statement, using a code like this:

EmployeeCollection employees = GetEmployeeCollection()
employees.Sort("IsActive DESC, Name")

Although people using the .NET Framework 3.5 should be able to do this easily using LINQ, I won't cover LINQ or lambda expressions. I will focus on how to implement this using .NET 2.0 only, which is still widely used. Some people may find it useful for some scenarios on 3.5 though.

In this article, we will work with the "Employee" class as described below:

Background

Comparers

Before going into details on the actual sorting, it is important to understand a basic part of most sorting algorithms: the element comparison. (Note: there are sorting algorithms that are not comparison based, but they are more complex and used in specific cases only. For most situations, comparison sorts will work fine.)

So, it doesn't matter what sort algorithm you choose to use, somewhere in your code you will always need to know if an element should go before or after another element in the list. That functionality is provided in .NET by the IComparer interface.

The IComparer interface is a contract that requires the implementation of the "Compare" method. This method accepts 2 objects and returns 0 if they are equal, a negative number if the first is lower than the second and a positive number if the first is higher than the second.

There is a default implementation of the System.Collections.IComparer interface, the Comparer.Default, that will work with almost any type you will want to compare (like strings, numbers, dates, etc).

In .NET 2.0, microsoft introduced the generic System.Collections.Generic.IComparer<T> and the System.Collections.Generic.Comparison<T> delegate. The IComparer<T> is exactly like the IComparer interface, but is strongly typed. The Comparison<T> delegate is like the IComparer<T>.Compare method, and is handy when you don't want or need to create an extra class. There is also a default implementation of the IComparer<T> implementation, the Comparer<T>.Default.

Array.Sort

The .NET framework provides a way to sort arrays using the Array.Sort method. This method uses the QuickSort algorithm to sort arrays of any type. You can easily sort an array of Employees by the "Name" property by creating a method to compare their names and then using this method as a delegate of type Comparison<T> like this:

private int CompareEmployeeNames(Customer a, Customer b)
{
    return String.Compare(a.Name, b.Name);
}

and use it like this:

Employee[] employees = GetEmployeeArray();
Array.Sort(employees, CompareEmployeeNames);

Since String.Compare already returns the right numeric values for string comparisons, we don't need to do anything else.

You can also use the List<T>.Sort in the same way to sort lists. It will internally use the Array.Sort method.

Sorting by multiple columns

Sort by multiple "columns" is very easy. Imagine you want to sort a collection of our Employee objects by active status (actives first), then by name and then by ID. The idea is to simply apply the order in the reverse order.

The steps to accomplish the sort above would be:

  1. Sort by ID in ascending order
  2. Sort by Name in ascending order
  3. Sort by IsActive in descending order.

So, you must think, if we just apply the sorts in this order using Array.Sort or List<T>.Sort, we are done. Well, not exactly.

The Problem: Array.Sort is Unstable

Array.Sort works fine if you need to sort only by one property or column, and if that is what you need, you should stop reading here. But if you need to order by more columns like you do on SQL (order by field1, field2, field3), you will have a surprise. The problem with Array.Sort is that it is unstable. At this point I need to say: DON'T PANIC! That doesn't mean your program will crash if you use it.

Stability is property of sorting algorithms. An unstable sort algorithm will change the order of the items in the list even if they are already ordered. Stable algorithms in contrast won't change the order of items if they are ordered.

See what happens when we apply Array.Sort to the IsActive column in a list that is already sorted by name:

Since all items have IsActive = True, they are already sorted, and you wouldn't expect the sort to do anything. But remember that Array.Sort uses an unstable algorithm, and unstable algorithms may change the order of sorted items if that makes them run faster.

Imagine we were doing the 3 steps discussed previously. The second sort would change the order of the first, and the third would change the second. That makes Array.Sort pretty useless to sort multi-column data.

The Solution

Implementing the Merge Sort

The first thing to solve here is the sort algorithm. As previously discussed, the Array.Sort uses QuickSort, which is unstable. Since there is no alternative in .NET, we must implement or our own stable sort algorithm.

I decided to implement the Merge Sort, which is stable and has a reasonable speed. You can implement your own sort or use an external library of your choice to do this. But for the sake of simplicity, this implementation is good enough.

Here is a sample of the MergeSort that I implemented:

public sealed class MergeSort<T>
{
    // the comparer to use (our PropertyComparer in this case)
    private IComparer<T> _comparer;

    // used to tell if the sort should be ascending or descending
    private bool _isAscending;

    // the list to sort
    private IList<T> _list;

    // a buffer of the same size of the list to work
    private T[] _buffer;

    // private constructor, used only inside this class by the static Sort method
    private MergeSort
	(IList<T> list, IComparer<T> comparer, ListSortDirection direction)
    {
        _list = list;
        _buffer = new T[list.Count];
        _comparer = comparer;
        _isAscending = (direction == ListSortDirection.Ascending);
    }

    // This is the method you actually call to do the sort
    public static void Sort(IList<T> list, IComparer<T> comparer, 
		ListSortDirection direction)
    {
        MergeSort<T> sort = new MergeSort<T>(list, comparer, direction);
        sort._MergeSort(0, list.Count - 1);
    }

    // This method is used internally to compare values.
    // it will check the order and return the inverse values
    // if you are sorting in descending order
    private int Compare(T x, T y)
    {
        if (_isAscending)
            return _comparer.Compare(x, y);
        else
            return _comparer.Compare(y, x);
    }

    // the recursive part to "divide and conquer"
    private void _MergeSort(int firstIndex, int lastIndex)
    {
        int lastRelativeIndex = lastIndex - firstIndex;

        if (lastRelativeIndex < 1)
            return;

        int middle = (lastRelativeIndex / 2) + firstIndex;
        int postMiddle = middle + 1;

        _MergeSort(firstIndex, middle);
        _MergeSort(postMiddle, lastIndex);

        Merge(firstIndex, middle, postMiddle, lastIndex);
    }

    // the actual sort
    private void Merge(int leftStart, int leftEnd, int rightStart, int rightEnd)
    {
        int bufferIndex = leftStart;
        int leftIndex = leftStart;
        int rightIndex = rightStart;

        // copy to the items we can to the buffer in the right order

        while (leftIndex <= leftEnd && rightIndex <= rightEnd)
        {
            if (Compare(_list[leftIndex], _list[rightIndex]) > 0)
                _buffer[bufferIndex++] = _list[rightIndex++];
            else
                _buffer[bufferIndex++] = _list[leftIndex++];
        }

        // copy the rest of the items to the buffer

        for (int i = leftIndex; i <= leftEnd; i++)
            _buffer[bufferIndex++] = _list[i];

        for (int i = rightIndex; i <= rightEnd; i++)
            _buffer[bufferIndex++] = _list[i];

        // copy the buffer back to the list

        for (int i = leftStart; i <= rightEnd; i++)
            _list[i] = _buffer[i];
    }
}

I won't cover in details how merge sort works, and you can check the details here if you want: http://en.wikipedia.org/wiki/Merge_sort.

Creating a PropertyComparer

Now, in order to sort by properties, we need a way to compare the objects by property name and know which one should go first or last. Instead of creating delegates for every case, I created the PropertyComparer, that given a type and a property name, can compare the values of those properties using reflection.

This class will find the property by name, extract the "get" method and call it to get the value.

This is a sample of how this works:

// gets the property
PropertyInfo pi = t.GetProperty
		(propertyName, BindingFlags.Public | BindingFlags.NonPublic |
                   BindingFlags.Instance | BindingFlags.IgnoreCase);

// gets the "get" acessor for the property
MethodInfo mi = pi.GetGetMethod();

// calls the method in the specific instance to get the value
object value = mi.Invoke(instance, null);

This will enable us to sort by comparing the property values. You can also use this Comparer with Array.Sort if you like.

Parsing the Sort expression

We already have the right sort algorithm and a way to compare the property values. Now, we can just create the comparers and call the MergeSort in the right direction.

PropertyComparer comparer = 
	new PropertyComparer(typeof(Employee), "Name");
SortHelper.MergeSort<employee>(employees, comparer, ListSortDirection.Ascending);

We could just create a bunch of comparers and call the MergeSort method multiple times. But instead, it is a better idea to create some code to parse a sort expression and do what we need. Remember, we want to use an expression like:

IsActive DESC, Name ASC, ID ASC

This is the last and easier part. This is the code for the sort parser:

public class CollectionSort<T>
{
    // This method is what you call to do the actual sort
    public static void Sort(IList<T> list, string sortExpression)
    {
        // builds the sort expressions into classes
        SortInfo[] sorts = BuildSorts(sortExpression);

        // loops in reverse direction and apply each sort
        for (int i = sorts.Length - 1; i >= 0; i--)
        {
            SortInfo si = sorts[i];
            MergeSort<T>.Sort(list, si.Comparer, si.Direction);
        }
    }

    // parses the sort expression and builds the list of property comparers 
    // and directions
    private static SortInfo[] BuildSorts(string sortExpression)
    {
        Type itemType = typeof(T);
        string[] sortArray = sortExpression.Split(',');
        int arrayLength = sortArray.Length;
        List<SortInfo> comparers = new List<SortInfo>(arrayLength);

        // loops through each of the sort expressions,
        // parse and add them to the list
        for (int i = 0; i < arrayLength; i++)
        {
            string sortExp = sortArray[i].Trim();

            ListSortDirection direction;
            string propertyName;
            int spacePos = sortExp.IndexOf(' ');

            // since there shouldn't be spaces on property names, spacePos >= 0
            // means that there should be an ASC or DESC in the expression
            if (spacePos >= 0)
            {
                propertyName = sortExp.Substring(0, spacePos);
                string sortOrder = sortExp.Substring(spacePos + 1);

                // checks the sort order
                if (String.Compare(sortOrder, "asc", 
                        StringComparison.OrdinalIgnoreCase) == 0)
                    direction = ListSortDirection.Ascending;
                else if (String.Compare(sortOrder, "desc", 
                         StringComparison.OrdinalIgnoreCase) == 0)
                    direction = ListSortDirection.Descending;
                else
                    throw new ArgumentException(
                        "Sort order '" + sortOrder + 
                        "' is invalid. 
                        Must be ASC or DESC.");
            }
            else
            {
                // if no space was found, there isn't a direction defined
                // so we default to ascending and the propertyName 
                // is the expression itself
                propertyName = sortExp;
                direction = ListSortDirection.Ascending;
            }

            // creates the comparer using the property name
            PropertyComparer<T> comparer = 
                 new PropertyComparer<T>(propertyName);
            
            // adds the new comparer and the sort direction
            comparers.Add(new SortInfo(comparer, direction));
        }

        // returns the array
        return comparers.ToArray();
    }

    // container class for the sort builder
    private class SortInfo
    {
        public SortInfo(PropertyComparer<T> comparer, 
             ListSortDirection direction)
        {
            this.Comparer = comparer;
            this.Direction = direction;
        }

        public PropertyComparer<T> Comparer;
        public ListSortDirection Direction;
    }
}

Using the code

Now we have a complete solution to sort collections by property names using a sql-like expression.

You can either use the CollectionSort in your code directly:

CollectionSort.Sort(myEmployeeCollection, "IsActive desc, Name");

or include the functionality directly into your custom collections:

using System.Collections.Generic.ObjectModel;

public class EmployeeCollection : Collection<Employee>
{
	public void Sort(string sortExpression)
	{
		ObjectSort.Sort(this, sortExpression);
	}
}

and use like I proposed in the introduction:

EmployeeCollection employees = GetEmployees();
employees.Sort("IsActive desc, Name");
You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
GeneralMy vote of 1
lucho_1981
10:46 16 Feb '09  
syntax seems incomplete, examples are not complete. Does not work under VS 2008
GeneralUsing DynamicComparer
DavyBrion
21:31 10 Sep '08  
There is a much easier way to do this (which is incredibly fast as well) by using Marc Brooks' DynamicComparer class. You can find more information about it here[^]
GeneralRe: Using DynamicComparer
radioman.lt
4:51 11 Sep '08  
can it sort 'deep' fields?

peace & serenity

GeneralRe: Using DynamicComparer
DavyBrion
5:24 11 Sep '08  
nope
Generaldeep sorting
radioman.lt
8:42 10 Sep '08  
how to sort that stuff?

   class Item
{
int? w;
public int? W
{
get
{
return w;
}
set
{
w = value;
}
}

public Item()
{
W = 5;
}
}

class Entity
{
int? x;
public int? X
{
get
{
return x;
}
set
{
x = value;
}
}

int? y;
public int? Y
{
get
{
return y;
}
set
{
y = value;
}
}

int? z;
public int? Z
{
get
{
return z;
}
set
{
z = value;
}
}

public Item Sub;

public Entity(int? x, int? y, int? z, int? sub)
{
X = x;
Y = y;
Z = z;

Sub = new Item();
Sub.W = sub;
}
}

List<Entity> el = new List<Entity>();
el.Add(new Entity(0, 0, 1, 1));
el.Add(new Entity(0, 0, 0, 2));
el.Add(new Entity(0, 0, 0, 3));
el.Add(new Entity(0, 0, 1, 1));

// this don't work
{
CollectionSort.Sort(el, "X asc, Y asc, Z asc, n.Sub.W asc");
}

// nlinq don't worktoo
{
NLinqQuery query = new NLinqQuery(@"from n in list orderby n.X, n.Y, n.Z, n.Sub.W select n");
LinqToMemory linq = new LinqToMemory(query);
linq.AddSource("list", el);
List<Entity> r = linq.List<Entity>();
}


peace & serenity
GeneralRe: deep sorting
Henrik Jonsson
9:07 10 Sep '08  
You should look at LINQ Dynamic Query Library[^]
or the Dynamic Reflection Library[^]. Both of these should be capable of doing "deep" sort.
GeneralRe: deep sorting
radioman.lt
10:50 10 Sep '08  
thanks, but i just implement direct custom comparer using your sorting code,
i sort 100000 in 1.8s on amd 2.7+,
with reflection { i sort 300 items ~0.2s and double time with nlinq }
and that is ~370 times faster Laugh Red faced


// container class for the sort builder
public class EntityComparer : IComparer
{
SortBy by;
ListSortDirection direction;

private EntityComparer()
{
//
}

public EntityComparer(SortBy by, ListSortDirection direction)
{
this.by = by;
this.direction = direction;
}

#region IComparer Members

public int Compare(Entity a, Entity b)
{
Entity x = this.direction == ListSortDirection.Ascending ? a : b;
Entity y = this.direction == ListSortDirection.Descending ? a : b;

switch(by)
{
case SortBy.X:
return x.X.Value.CompareTo(y.X.Value);
break;

case SortBy.Y:
return x.Y.Value.CompareTo(y.Y.Value);
break;

case SortBy.Z:
return x.Y.Value.CompareTo(y.Y.Value);
break;

case SortBy.SubW:
return x.Sub.W.Value.CompareTo(y.Sub.W.Value);
break;
}

return 0;
}

#endregion
}

///
/// Implementation of the merge sort algorithm.
///

public sealed class EntityMergeSort
{
private IComparer _comparer;
private IList _list;
private Entity[] _buffer;

///
/// Creates a new MergeSort class.
///

private EntityMergeSort(IList list, IComparer comparer)
{
_list = list;
_buffer = new Entity[list.Count];
_comparer = comparer;
}

///
/// Sorts an IList using the specified comparer and the sort direction.
///

public static void Sort(IList list, List order)
{
for(int i = order.Count - 1; i >= 0; i--)
{
EntityMergeSort sort = new EntityMergeSort(list, order[i]);
sort._MergeSort(0, list.Count - 1);
}
}

private int Compare(Entity x, Entity y)
{
return _comparer.Compare(x, y);
}

#region Algorithm Implementation

private void _MergeSort(int firstIndex, int lastIndex)
{
int lastRelativeIndex = lastIndex - firstIndex;

if(lastRelativeIndex < 1)
return;

int middle = (lastRelativeIndex / 2) + firstIndex;
int postMiddle = middle + 1;

_MergeSort(firstIndex, middle);
_MergeSort(postMiddle, lastIndex);

Merge(firstIndex, middle, postMiddle, lastIndex);
}

private void Merge(int leftStart, int leftEnd, int rightStart, int rightEnd)
{
int bufferIndex = leftStart;
int leftIndex = leftStart;
int rightIndex = rightStart;

// copy to the buffer the sortable items
while(leftIndex <= leftEnd && rightIndex <= rightEnd)
{
if(Compare(_list[leftIndex], _list[rightIndex]) > 0)
_buffer[bufferIndex++] = _list[rightIndex++];
else
_buffer[bufferIndex++] = _list[leftIndex++];
}

// copy the rest of the items to the buffer

for(int i = leftIndex; i <= leftEnd; i++)
_buffer[bufferIndex++] = _list[i];

for(int i = rightIndex; i <= rightEnd; i++)
_buffer[bufferIndex++] = _list[i];

// copy the buffer back to the list

for(int i = leftStart; i <= rightEnd; i++)
_list[i] = _buffer[i];
}

#endregion
}

List el = new List();
{
{
el.Add(new Entity(3, 0, 0, 4));
el.Add(new Entity(2, 3, 4, 3));
el.Add(new Entity(2, 5, 4, 2));
el.Add(new Entity(1, 0, 0, 1));

for(int i = 0; i < 100000; i++)
{
el.Add(new Entity(4, 4, 4, 4));
}
}

{
List order = new List();
{
order.Add(new EntityComparer(SortBy.X, ListSortDirection.Ascending));
order.Add(new EntityComparer(SortBy.Y, ListSortDirection.Ascending));
order.Add(new EntityComparer(SortBy.Z, ListSortDirection.Ascending));
order.Add(new EntityComparer(SortBy.SubW, ListSortDirection.Ascending));
EntityMergeSort.Sort(el, order);
}
}


peace & serenity

GeneralRe: deep sorting
Natan Vivo
14:34 10 Sep '08  
Most people worry about using the new stuff, and forget about speed.
Good thing you did some tests.

Now, just a tip. It is a nice idea to separate the sort from the logic you use to get values from your objects. The Merge Sort should be able to sort whatever you need, independently of the source, just like Array.Sort would be your QuickSort alternative to sort whatever you need using that algorithm.

You could instead work on an EntityComparer that could extract values from sub properties. That shouldn't be hard to do.

Mixing everything in just one class will make it confusing to maintain and will make this code useful only for this case.

But that's just my opinion. =)
GeneralRe: deep sorting
radioman.lt
19:32 10 Sep '08  
..well i try about 'extracting', but i give up for now D'Oh!

peace & serenity

AnswerRe: deep sorting
Natan Vivo
9:46 11 Sep '08  
Hi,

I just did some changes in the PropertyComparer, so you can compare your deep fields.
I'll update the article later to use this version. Note that this can impact the speed of the sort due to more checks and more reflection.

Did some quick tests, seems to work fine. Just replace the old version. Nothing else is needed.

Hope it solves your problem. =)


using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;

namespace NVivo.Sorting
{
/// <summary>
/// This class compares objects using a property value.
/// It supports direct or sub properties.
/// </summary>
/// <typeparam name="T">The type of class to compare.</typeparam>
[DebuggerDisplay("{GetDebuggerText()}")]
public class PropertyComparer<T> : IComparer<T>
{
private string[] _propertyPath;
private bool _isDeep;
private MethodInfo _getMethod;
private Comparer _comparer;

// let's leave it here to avoid recreating it many times
private static readonly BindingFlags SearchFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.IgnoreCase;

/// <summary>
/// Creates a new PropertyComparer using a default Comparer.
/// </summary>
/// <param name="propertyName">The name of the property to compare.</param>
/// <
public PropertyComparer(string propertyName)
: this(propertyName, null)
{ }

/// <summary>
/// Creates a new PropertyComparer.
/// </summary>
/// <param name="propertyName">The name of the property to compare.</param>
/// <param name="valueComparer">A Comparer to compare the property value.</param>
public PropertyComparer(string propertyName, Comparer valueComparer)
{
ExtractMethod(typeof(T), propertyName);

if (valueComparer != null)
_comparer = valueComparer;
else
_comparer = Comparer.Default;
}

/// <summary>
/// Extracts the "get" accessor from the type.
/// </summary>
private void ExtractMethod(Type rootType, string fullPropertyName)
{
_propertyPath = fullPropertyName.Split('.');

Type t = rootType;
PropertyInfo pi = null;

// loops through each property until the last one
for (int i = 0; i < _propertyPath.Length; i++)
{
string property = _propertyPath[i];

// gets the property from the current member
pi = t.GetProperty(property, SearchFlags);

if (pi == null)
throw new InvalidOperationException(String.Format("Cannot find a instance property named '{0}' inside '{1}'.", property, t.FullName));

// updates the name on the list, just to get the right case
// this will give the correct case for the debugger and also give a very
// small speed up in the comparison as we don't need to ignore the case
_propertyPath[i] = pi.Name;

// sets the type to the type of the property for the next iteration
t = pi.PropertyType;
}

// gets the "get" acessor for the property
MethodInfo mi = pi.GetGetMethod();

if (mi == null)
throw new InvalidOperationException("The property '" + fullPropertyName + "' does not have a get accessor.");

_getMethod = mi;
_isDeep = _propertyPath.Length > 1;
}

/// <summary>
/// Compares two object's properties.
/// </summary>
public int Compare(T x, T y)
{
object xValue, yValue;

// only uses GetComparisonInstance if it is a "deep" property
if (_isDeep)
{
xValue = _getMethod.Invoke(GetComparisonInstance(x), null);
yValue = _getMethod.Invoke(GetComparisonInstance(y), null);
}
else
{
xValue = _getMethod.Invoke(x, null);
yValue = _getMethod.Invoke(y, null);
}

return _comparer.Compare(xValue, yValue);
}

// uses the _propertyPath to extract the correct instance to compare the values
private object GetComparisonInstance(object rootInstance)
{
object instance = rootInstance;

int lastIndex = _propertyPath.Length - 1;

// small check to make the method consistent simple property cases
if (lastIndex > 0)
{

// loops until the last - 1 property,
// which is the property what we want
// (ex: for Adress.City, we want the Address instance)
for (int i = 0; i < lastIndex; i++)
{
// gets the type of the instance
Type t = instance.GetType();

// extracts the property
PropertyInfo pi = t.GetProperty(_propertyPath[i], SearchFlags);

// extracts the property value from the current instance and prepares for the next iteration
instance = pi.GetValue(instance, null);
}
}

return instance;
}

// this method is used to display a more descriptive text in the debugger
private string GetDebuggerText()
{
return String.Format("{0}.{1}", _getMethod.DeclaringType.Name, String.Join(".", _propertyPath));
}
}
}

GeneralRe: deep sorting
radioman.lt
12:07 11 Sep '08  
Nice! Smile

peace & serenity

GeneralLINQ alternative
Sebastien Ros
1:09 10 Sep '08  
LINQ can already do it, and if you can't use .NET 3.5 you can still use nlinq.

However, good idea Wink

Sébastien Ros
[Euss][Blog]

GeneralRe: LINQ alternative
johannesnestler
2:42 10 Sep '08  
Is this what you meant, Sebastien? This example just shows the use of the (Linq) orderby clause

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LinqSorting
{
class Employee
{
public int ID { get; set; }
public string Name { get; set; }
public DateTime HireDate { get; set; }
public bool IsActive { get; set; }

public override string ToString()
{
return String.Format("{0}, {1}, {2}, {3}", ID, Name, HireDate, IsActive);
}
}

class Program
{
static List<Employee> GetTestEmployees()
{
return new List<Employee>() {
new Employee() { ID = 4, Name = "Anna", HireDate = new DateTime(2000, 09, 10), IsActive = true },
new Employee() { ID = 2, Name = "Barbara", HireDate = new DateTime(2001, 08, 08), IsActive = true },
new Employee() { ID = 1, Name = "Cecil", HireDate = new DateTime(1999, 01, 01), IsActive = false },
new Employee() { ID = 3, Name = "Doris", HireDate = new DateTime(2006, 04, 04), IsActive = true },
new Employee() { ID = 0, Name = "Eve", HireDate = new DateTime(2007, 12, 12), IsActive = true }};
}

static void Main(string[] args)
{
List<Employee> list = GetTestEmployees();
// Query for ascending sort.
IEnumerable<Employee> sortAscendingQuery =
from employee in list
orderby employee.ID orderby employee.IsActive //"ascending" is default
select employee;

foreach (Employee emp in sortAscendingQuery)
Console.WriteLine(emp);

Console.ReadKey();
}
}
}

GeneralRe: LINQ alternative
Sebastien Ros
3:11 10 Sep '08  
Yes but with a slight difference. To order multiple fields, you need to use 'ThenBy' for each additional field:
myList = myList.OrderBy(p => p.Value1).ThenBy(p => p.Value2).ToList();

Sébastien Ros
[Euss][Blog]

GeneralRe: LINQ alternative
Natan Vivo
3:13 10 Sep '08  
As I have written in the article, I am aware that this is possible using LINQ. But I decided to write this using only .NET 2.0 that is still relevant to a lot of people.

Thanks.
GeneralRe: LINQ alternative
Sebastien Ros
3:15 10 Sep '08  
As I have written, it was to mention how to use the "full" LINQ capabilities within 1.1 and 2.0.

Please read the message before posting. Seems you modified your response in the meantime Smile

Sébastien Ros
[Euss][Blog]

GeneralRe: LINQ alternative
gersonadr
17:18 16 Sep '08  
I think building your custom sorting is a good idea if performance or memory allocation are critical in your app (so you could choose between using an unstable-quicksort or memory consuming-mergesort) or, maybe, if you need to implement a custom sort in a multithread environment using atomic operations (good luck on THAT Wink)
Anyway, the article and the linq example are both usefull! tnx!
GeneralRe: LINQ alternative
Sebastien Ros
3:14 10 Sep '08  
But I'm also stupid, your syntax is correct, as it will be transformed to the methods I showed.

Sébastien Ros
[Euss][Blog]

GeneralCOOL!
radioman.lt
19:40 9 Sep '08  
Thank You! Big Grin

peace & serenity


Last Updated 9 Sep 2008 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010