使用AutoMapper时Expression的转换
此文章为转载:http://www.bubuko.com/infodetail-699735.html
参考链接:
http://q.cnblogs.com/q/34480/ dudu有回复,其中一个链接http://stackoverflow.com/questions/7424501/automapper-for-funcs-between-selector-types可以打开,并且本人主要参考此链接进行修改
下文链接为automapper相关源码
http://www.symbolsource.org/Public/Metadata/NuGet/Project/AutoMapper/3.3.0-ci1017/Release/Unsupported,Version%3Dv0.0/AutoMapper/AutoMapper/Internal/MappingExpression.cs?ImageName=AutoMapper
以下为转载内容:
问题描述
项目中使用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 #region using namespace 2 3 using System; 4 using System.Collections.Concurrent; 5 using System.Linq.Expressions; 6 using System.Reflection; 7 using AutoMapper; 8 using AutoMapper.QueryableExtensions; 9 10 #endregion 11 12 namespace Core 13 { 14 public static class FunctionCompositionExtensions 15 { 16 private static readonly ConcurrentDictionary<Tuple<Type, Type>, Tuple<MethodInfo, Expression>> Dictionary = 17 new ConcurrentDictionary<Tuple<Type, Type>, Tuple<MethodInfo, Expression>>(); 18 19 private static readonly MethodInfo Method = typeof (FunctionCompositionExtensions).GetMethod("Compose", 20 BindingFlags.NonPublic | BindingFlags.Static); 21 22 public static Expression<Func<TDestination, bool>> MapExpression<TSource, TDestination>( 23 this Expression<Func<TSource, bool>> selector) 24 { 25 var bulidMethod = Dictionary.GetOrAdd(new Tuple<Type, Type>(typeof (TSource), typeof (TDestination)), _ => 26 { 27 var expression = Mapper.Engine.CreateMapExpression<TDestination, TSource>(); 28 return new Tuple<MethodInfo, Expression>( 29 Method.MakeGenericMethod(typeof (TDestination), typeof (bool), typeof (TSource)), expression); 30 }); 31 return 32 bulidMethod.Item1.Invoke(null, new object[] {selector, bulidMethod.Item2}) as 33 Expression<Func<TDestination, bool>>; 34 } 35 36 public static Expression<Func<TX, TY>> Compose<TX, TY, TZ>(this Expression<Func<TZ, TY>> outer, 37 Expression<Func<TX, TZ>> inner) 38 { 39 return Expression.Lambda<Func<TX, TY>>( 40 ParameterReplacer.Replace(outer.Body, outer.Parameters[0], inner.Body), 41 inner.Parameters[0]); 42 } 43 44 public static Expression<Predicate<TX>> ComposePredicate<TX, TZ>(this Expression<Predicate<TZ>> outer, 45 Expression<Func<TX, TZ>> inner) 46 { 47 return Expression.Lambda<Predicate<TX>>( 48 ParameterReplacer.Replace(outer.Body, outer.Parameters[0], inner.Body), 49 inner.Parameters[0]); 50 } 51 } 52 53 class ParameterReplacer : ExpressionVisitor 54 { 55 private readonly ParameterExpression _parameter; 56 private readonly Expression _replacement; 57 58 private ParameterReplacer(ParameterExpression parameter, Expression replacement) 59 { 60 _parameter = parameter; 61 _replacement = replacement; 62 } 63 64 public static Expression Replace(Expression expression, ParameterExpression parameter, Expression replacement) 65 { 66 return new ParameterReplacer(parameter, replacement).Visit(expression); 67 } 68 69 protected override Expression VisitParameter(ParameterExpression parameter) 70 { 71 if (parameter == _parameter) 72 { 73 return _replacement; 74 } 75 return base.VisitParameter(parameter); 76 } 77 } 78 }
测试
1 public class Entity 2 { 3 public string A { get; set; } 4 } 5 6 public class Dto 7 { 8 public string A { get; set; } 9 } 10 11 12 Mapper.CreateMap<Entity, Dto>(); 13 Mapper.CreateMap<Dto, Entity>(); 14 15 16 var list = new List<Dto>() 17 { 18 new Dto() {A = "A"}, 19 new Dto() {A = "B"}, 20 new Dto() {A = "C"}, 21 new Dto() {A = "D"}, 22 new Dto() {A = "E"}, 23 }; 24 25 //Predicate<Entity> fun = _ => _.A =="A"; 26 Expression<Func<Entity,bool>> funEntity = _ => _.A == "A"; 27 28 var query = list.Where(funEntity.MapExpression<Entity, Dto>().Compile()); 29 Assert.True(query.Count() == 1); 30 31 Expression<Func<Entity, bool>> funEntity2 = _ => _.A == "F"; 32 var query2 = list.Where(funEntity2.MapExpression<Entity, Dto>().Compile()); 33 Assert.True(query2.Count() == 0);