1

I am trying to sort an IQueryable object dynamically (using reflection in order to locate the requested ordering field) and I have followed the approach below, where I essentially use extension methods on the queryable and then dynamically build the Lambda to be used for the sorting

public static class IQueryableOrderingExtensions
{
    public static IOrderedQueryable<T> OrderBy<T>(this IQueryable<T> source, string propertyName)
    {
        return source.OrderBy(ToExpression<T>(propertyName));
    }

    public static IOrderedQueryable<T> OrderByDescending<T>(this IQueryable<T> source, string propertyName)
    {
        return source.OrderByDescending(ToExpression<T>(propertyName));
    }

    private static Expression<Func<T, object>> ToExpression<T>(string propertyName)
    {
        var parameter = Expression.Parameter(typeof(T));
        var property = Expression.Property(parameter, propertyName);

        UnaryExpression propAsObject = null;
        if (property.Type.IsEnum)
        {
            //TODO
        }
        else
        {
            propAsObject = Expression.Convert(property, typeof(object));
        }
        
        return Expression.Lambda<Func<T, object>>(propAsObject, parameter);            
    }
}

The issue I am facing has to do with Enums, that by default are being treated as integers when sorting. Example (Waiting Approval = 0, Approved = 1 etc.)

I there a way to achieve this? Is there a way to map the property to something like property.ToString?

mariosk89
  • 944
  • 1
  • 11
  • 31
  • 1
    See this [link](https://github.com/naeemaei/AgGridDynamicFilter/blob/c29bb86e075c6d69b608d85162a8e7931d6011e7/src/AgGridDynamicFilter/Extensions/Linq.cs#L129) can help you – Hamed Naeemaei Dec 28 '21 at 08:53
  • 1
    So you went a lexicographical ordering based on the names of the members instead of there numeric representations? – Aluan Haddad Dec 28 '21 at 08:56
  • 1
    Check [this one](https://stackoverflow.com/a/65850085/10646316). It contains full solution for such operation. – Svyatoslav Danyliv Dec 28 '21 at 09:12

1 Answers1

1

Thanks everyone for your answers. I ended up doing the following:

private static Expression<Func<T, object>> ToExpression<T>(string propertyName)
    {
        var parameter = Expression.Parameter(typeof(T));
        var property = Expression.Property(parameter, propertyName);
        
        UnaryExpression propertyObject = Expression.Convert(property, typeof(object));
        if (property.Type.IsEnum)
        {
            //sort enums by their string values
            var toStringMethod = typeof(object).GetMethod("ToString");
            return Expression.Lambda<Func<T, object>>(Expression.Call(propertyObject, toStringMethod), parameter);
        }
        else
        {
            return Expression.Lambda<Func<T, object>>(propertyObject, parameter); 
        }
    }

Essentially is casts the enum into a string by 'calling' the ToString method on the converted property object

mariosk89
  • 944
  • 1
  • 11
  • 31