Search code examples
c#.netlinq.net-coreexpression-trees

Net Core: Find Data Type for any Variable Field in Class


How do I take this OrderBy Expression tree and make it accept any Order type , int, float, string, boolean etc? Is it possible? Right now its typecasted to only string. Should I just convert everything as string when calling method, or is there better way to make more generic?

I just need the data type of this propertyName in class T, so I can place in function below. Testing these out, no luck yet.

MemberType, GetType(), FieldType

OrderBy Expression Tree in Net Core Linq for Extension Method

Creating Expression:

public static class ExpressionTreesExtesion
{
    public static Expression<Func<T,string>> OrderByExpression<T>(this IEnumerable<T> enumerable, string propertyName)
    {
        var propInfo = typeof(T).GetProperty(propertyName);

        var collectionType = typeof(T);

        var parameterExpression = Expression.Parameter(collectionType, "x");
        var propertyAccess = Expression.MakeMemberAccess(parameterExpression, propInfo);
        var orderExpression = Expression.Lambda<Func<T,string>>(propertyAccess, parameterExpression);
        return orderExpression;
    }
}

How to Call:

var ProductExpression = records.OrderByExpression("Name");

var result  = records.OrderBy(ProductExpression.Compile());
ProductExpression.Compile() above will compile into x => x.Name, where column name is supplied at the run-time

Solution

  • Because the type is not known at compile time, you will not be able to use a strongly typed return type like Expression<Func<T,TKey>>.

    public static class ExpressionTreesExtension {
        static readonly Type funcTTResult = typeof(Func<,>);
        public static IOrderedQueryable<T> OrderByProperty<T>(this IEnumerable<T> enumerable, string propertyName) {
            var itemType = typeof(T);
            var propertyInfo = itemType.GetProperty(propertyName);
            var propertyType = propertyInfo.PropertyType;
            // Func<T,TPropertyType>
            var delegateType = funcTTResult.MakeGenericType(itemType, propertyType);
            // T x =>
            var parameterExpression = Expression.Parameter(itemType, "x");
            // T x => x.Property
            var propertyAccess = Expression.Property(parameterExpression, propertyInfo);
            // Func<T,TPropertyType> = T x => x.Property
            var keySelector = Expression.Lambda(delegateType, propertyAccess, parameterExpression);
    
            var query = enumerable.AsQueryable();
    
            // query.OrderBy(x => x.Property)
            MethodCallExpression orderByExpression = Expression.Call(
                 typeof(Queryable),
                 "OrderBy",
                 new[] { query.ElementType, propertyInfo.PropertyType },
                 query.Expression, keySelector);
    
            // Create an executable query from the expression tree. 
            return (IOrderedQueryable<T>)query.Provider.CreateQuery<T>(orderByExpression);
        }
    }
    

    Reference How to: Use Expression Trees to Build Dynamic Queries (C#)

    And used like

    //IEnumerable<Person> records...
    var data = records.OrderByProperty("Name");