using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Linq.Expressions; namespace umbraco.MacroEngines { public static class DynamicNodeListOrdering { private static TOut Reduce(Func func, DynamicNode node) { var value = func(node); while (value is Func) { value = (value as Func)(node); } //when you're sorting a list of properties //and one of those properties doesn't exist, it will come back as DynamicNull //when that gets handled by the expression tree parser, it's converted to be false //which lets .Where work properly with e.g. umbracoNaviHide which may not be defined //on all properties //this checks to see if the type of value is bool, and if it is, and it's false //then return false //in a case where Reduce is being called, this will return false, which is the //same as the actual real value //but when Reduce [a dynamicnode dynamic property call] is called //it will result in null, (because default(object) is null) //which will cause the item with the missing property to sort up to the top of the list if (value.GetType() == typeof(bool) && !((value as bool?) ?? false)) { return default(TOut); } if (value.GetType() == typeof(string) && string.IsNullOrEmpty((value as string))) { return default(TOut); } return (TOut)value; } public static IOrderedQueryable OrderBy(object source, object key) { IEnumerable typedSource = source as IEnumerable; LambdaExpression lambda = key as LambdaExpression; //if the lambda we have returns an actual property, not a dynamic one, //then the TOut of the func will be the actual type, not object //Func func = (Func)lambda.Compile(); var func = lambda.Compile(); var TOut = func.GetType().GetGenericArguments()[1]; IOrderedQueryable result = null; if (TOut == typeof(Func)) { result = (IOrderedQueryable)typedSource .OrderBy(x => Reduce(func as Func, x)) .AsQueryable(); } if (TOut == typeof(object)) { result = (IOrderedQueryable)typedSource .OrderBy(x => Reduce(func as Func, x)) .AsQueryable(); } if (TOut == typeof(bool)) { result = (IOrderedQueryable)typedSource .OrderBy(x => Reduce(func as Func, x)) .AsQueryable(); } if (TOut == typeof(decimal)) { result = (IOrderedQueryable)typedSource .OrderBy(x => Reduce(func as Func, x)) .AsQueryable(); } if (TOut == typeof(int)) { result = (IOrderedQueryable)typedSource .OrderBy(x => Reduce(func as Func, x)) .AsQueryable(); } if (TOut == typeof(string)) { result = (IOrderedQueryable)typedSource .OrderBy(x => Reduce(func as Func, x)) .AsQueryable(); } if (TOut == typeof(DateTime)) { result = (IOrderedQueryable)typedSource .OrderBy(x => Reduce(func as Func, x)) .AsQueryable(); } return result; } public static IOrderedQueryable ThenBy(object source, object key) { IOrderedQueryable typedSource = source as IOrderedQueryable; LambdaExpression lambda = key as LambdaExpression; var func = lambda.Compile(); var TOut = func.GetType().GetGenericArguments()[1]; IOrderedQueryable result = null; if (TOut == typeof(Func)) { result = (IOrderedQueryable)typedSource .ThenBy(x => Reduce(func as Func, x)) .AsQueryable(); } if (TOut == typeof(object)) { result = (IOrderedQueryable)typedSource .ThenBy(x => Reduce(func as Func, x)) .AsQueryable(); } if (TOut == typeof(bool)) { result = (IOrderedQueryable)typedSource .ThenBy(x => Reduce(func as Func, x)) .AsQueryable(); } if (TOut == typeof(decimal)) { result = (IOrderedQueryable)typedSource .ThenBy(x => Reduce(func as Func, x)) .AsQueryable(); } if (TOut == typeof(int)) { result = (IOrderedQueryable)typedSource .ThenBy(x => Reduce(func as Func, x)) .AsQueryable(); } if (TOut == typeof(string)) { result = (IOrderedQueryable)typedSource .ThenBy(x => Reduce(func as Func, x)) .AsQueryable(); } if (TOut == typeof(DateTime)) { result = (IOrderedQueryable)typedSource .ThenBy(x => Reduce(func as Func, x)) .AsQueryable(); } return result; } public static IOrderedQueryable OrderByDescending(object source, object key) { IEnumerable typedSource = source as IEnumerable; LambdaExpression lambda = key as LambdaExpression; var func = lambda.Compile(); var TOut = func.GetType().GetGenericArguments()[1]; IOrderedQueryable result = null; if (TOut == typeof(Func)) { result = (IOrderedQueryable)typedSource .OrderByDescending(x => Reduce(func as Func, x)) .AsQueryable(); } if (TOut == typeof(object)) { result = (IOrderedQueryable)typedSource .OrderByDescending(x => Reduce(func as Func, x)) .AsQueryable(); } if (TOut == typeof(bool)) { result = (IOrderedQueryable)typedSource .OrderByDescending(x => Reduce(func as Func, x)) .AsQueryable(); } if (TOut == typeof(decimal)) { result = (IOrderedQueryable)typedSource .OrderByDescending(x => Reduce(func as Func, x)) .AsQueryable(); } if (TOut == typeof(int)) { result = (IOrderedQueryable)typedSource .OrderByDescending(x => Reduce(func as Func, x)) .AsQueryable(); } if (TOut == typeof(string)) { result = (IOrderedQueryable)typedSource .OrderByDescending(x => Reduce(func as Func, x)) .AsQueryable(); } if (TOut == typeof(DateTime)) { result = (IOrderedQueryable)typedSource .OrderByDescending(x => Reduce(func as Func, x)) .AsQueryable(); } return result; } public static IOrderedQueryable ThenByDescending(object source, object key) { IOrderedQueryable typedSource = source as IOrderedQueryable; LambdaExpression lambda = key as LambdaExpression; var func = lambda.Compile(); var TOut = func.GetType().GetGenericArguments()[1]; IOrderedQueryable result = null; if (TOut == typeof(Func)) { result = (IOrderedQueryable)typedSource .ThenByDescending(x => Reduce(func as Func, x)) .AsQueryable(); } if (TOut == typeof(object)) { result = (IOrderedQueryable)typedSource .ThenByDescending(x => Reduce(func as Func, x)) .AsQueryable(); } if (TOut == typeof(bool)) { result = (IOrderedQueryable)typedSource .ThenByDescending(x => Reduce(func as Func, x)) .AsQueryable(); } if (TOut == typeof(decimal)) { result = (IOrderedQueryable)typedSource .ThenByDescending(x => Reduce(func as Func, x)) .AsQueryable(); } if (TOut == typeof(int)) { result = (IOrderedQueryable)typedSource .ThenByDescending(x => Reduce(func as Func, x)) .AsQueryable(); } if (TOut == typeof(string)) { result = (IOrderedQueryable)typedSource .ThenByDescending(x => Reduce(func as Func, x)) .AsQueryable(); } if (TOut == typeof(DateTime)) { result = (IOrderedQueryable)typedSource .ThenByDescending(x => Reduce(func as Func, x)) .AsQueryable(); } return result; } } }