using System.Collections;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.ComponentModel;
using System.Linq.Expressions;
using System.Text.RegularExpressions;
using System.Linq.Dynamic.Core;
using System.Linq.Dynamic.Core.Parser;
public string Name {get;set;}
public string Desc {get;set;}
public DateTime Time {get;set;}
private static List<MyModel> list = new List<MyModel>{
new () {Name = "test", Time = DateTime.Now},
new () {Name = "test2", Time = DateTime.Now.AddDays(-1)},
public static Dictionary<string, Expression> Filters = new();
private static Type ItemType { get; set; } = typeof(MyModel);
private static Type QueryableItemType { get; set; } = typeof(IQueryable<MyModel>);
private static Expression QueryableItemTypeExpression = new List<MyModel>().AsQueryable().Expression;
public static Dictionary<string, bool?> Sorts = new();
public static Expression GetDynamicQuery()
Expression? filterExpression = null;
Expression? sortExpression = null;
Expression? combinedExpression = null;
var itemX = Expression.Parameter(ItemType, "x");
var queryableX = Expression.Parameter(QueryableItemType, "x");
foreach (var (key, value) in Filters)
var property = ItemType.GetProperty(key);
if (property == null) continue;
if (expression == null) continue;
filterExpression = filterExpression == null ? expression : Expression.AndAlso(filterExpression, expression);
if (filterExpression != null)
var filterLambda = Expression.Lambda<Func<MyModel, bool>>(filterExpression, itemX);
filterExpression = Expression.Call(
QueryableItemTypeExpression,
foreach (var (key, value) in Sorts)
var property = ItemType.GetProperty(key);
if (property == null) continue;
var isDescending = value ?? false;
var selector = Expression.Lambda(Expression.PropertyOrField(itemX, key), itemX);
if (filterExpression != null && combinedExpression == null)
combinedExpression = Expression.Call(typeof(Queryable),
isDescending ? nameof(Queryable.OrderByDescending) : nameof(Queryable.OrderBy),
new[] { ItemType, selector.ReturnType },
Expression.Quote(selector));
else if (filterExpression != null && combinedExpression != null)
combinedExpression = Expression.Call(typeof(Queryable),
isDescending ? nameof(Queryable.ThenByDescending) : nameof(Queryable.ThenBy),
new[] { ItemType, selector.ReturnType },
Expression.Quote(selector));
else if (sortExpression == null)
sortExpression = Expression.Call(typeof(Queryable),
isDescending ? nameof(Queryable.OrderByDescending) : nameof(Queryable.OrderBy),
new[] { ItemType, selector.ReturnType },
Expression.Quote(selector));
sortExpression = Expression.Call(typeof(Queryable),
isDescending ? nameof(Queryable.ThenByDescending) : nameof(Queryable.ThenBy),
new[] { ItemType, selector.ReturnType },
Expression.Quote(selector));
if (combinedExpression != null)
return combinedExpression;
if (filterExpression != null)
public static void Main()
var list = new List<MyModel>{
new () {Name = "test", Time = DateTime.Now},
new () {Name = "test2", Time = DateTime.Now.AddDays(-1)},
var paramExpression = Expression.Parameter(ItemType, "x");
var property = ItemType.GetProperty(nameof(MyModel.Name));
var tc = TypeDescriptor.GetConverter(property.PropertyType);
var parsedValue = tc.ConvertFromString("Weee");
var expression = Expression.Equal(Expression.Property(paramExpression, property), Expression.Constant(parsedValue, property.PropertyType));
Filters.Add(nameof(MyModel.Name), expression);
parsedValue = tc.ConvertFromString("Woo");
expression = Expression.NotEqual(Expression.Property(paramExpression, property), Expression.Constant(parsedValue, property.PropertyType));
Filters.Add(nameof(MyModel.Desc), expression);
Sorts.Add(nameof(MyModel.Name), true);
Sorts.Add(nameof(MyModel.Desc), false);
var equalLambda = Expression.Lambda<Func<MyModel, bool>>(expression, paramExpression);
MethodCallExpression whereEqualCallExpression = Expression.Call(
new Type[] { typeof(MyModel) },
QueryableItemTypeExpression,
Console.WriteLine(whereEqualCallExpression.ToString());
FiddleHelper.WriteTable(list.AsQueryable().Provider.CreateQuery(whereEqualCallExpression));
var query = GetDynamicQuery();
ParameterExpression x = Expression.Parameter(typeof(MyModel), "x");
ParameterExpression y = Expression.Parameter(typeof(IQueryable<MyModel>), "x");
var symbols = new[] { y };
var config = new ParsingConfig{ResolveTypesBySimpleName = true, RenameParameterExpression = true};
Expression body = new ExpressionParser(symbols, "it.Where(((Name == \"Weee\") AndAlso (Name != \"Woo\"))).OrderByDescending(Name).ThenBy(Desc)", null, null).Parse(null);
Console.WriteLine(String.Compare("test", "test"));
var param = Expression.Parameter(typeof(MyModel), "x");
var compare = Expression.LessThan(Expression.Call(
Expression.PropertyOrField(param, nameof(MyModel.Name)),
Expression.Constant("test")),
var lambda = Expression.Lambda<Func<MyModel, bool>>(compare, param);
MethodCallExpression whereCallExpression = Expression.Call(
new Type[] { typeof(MyModel) },
QueryableItemTypeExpression,
Console.WriteLine(whereCallExpression.ToString());
FiddleHelper.WriteTable(list.AsQueryable().Provider.CreateQuery<MyModel>(whereCallExpression));
var parameter = Expression.Parameter(ItemType, "x");
var propertyAccess = Expression.MakeMemberAccess(parameter, property);
var orderByExp = Expression.Lambda(propertyAccess, parameter);
MethodCallExpression orderByCallExpression = Expression.Call(
new Type[] { ItemType, orderByExp.ReturnType },
Expression.Quote(orderByExp));
Console.WriteLine(orderByCallExpression.ToString());
FiddleHelper.WriteTable(list.AsQueryable().Provider.CreateQuery<MyModel>(orderByCallExpression));