2014-10-03 2 views
0

Это можно преобразовать массив params Expression<Func<TModel, object>>[] includePropertiesПреобразование массива Expression <Func <TModel, объект >> [] в список List <System.Reflection.PropertyInfo>

в массив List<System.Reflection.PropertyInfo> propertiesInfo?

Если да, объясните, как я могу это сделать?

TModel представляет собой класс

EDITED:

Моя цель этого действия в том, что я могу назначить только некоторые свойства объекта к другому объекту. Мой метод для этой цели:

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

Я не понимаю: как вы ожидаете получить свойство из 'Func '? возвращает ли функция значение свойства? – Blorgbeard

ответ

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

EDIT

Итак, теперь мы знаем, что ваш массив на самом деле содержит сочетание различных деревьев выражений (те, которые нацелены на свойства типа значения, и те, которые нацелены на свойства ссылочного типа). Ниже будет обрабатывать как:

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

+0

я получил исключение в член (Expression > выражение) Дополнительная информация: Не удается привести объект типа «System.Linq.Expressions.PropertyExpression» к типу «System.Linq.Expressions.UnaryExpression». Одним из моих параметров является m => m.Title, что Title является строкой. – Jahan

+0

Большое спасибо за ваши попытки, но все же есть проблема. , если мой параметр равен m => m.Id или m => m.IsActive, что Id является int и IsActive является bool, я сталкиваюсь с исключением ..... Дополнительная информация: Невозможно наложить объект типа «System.Linq.Expressions.UnaryExpression» на тип «System.Linq.Expressions.MemberExpression» , – Jahan

+1

@Jahan, см. Мое последнее редактирование (я изменил «ExpressionUtil.Member » и простой пример в разделе * edit * для обработки унарных, а также не унарных выражений). Поскольку это * все * приведенные выше примеры кода должны работать на вас. Если они не угождают, дайте мне знать, и я буду исследовать дальше. –