IOrderedEnumerable and defensive programming

1.1k views Asked by At

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

1

There are 1 answers

3
Roman Boiko On BEST ANSWER

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();
    }
}