代码之家  ›  专栏  ›  技术社区  ›  AliReza Sabouri

使用反射和表达式的自动列映射

  •  2
  • AliReza Sabouri  · 技术社区  · 7 年前

    这有可能通过反射自动化这些映射吗?

    我有一个简单的列映射:

    var columnsMap = new Dictionary<string, Expression<Func<Industry, object>>>
    {
        ["id"] = v => v.Id,
        ["name"] = v => v.Name,
        ["isActive"] = v => v.IsActive
    };
    

    columnsMap运行时结果:

    enter image description here


    我想在包装类中自动化这些映射:

     public class QueryColumnMapper<T> : Dictionary<string, Expression<Func<T, object>>>
        {
            public QueryColumnMapper<T> GenerateMappings()
            {
                foreach (var item in typeof(T).GetProperties())
                {
                    // get dictionary key ======> its OK
                    var name = Char.ToLowerInvariant(item.Name[0]) + item.Name.Substring(1); //camel-case name
    
                    // get expression    =======> this is the problem. wrong way
                    Expression<Func<T, object>> exp = v => v.GetType().GetProperty(item.Name);
                    //Expression<Func<T, object>> exp = v => v.?????;    <-----   
    
                    // add to mapper object
                    this.Add(name, exp);
                }
                return this;
            }
        }
    

    使用此类的示例:

    var columnsMap = new QueryColumnMapper<Industry>().GenerateMappings();  
    

    columnsMap运行时结果: enter image description here

    我不知道是否可以在运行时动态获取我的表达式?

    (我正在使用此映射字典对实体框架应用筛选 IQueryable 查询。在第一个例子中(手动映射),它可以工作,但是我不知道如何在没有手动映射的情况下在运行时做到这一点)

    2 回复  |  直到 7 年前
        1
  •  2
  •   johnny 5    7 年前

    可以使用属性名手动生成自定义表达式

    // x =>
    var parameter = Expression.Parameter(typeof(T));
    // x.Name
    var mapProperty = Expression.Property(parameter, "Name");
    // (object)x.Name
    var convertedExpression = Expression.Convert(mapProperty, typeof(object));
    // x => (object)x.Name
    var exp = Expression.Lambda<Func<T, object>>(convertedExpression, parameter);
    

    如果这是一个公共子集,并且您发现您经常这样做,那么您可以创建一个基本接口。

        2
  •  2
  •   AliReza Sabouri    7 年前

    对于其他观众,我分享了最终代码:

     public class QueryColumnMapper<T> 
    {
        public QueryColumnMapper()
        {
            Mappings = new Dictionary<string, Expression<Func<T, object>>>();
        }
        public Dictionary<string, Expression<Func<T, object>>> Mappings { get; set; }
        public Dictionary<string, Expression<Func<T, object>>> GenerateMappings()
        {
            foreach (var item in typeof(T).GetProperties())
            {
                var name = Char.ToLowerInvariant(item.Name[0]) + item.Name.Substring(1); //camel-case name
    
                // add to mapper object
                Mappings.Add(name, GetExpression(item.Name));
            }
            return Mappings;
        }
    
        private Expression<Func<T,object>> GetExpression(string propertyName)
        {
            // x =>
            var parameter = Expression.Parameter(typeof(T));
            // x.Name
            var mapProperty = Expression.Property(parameter, propertyName);
            // (object)x.Name
            var convertedExpression = Expression.Convert(mapProperty, typeof(object));
            // x => (object)x.Name
            return Expression.Lambda<Func<T, object>>(convertedExpression, parameter);
        }
    }
    

    用法:

    var columnsMap = new QueryColumnMapper<Industry>().GenerateMappings();