using System.Collections.Generic;
using System.Linq.Expressions;
public static void Main()
IQueryable<DemoClass> data = GetTestData().AsQueryable();
OrderExpressions<DemoClass> expressions = new OrderExpressions<DemoClass>()
.Add(x => x.Created, "created")
.Add(x => x.Approved, "approved")
.Add(x =>x.Author.Name, "author");
BuildAndPrintQuery<DemoClass>(data, expressions, "+created", "-approved", "+author");
BuildAndPrintQuery<DemoClass>(data, expressions, "+author", "-created", "-approved");
BuildAndPrintQuery<DemoClass>(data, expressions, "-author", "+created", "-approved");
BuildAndPrintQuery<DemoClass>(data, expressions, "-created");
BuildAndPrintQuery<DemoClass>(data, expressions, "+created");
BuildAndPrintQuery<DemoClass>(data, expressions, "created");
public static void BuildAndPrintQuery<T>(IQueryable<T> data, OrderExpressions<T> expressions, params string[] arguments)
IOrderedQueryable<T> result = data.OrderBy(expressions, arguments);
Console.WriteLine(String.Join(", ", arguments));
foreach(T entry in result)
Console.WriteLine(entry);
public static IEnumerable<DemoClass> GetTestData()
yield return new DemoClass
Author = new Person { Name = "Name A" },
Created = DateTime.Now.AddDays(-1)
yield return new DemoClass
Author = new Person { Name = "Name C" },
Created = DateTime.Now.AddDays(-2)
yield return new DemoClass
Author = new Person { Name = "Name E" },
Created = DateTime.Now.AddDays(-3)
yield return new DemoClass
Author = new Person { Name = "Name B" },
Created = DateTime.Now.AddDays(-4)
yield return new DemoClass
Author = new Person { Name = "Name D" },
Created = DateTime.Now.AddDays(-5)
yield return new DemoClass
Author = new Person { Name = "Name A" },
Created = DateTime.Now.AddDays(-11)
yield return new DemoClass
Author = new Person { Name = "Name C" },
Created = DateTime.Now.AddDays(-3)
yield return new DemoClass
Author = new Person { Name = "Name E" },
Created = DateTime.Now.AddDays(-5)
yield return new DemoClass
Author = new Person { Name = "Name B" },
Created = DateTime.Now.AddDays(-8)
yield return new DemoClass
Author = new Person { Name = "Name D" },
Created = DateTime.Now.AddDays(-5)
public class OrderExpressions<T>
private readonly Dictionary<string, Expression<Func<T, object>>> _mappings = new Dictionary<string, Expression<Func<T, object>>>();
public OrderExpressions<T> Add(Expression<Func<T, object>> expression, string keyword)
_mappings.Add(keyword, expression);
public Expression<Func<T, object>> this[string keyword]
get { return _mappings[keyword]; }
public static class KeywordSearchExtender
public static IOrderedQueryable<T> OrderBy<T>(this IQueryable<T> data, OrderExpressions<T> mapper, params string[] arguments)
if (arguments.Length == 0)
throw new ArgumentException(@"You need at least one argument!", "arguments");
List<SortArgument> sorting = arguments.Select(a => new SortArgument(a)).ToList();
IOrderedQueryable<T> result = null;
for (int i = 0; i < sorting.Count; i++)
SortArgument sort = sorting[i];
Expression<Func<T, object>> lambda = mapper[sort.Keyword];
result = sorting[i].Ascending ? data.OrderBy(lambda) : data.OrderByDescending(lambda);
result = sorting[i].Ascending ? result.ThenBy(lambda) : result.ThenByDescending(lambda);
public class SortArgument
public SortArgument(string term)
if (term.StartsWith("-"))
Keyword = term.Substring(1);
else if (term.StartsWith("+"))
Keyword = term.Substring(1);
public string Keyword { get; set; }
public bool Ascending { get; set; }
public DateTime Created { get; set; }
public bool Approved { get; set; }
public Person Author { get; set; }
public override string ToString()
return Created + " " + Approved + " " + Author.Name;
public string Name { get; set; }