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

 

改造一下支持泛型,代码如下:

 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);
        }
    }

 

 

测试

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);

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。