C#之表达式树使用
Posted dotNET跨平台
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C#之表达式树使用相关的知识,希望对你有一定的参考价值。
目的
遇到一个场景需要接收一个表的列来进行动态排序,比如我想根据CreateTime进行正序排序,加上我使用的ORM框架是EFCore,那么我一下子就想到应该使用OrderBy,然后接收一个要排序的列
query.OrderBy("CreateTime")
但是这样子是不行的,所以寻找方案后找到了一个nuget包System.Linq.Dynamic.Core,该包的用法如下
//OrderBy("time asc")
query.OrderBy($"orderContent.SortName orderContent.Sort");
但是把这样子就会多引用一个nuget包,所以就在继续找其他方法,就找到了使用表达式树来实现,那么就简单介绍几种表达式树可能用到的例子吧。
是什么
定义一种树状的数据结构来描述c#中的代码,这种树状的数据结构就是表达式树。
还是直接放上原文的链接吧
和委托的关系
表达式树其实与委托已经没什么关系了,非要扯上关系,那就这么说吧,表达式树是存放委托的容器。
要用Lambda表达式的时候,直接从表达式中获取出来,Compile()就可以直接用了。如下代码:
static void Main(string[] args)
Expression<Func<int, int, int>> exp = (x, y) => x + y;
Func<int, int, int> fun = exp.Compile();
int result = fun(2, 3);
使用场景
平常我是很少或者几乎不自己构建表达式树,就像上面文章那个老哥说的那样子,表达式树一般是给框架的作者用的。
操作
下文中UserDto.GetUserDtos()返回的是一个UserDto集合(算是一个伪代码),虽然本文示例没有直接查询的数据库,但是我已经在其他项目中测试过,在执行输出SQL中已经体现出来效果。
本文示例虽已经过验证,但是还未上生产。
简单筛选
public void SampleWhere()
var user = UserDto.GetUserDtos().AsQueryable();
//泛型写法
Func<UserDto, bool> predicate = s => s.Deleted=false;
var list = user.Where(predicate).ToList(); // 这个执行是在内存中执行的
//表达式树写法
Expression<Func<UserDto, bool>> lambdaExp = (s) => !s.Deleted;
var list2 = user.Where(lambdaExp).ToList();
通过简单的筛选去学习如何创建简单的表达式树
/// <summary>
/// 通过简单的筛选去学习
/// </summary>
public void SampleWhereToStudy()
// 实现效果 t => t.Name == "张三"
var user = UserDto.GetUserDtos().AsQueryable();
var result1 = user.Where(t => t.Name == "张三");
ParameterExpression demo = Expression.Parameter(typeof(UserDto), "t");
Console.WriteLine(demo);
MemberExpression demo_name = Expression.Property(demo, "Name");
Console.WriteLine(demo_name);// t.Name
ConstantExpression value = Expression.Constant("张三");
Console.WriteLine(value);// 张三
BinaryExpression greaterThen = Expression.Equal(demo_name, value);
Console.WriteLine(greaterThen); // t.Name=="张三"
var lambda = Expression.Lambda<Func<UserDto, bool>>(greaterThen, demo);
Console.WriteLine(lambda);// t=>t.Name=="张三"
var lamdbaFunc = lambda.Compile();// 编译表达式
Console.WriteLine(lamdbaFunc);// System.Func`2[CSharpBasic.Model.UserDto,System.Boolean]
var resultTrue = lamdbaFunc(new UserDto Name = "张三" );
Console.WriteLine(resultTrue);//True
// 筛选张三
var result = user.Where(lamdbaFunc).ToList();
资料来自:超超老师教程
动态筛选
public void DynamicWhere()
//实现效果:已知一个表UserDto 包含属性Name、Address、Id等,需要实现通过属性进行动态过滤
var user = UserDto.GetUserDtos().AsQueryable();
var list2 = user.EqualWhere("Name", "张三").FirstOrDefault();
// 执行SQL:SELECT u.id, u.account,u.name FROM test."user" AS u WHERE u.name = '张三'
// 扩展方法
public static class ExpressExtensons
/// <summary>
/// 等于筛选
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="queryable"></param>
/// <param name="whereField"></param>
/// <param name="value"></param>
/// <returns></returns>
public static IQueryable<T> EqualWhere<T>(this IQueryable<T> queryable, string whereField, object value)
return queryable.Where<T>(whereField, value);
/// <summary>
/// 小于筛选
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="queryable"></param>
/// <param name="whereField"></param>
/// <param name="value"></param>
/// <returns></returns>
public static IQueryable<T> LessWhere<T>(this IQueryable<T> queryable, string whereField, object value)
return queryable.Where<T>(whereField, value, 1);
/// <summary>
/// 大于筛选
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="queryable"></param>
/// <param name="whereField"></param>
/// <param name="value"></param>
/// <returns></returns>
public static IQueryable<T> GreaterWhere<T>(this IQueryable<T> queryable, string whereField, object value)
return queryable.Where<T>(whereField, value, 1);
private static IQueryable<T> Where<T>(this IQueryable<T> queryable, string whereField, object value, int type = 0)
var paramExp = Expression.Parameter(typeof(T), "t");
//因为这个Property里面已经包含属性校验的功能,所以不用再另外写了
var memberExp = Expression.Property(paramExp, whereField);
//值表达式
var valueExp = Expression.Constant(value);
var exp = type switch
//小于
1 => Expression.LessThan(memberExp, valueExp),
//小于等于
2 => Expression.LessThanOrEqual(memberExp, valueExp),
//大于
3 => Expression.GreaterThan(memberExp, valueExp),
//大于等于
4 => Expression.GreaterThanOrEqual(memberExp, valueExp),
//等于
_ => Expression.Equal(memberExp, valueExp),
;
var lambda = Expression.Lambda<Func<T, bool>>(exp, paramExp);
return queryable.Where(lambda);
动态排序
public void DynamicOrderby()
// 实现效果
var userQueryable = UserDto.GetUserDtos().AsQueryable();
var sortList = userQueryable.OrderBy(t => t.CreateTime).ToList();
foreach (var item in sortList)
Console.WriteLine(item.CreateTime);
Console.WriteLine("-----------------");
// 通过表达式树去实现效果
var list = userQueryable.OrderBy("CreateTime", false);
// 执行SQL:SELECT u.id, u.account, u.create_time FROM test."user" AS u ORDER BY u.create_time DESC
foreach (var item in list)
Console.WriteLine(item.CreateTime);
public static class ExpressExtensons
/// <summary>
/// 根据字段排序处理
/// </summary>
/// <typeparam name="T">泛型列</typeparam>
/// <param name="queryable">查询queryable</param>
/// <param name="sortField">排序列</param>
/// <param name="isAsc">true正序 false倒序</param>
/// <returns></returns>
public static IQueryable<T> OrderBy<T>(this IQueryable<T> queryable, string sortField, bool isAsc = true)
var parameter = Expression.Parameter(typeof(T));
var property = typeof(T).GetProperty(sortField);
if (property == null)
throw new ArgumentNullException($"无效的属性 sortField");
var memberExpression = Expression.Property(parameter, property);
var orderbeExpression = Expression.Lambda(memberExpression, new ParameterExpression[] parameter );
var orderMethod = isAsc ? "OrderBy" : "OrderByDescending";
var resultExpression = Expression.Call(typeof(Queryable), orderMethod, new Type[] queryable.ElementType, property.PropertyType ,
new Expression[] queryable.Expression, Expression.Quote(orderbeExpression) );
return queryable.Provider.CreateQuery<T>(resultExpression);
动态查询指定属性
通过传递一个字符串,然后查询指定的列返回
var userQueryable = UserDto.GetUserDtos().AsQueryable();
ParameterExpression parameter1 = Expression.Parameter(typeof(UserDto));
MemberExpression men = Expression.Property(parameter1, "Name");
var selectFieldExpression = Expression.Lambda<Func<UserDto, string>>(men, new ParameterExpression[] parameter1 );
var result1 = userQueryable.Select(selectFieldExpression).ToList();
通过编写一个映射后的类实现简单的对应映射转换
public void DynamicSelect()
var userQueryable = UserDto.GetUserDtos().AsQueryable();
// 简单映射转换
var result2 = userQueryable.SelectMapper<UserDto, UserTest>().ToList();
// 执行SQL:SELECT u.id AS "Id", u.account AS "Account" FROM test."user" AS u
public static class ExpressExtensons
/// <summary>
/// 查询映射
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="M"></typeparam>
/// <param name="queryable"></param>
/// <returns></returns>
public static IQueryable<M> SelectMapper<T, M>(this IQueryable<T> queryable)
var parameter = Expression.Parameter(typeof(T), "t");
var newExpression = Expression.New(typeof(M));
var mapperType = typeof(T).GetProperties();
var listBinding = new List<MemberBinding>();
foreach (var item in typeof(M).GetProperties())
if (!mapperType.Any(t => t.Name == item.Name))
continue;
var mem = Expression.Property(parameter, item.Name);// t.name
var member = typeof(M).GetMember(item.Name)[0];
MemberBinding memBinding = Expression.Bind(member, mem);// 这里传mem是用t.name给他赋值
listBinding.Add(memBinding);
var memberExp = Expression.MemberInit(newExpression, listBinding);
var selectExpression = Expression.Lambda<Func<T, M>>(memberExp, new ParameterExpression[] parameter );
return queryable.Select(selectExpression);
资料
表达式树资料:https://www.cnblogs.com/li-peng/p/3154381.html
以上是关于C#之表达式树使用的主要内容,如果未能解决你的问题,请参考以下文章