2012-06-22 1 views
0

동적으로 다음 1 (재귀 적으로) 더 깊은 수준에 MemberAcess 표현 만들 싶습니다

public class Job 
{ 
    public string Name { get; set; } 
    public int Salary { get; set; } 
} 
public class Employee 
{ 
    public string Name { get; set; } 
    public Job Job { get; set; } 
} 

을 그리고 동적으로 각 MemberAccesExpressions의 목록을 만들려면

: 이것은 내가 가진 무엇 의사 코드가

MemberAccesExpression[] { 
    { e => e.Name }, 
    { e => e.Job.Name }, 
    { e => e.Job.Name } 
} 

: 직원의 재산과 직원의 복잡한 회원의 각 속성은, 결과는 다음과 같이해야한다

어떻게 이것을 재귀 적 방법으로 만들 수 있습니까? (TModel 모델, Expression> baseMemberAccess = null) 이라는 선택적 매개 변수를 추가하고 null이 아닌 경우 멤버 식을 baseMemberAccess에 연결하는 방법을 생각했습니다.

P. Type이 원자 유형이 아닌지 확인하는 더 좋은 방법이 있습니다. (prop.PropertyType.Namespace! = "System") ? 내가 표현을 만들려면

: 더 간단하게 누워 노력에 대한 아담

에게,

어떤 도움을 주셔서 감사 편집 결과 (..., 플로트, 문자열 등을 int로하지 않음)

 var param = Expression.Parameter(type, "x"); 
     var memberAccess = Expression.PropertyOrField(param, memberName); 
     return Expression.Lambda<Func<TModel, TMember>>(memberAccess, param); 

Employee.Job.Salary에 멤버 액세스이에 상응하는 무엇입니까 :이 Employee.Name하는 멤버 액세스의 나무는 내가 무엇인가?

+0

[XY 문제]를 감지합니다 (http://meta.stackexchange.com/a/66378/168269). 코드로 어떤 문제를 해결하고 싶습니까? –

+0

나는 그것이 명확하지 않다고 생각하지는 않지만 질문을 편집하고 끝 부분에 정확한 문제를 추가했습니다. –

+0

그는 더 큰 문제를 해결하려고 무엇을 요구하고 있습니까? 왜 객체의 모든 멤버 표현식을 수집하려고합니까? –

답변

2
public IEnumerable<Expression<Func<TModel, dynamic>>> CreateME<TModel>() 
    { 
     var stack = new Stack<StackItem>(); 
     var type = typeof(TModel); 
     var parameterExpression = Expression.Parameter(type, "x"); 
     stack.Push(new StackItem(typeof(TModel), parameterExpression)); 

     while (stack.Count > 0) 
     { 
      var currentItem = stack.Pop(); 
      var properties = currentItem.PropertyType.GetProperties(); 
      foreach (var property in properties) 
      { 
       if (IsComplexProperty(property)) 
        stack.Push(new StackItem(property.PropertyType, Expression.PropertyOrField(currentItem.AccessChainExpression, property.Name))); 
       else 
       { 
        yield return GetSimplePropertyExpression<TModel>(parameterExpression, currentItem.AccessChainExpression, property.Name); 
       } 
      } 
     } 


    } 

    private static Expression<Func<TModel, dynamic>> GetSimplePropertyExpression<TModel>(ParameterExpression lhs, Expression accessChain, string propertyName) 
    { 
     var memberAccess = Expression.Convert(Expression.PropertyOrField(accessChain, propertyName), typeof(object)); 
     return Expression.Lambda<Func<TModel, dynamic>>(memberAccess, lhs); 
    } 

    private static bool IsComplexProperty(PropertyInfo p) 
    { 
     return !typeof (ICollection).IsAssignableFrom(p.PropertyType) && p.PropertyType.Namespace != "System"; 
    } 


    class StackItem 
    { 
     public StackItem(Type propertyType, Expression accessChainExpression) 
     { 
      PropertyType = propertyType; 
      AccessChainExpression = accessChainExpression; 
     } 

     public Type PropertyType { get; private set; } 
     public Expression AccessChainExpression { get; private set; } 
    } 

확실하지만 개선 될 수 있습니다.

+0

이 두 가지가 작동하지 않거나 사용 방법을 모르는 것 같습니다. 이 줄에서 - Expression.Convert (Expression.PropertyOrField (accessChain, propertyName), typeof (object)); 이 예외가 발생했습니다 - " 'memberName'이 (가) 'System.Func'2 [TModel, System.Object]'유형의 멤버가 아닙니다." –

+0

예제 개체에 대해서만 테스트 했으므로 실제 클래스 정의를 게시 할 수 있습니다. TModel에 사용하고 있습니다. –

+0

실제 TModel에 Func의 속성이 있습니까? –