表达式和自动映射器

时间:2017-10-14 17:16:56

标签: c# reflection

在互联网的某个地方,我发现下面的课程用于将Expression<Func<T, bool>>从DTO转换为域名:

public class EvaluateVariableVisitor<TEntity, TDto> : ExpressionVisitor
{
    private readonly ParameterExpression _dtoParameter;
    private readonly ParameterExpression _entityParameter;
    private readonly IMapper _mapper;

    public EvaluateVariableVisitor()
    {
        _entityParameter = Expression.Parameter(typeof(TEntity));
        _dtoParameter = Expression.Parameter(typeof(TDto));
        _mapper = AutoMapperConfig.Initialize();
    }

    protected override Expression VisitMember(MemberExpression node)
    {
        try
        {
            //change dto to entity type.
            if (node.Expression.Type == _dtoParameter.Type)
            {
                var reducedExpression = Visit(node.Expression);

                //TypeMap typeMap = Mapper.Configuration.FindTypeMapFor<TDto, TEntity>();
                TypeMap typeMap = _mapper.ConfigurationProvider.FindTypeMapFor<TDto, TEntity>();

                //find the correct name of the property in the destination object by using the name of the source objekt
                string destinationPropertyName = typeMap.GetPropertyMaps() //GetCustomPropertyMaps()
                                                        .Where(propertyMap => propertyMap.SourceMember.Name == node.Member.Name)
                                                        .Select(propertyMap => propertyMap.DestinationProperty.Name).FirstOrDefault();


                //find the correct name of the property in the destination object by using the name of the source objekt
                //string destinationPropertyName = typeMap.GetPropertyMaps() //GetCustomPropertyMaps()
                //                                        .Where(propertyMap => propertyMap.SourceMember.Name == node.Member.Name)
                //                                        .Select(propertyMap => propertyMap.DestinationProperty.Name).Single();

                var newMember = _entityParameter.Type.GetMember(destinationPropertyName).First();

                return Expression.MakeMemberAccess(reducedExpression, newMember);
            }

            //Recurse down to see if we can simplify...
            var expression = Visit(node.Expression);

            //If we've ended up with a constant, and it's a property or a field,
            //we can simplify ourselves to a constant
            var constantExpression = expression as ConstantExpression;
            if (constantExpression != null)
            {
                object container = constantExpression.Value;
                object value = null;

                var memberAsFieldInfo = node.Member as FieldInfo;
                var memberAsPropertyInfo = node.Member as PropertyInfo;

                if (memberAsFieldInfo != null)
                {
                    value = memberAsFieldInfo.GetValue(container);
                }

                if (memberAsPropertyInfo != null)
                {
                    value = memberAsPropertyInfo.GetValue(container, null);
                }

                if (value != null)
                {
                    return Expression.Constant(value);
                }
            }

            return base.VisitMember(node);
        }
        catch (System.Exception exc)
        {
            var ex = exc.Message;
            throw;
        }
    }

    //change type from dto to entity --> otherwise the generated expression tree would throw an exception, because of missmatching types(Dto can't be used in Entity expression).
    protected override Expression VisitParameter(ParameterExpression node)
    {
        return node.Type == _dtoParameter.Type ? _entityParameter : node;
    }
}

它工作得很好,但是当我在DTO中拥有相同类型的属性时,我遇到了一个问题:

  public class InventoryApplicationDto
  {
      public int Id { get; set; }
      public string Name{ get; set; }
      public InventoryApplicationDto ParentApplication { get; set; }    
  }

首先,我必须改变:

string destinationPropertyName = typeMap.GetPropertyMaps() 
    .Where(propertyMap => propertyMap.SourceMember.Name == node.Member.Name)
    .Select(propertyMap => propertyMap.DestinationProperty.Name).Single();

要:

string destinationPropertyName = typeMap.GetPropertyMaps() 
    .Where(propertyMap => propertyMap.SourceMember.Name == node.Member.Name)
    .Select(propertyMap => propertyMap.DestinationProperty.Name).FirstOrDefault();

我的问题是我收到错误:

  

System.ArgumentException:未为类型定义属性“Int32 ID”   'InventoryApplicationDto'

在线:

return Expression.MakeMemberAccess(reducedExpression, newMember);

MakeMemberAccess方法区分大小写还是存在其他问题?

0 个答案:

没有答案