views:

179

answers:

1

Hi,

I'm fond of defensive programming. I hate exception throwing, but this is not the subject of my question.

I adapted an extension to linQ to be able to perform an order by with a column name

        public static IEnumerable<T> OrderBy<T>(this IEnumerable<T> list, string sortExpression)

With defensive programming, this method returns the given enumerable if the column name is not valid.

Now I need to perform a secondary sorting with ThenBy. So I need that signature :

        public static IOrderedEnumerable<T> OrderBy<T>(this IEnumerable<T> list, string sortExpression)

I need to return a IOrderedEnumerable. My problem is to keep my defensive programming feature : I must return the given set is the column name is invalid.

Is there a clean way to do this ? All I'm thinking of are kind of tricks :

  • Use reflection to order by the first found property, which is risky because the property may not be sorting-allowed
  • Implement my own IOrderedEnumerable, which is risky too because I perform ordering on IQueryable or IList, then I perform other LinQ operations, so I fear side effects.

And advice / suggestion ? Thanks

+3  A: 

You may do any ordering. If column doesn't exist, just leave your input enumerable as it was before. To do this, create key selector that returns the same value for all elements.

See example:

using System;
using System.Linq;
using System.Collections.Generic;
using System.Reflection;

static class Program
{
    public static IOrderedEnumerable<T> OrderBy<T>(this IEnumerable<T> list, string sortExpression) where T : class
    {
        Func<T, Int32> keySelector = (elem) =>
        {
            PropertyInfo pi = typeof(T).GetProperty(sortExpression, typeof(Int32));
            if (pi == null)
                return 0; // return the same key for all elements

            return Int32.Parse(pi.GetValue(elem, null).ToString());
        };

        return list.OrderBy(keySelector);
    }

    static void Main(string[] args)
    {
        // Create an array of strings to sort.
        string[] fruits = { "apricot", "orange", "banana", "mango", "apple", "grape", "strawberry" };

        // Sort by "column" Length
        foreach (string s in fruits.OrderBy<string>("Length"))
            Console.WriteLine(s);
        Console.WriteLine();

        // Sort by non-existing column
        foreach (string s in fruits.OrderBy<string>("ength"))
            Console.WriteLine(s);
        Console.ReadKey();
    }
}
Roman Boiko
Note that "column" in this example has type Int32 and is just one of properties of element. You may have type String instead, or create a generic method.
Roman Boiko
Note that ordering when key is always the same (0 in my example) **does not** guarantee you that output will have the same order as input. I think it will be the same, but formally order may be undetermined in this case.
Roman Boiko
Undetermined order is not a problem if your column name is wrong, as long as the result is the same as the input.I just don't want to check if the result is null or catch an exception ;)Thanks for your answer, glad it helped you too. I'll test it asap.
Mose