AutoMapper映射ExpressionTree
问题描述
项目中使用AutoMapper进行VO&DTO&Entity的互相映射,但是默认Map方法不支持Expression的转换。如
Expression<Func<Entity,bool>> fun = _ => _.A == "A";
希望转换成
Expression<Func<Dto,bool>> fun = _ => _.A == "A";
似乎解决方案就是解析ExpressionTree并映射替换节点。正好找到了人家的提问和解决方案
http://stackoverflow.com/questions/7424501/automapper-for-funcs-between-selector-types
改造一下支持泛型,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | public static class FunctionCompositionExtensions { private static ConcurrentDictionary<Tuple<Type, Type>, Tuple<MethodInfo, Expression>> dictionary = new ConcurrentDictionary<Tuple<Type, Type>, Tuple<MethodInfo, Expression>>(); private static MethodInfo method = typeof (FunctionCompositionExtensions).GetMethod( "Compose" , BindingFlags.NonPublic | BindingFlags.Static); public static Expression<Func<D, bool >> MapExpression<S, D>( this Expression<Func<S, bool >> selector) { var bulidMethod = dictionary.GetOrAdd( new Tuple<Type, Type>( typeof (S), typeof (D)), _ => { var expression = Mapper.Engine.CreateMapExpression<D, S>(); return new Tuple<MethodInfo, Expression>(method.MakeGenericMethod( typeof (D), typeof ( bool ), typeof (S)), expression); }); return bulidMethod.Item1.Invoke( null , new [] { selector, bulidMethod.Item2 }) as Expression<Func<D, bool >>; } static Expression<Func<X, Y>> Compose<X, Y, Z>( this Expression<Func<Z, Y>> outer, Expression<Func<X, Z>> inner) { return Expression.Lambda<Func<X, Y>>( ParameterReplacer.Replace(outer.Body, outer.Parameters[0], inner.Body), inner.Parameters[0]); } static Expression<Predicate<X>> ComposePredicate<X, Z>( this Expression<Predicate<Z>> outer, Expression<Func<X, Z>> inner) { return Expression.Lambda<Predicate<X>>( ParameterReplacer.Replace(outer.Body, outer.Parameters[0], inner.Body), inner.Parameters[0]); } } class ParameterReplacer : ExpressionVisitor { private ParameterExpression _parameter; private Expression _replacement; private ParameterReplacer(ParameterExpression parameter, Expression replacement) { _parameter = parameter; _replacement = replacement; } public static Expression Replace(Expression expression, ParameterExpression parameter, Expression replacement) { return new ParameterReplacer(parameter, replacement).Visit(expression); } protected override Expression VisitParameter(ParameterExpression parameter) { if (parameter == _parameter) { return _replacement; } return base .VisitParameter(parameter); } } |
测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | public class Entity { public string A { get ; set ; } } public class Dto { public string A { get ; set ; } } Mapper.CreateMap<Entity, Dto>(); Mapper.CreateMap<Dto, Entity>(); var list = new List<Dto>() { new Dto() {A = "A" }, new Dto() {A = "B" }, new Dto() {A = "C" }, new Dto() {A = "D" }, new Dto() {A = "E" }, }; //Predicate<Entity> fun = _ => _.A =="A"; Expression<Func<Entity, bool >> funEntity = _ => _.A == "A" ; var query = list.Where(funEntity.MapExpression<Entity, Dto>().Compile()); Assert.True(query.Count() == 1); Expression<Func<Entity, bool >> funEntity2 = _ => _.A == "F" ; var query2 = list.Where(funEntity2.MapExpression<Entity, Dto>().Compile()); Assert.True(query2.Count() == 0); |
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET 原生驾驭 AI 新基建实战系列:向量数据库的应用与畅想
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
· 一次Java后端服务间歇性响应慢的问题排查记录
· dotnet 源代码生成器分析器入门
· ASP.NET Core 模型验证消息的本地化新姿势
· ThreeJs-16智慧城市项目(重磅以及未来发展ai)
· .NET 原生驾驭 AI 新基建实战系列(一):向量数据库的应用与畅想
· Ai满嘴顺口溜,想考研?浪费我几个小时
· Browser-use 详细介绍&使用文档
· 软件产品开发中常见的10个问题及处理方法