将Expression <func <tmodel,object =“”>&gt; []的数组转换为List <system.reflection.propertyinfo> </system.reflection.propertyinfo> </func <tmodel>的列表

时间:2014-10-03 00:48:19

标签: c# reflection lambda func system.reflection

是否可以转换params Expression<Func<TModel, object>>[] includeProperties

的数组

List<System.Reflection.PropertyInfo> propertiesInfo的数组?

如果是,请解释我该怎么做?

TModel是一个类

编辑:

我这个动作的目的是我可以只将一个对象的一些属性分配给另一个对象。 我实现这一目标的方法是:

public static void Assign(this object destination, object source,   List<System.Reflection.PropertyInfo> includeProperties)
    {
        if (destination is IEnumerable && source is IEnumerable)
        {
            var dest_enumerator = (destination as IEnumerable).GetEnumerator();
            var src_enumerator = (source as IEnumerable).GetEnumerator();
            while (dest_enumerator.MoveNext() && src_enumerator.MoveNext())
                dest_enumerator.Current.Assign(src_enumerator.Current);
        }
        else
        {
            //var destProperties = destination.GetType().GetProperties();
            foreach (var sourceProperty in source.GetType().GetProperties())
            {
                foreach (PropertyInfo destProperty in includeProperties)
                {
                    if (destProperty.Name == sourceProperty.Name && destProperty.PropertyType.IsAssignableFrom(sourceProperty.PropertyType))
                    {
                        destProperty.SetValue(destination, sourceProperty.GetValue(source, new object[] { }), new object[] { });
                        break;
                    }
                }
            }
        }
    }

另一种方法:

public virtual void Update(object viewModel, params Expression<Func<TModel, object>>[] includeProperties)
    {
        List<PropertyInfo> pList = new List<PropertyInfo>();
        foreach (var prop in includeProperties)
        {
            //Todo: I should convert prop to PropertyInfo and then add to pList 
        }
        using (new EFUnitOfWorkFactory().Create())
        {
            TModel model = new TModel();
            model.Assign(viewModel, pList);
            RepositoryContainer<TRepository>().Update(model);
        }
    }

1 个答案:

答案 0 :(得分:1)

我将其分解为两部分:

第1部分:从PropertyInfo中提取Expression<Func<T, object>>

public static class ExpressionUtil
{
    public static PropertyInfo Property<T>(Expression<Func<T, object>> expr)
    {
        var member = ExpressionUtil.Member(expr);
        var prop = member as PropertyInfo;

        if (prop == null)
        {
            throw new InvalidOperationException("Specified member is not a property.");
        }

        return prop;
    }

    public static MemberInfo Member<T>(Expression<Func<T, object>> expr)
    {
        // This is a tricky case because of the "object" return type.
        // An expression which targets a value type property will
        // have a UnaryExpression body, whereas an expression which
        // targets a reference type property will have a MemberExpression
        // (or, more specifically, PropertyExpression) Body.
        var unaryExpr = expr.Body as UnaryExpression;
        var memberExpr = (MemberExpression)(unaryExpr == null ? expr.Body : unaryExpr.Operand);

        return memberExpr.Member;
    }
}

第2部分:执行投射以获得List<PropertyInfo>

// includeProperties is Expression<Func<TModel, object>>[].
List<PropertyInfo> pList = includeProperties
    .Select(ExpressionUtil.Property)
    .ToList();

...或(将其插入现有代码):

List<PropertyInfo> pList = new List<PropertyInfo>();

foreach (var prop in includeProperties)
{
    PropertyInfo pi = ExpressionUtil.Property(prop);

    pList.Add(pi);
}

修改

好的,现在我们知道你的数组实际上包含不同表达式树的组合(那些目标值类型属性和那些目标引用类型属性)。以下将处理:

List<PropertyInfo> pList = new List<PropertyInfo>();

foreach (var prop in includeProperties)
{
    MemberExpression memberExpr = prop.Body as MemberExpression;

    if (memberExpr == null)
    {
        UnaryExpression unaryExpr = (UnaryExpression)prop.Body;

        memberExpr = (MemberExpression)unaryExpr.Operand;
    }

    PropertyInfo pi = (PropertyInfo)memberExpr.Member;

    pList.Add(pi);
}

我已调整ExpressionUtil.Member以便在您的情况下正常工作以及我最初为其编写的一般情况。

最后一句话

现在我已经列出了你可以做什么来使用BCL使事情有效我想指出映射实体的问题无处不在,并且有很多专门针对它的第三方工具 - 即AutoMapper(https://github.com/AutoMapper/AutoMapper/wiki/Getting-started)。