2017-11-11 164 views
1

我试图创建一个函数,我可以在表达式中传递我感兴趣的属性。我让它为顶级属性工作,但不适用于嵌套属性。通过表达式检索嵌套的PropertyInfo

例模型

public class Foo { 
    public string Name { get; set; } 
    public List<Foo> List { get; set; } 
} 

我有什么到目前为止

private PropertyInfo GetPropertyInfo<TModel>(Expression<Func<TModel, object>> selector) 
    { 
     if (selector.NodeType != ExpressionType.Lambda) 
     { 
      throw new ArgumentException("Selector must be lambda expression", nameof(selector)); 
     } 

     var lambda = (LambdaExpression)selector; 

     var memberExpression = ExtractMemberExpression(lambda.Body); 
     if (memberExpression == null) 
      throw new ArgumentException("Selector must be member access expression", nameof(selector)); 

     if (memberExpression.Member.DeclaringType == null) 
     { 
      throw new InvalidOperationException("Property does not have declaring type"); 
     } 

     return memberExpression.Member.DeclaringType.GetProperty(memberExpression.Member.Name); 
    } 

    private static MemberExpression ExtractMemberExpression(Expression expression) 
    { 
     if (expression.NodeType == ExpressionType.MemberAccess) 
     { 
      return ((MemberExpression)expression); 
     } 

     if (expression.NodeType == ExpressionType.Convert) 
     { 
      var operand = ((UnaryExpression)expression).Operand; 
      return ExtractMemberExpression(operand); 
     } 

     return null; 
    } 

所以:

GetPropertyInfo<Foo>(x => x.Name); // works 
GetPropertyInfo<Foo>(x => x.List.Select(y => y.Name); <-- how do I get this? 

我正在寻找一种方法可以选择任何财产从一个复杂的对象。

回答

2

您需要扩展ExtractMemberExpression只是有点接受Select调用表达式:

private MemberExpression ExtractMemberExpression(Expression expression) { 
    if (expression.NodeType == ExpressionType.MemberAccess) { 
     return ((MemberExpression) expression); 
    } 

    if (expression.NodeType == ExpressionType.Convert) { 
     var operand = ((UnaryExpression) expression).Operand; 
     return ExtractMemberExpression(operand); 
    } 
    if (expression.NodeType == ExpressionType.Lambda) {    
     return ExtractMemberExpression(((LambdaExpression) expression).Body); 
    } 

    if (expression.NodeType == ExpressionType.Call) { 
     var call = (MethodCallExpression) expression; 
     // any method named Select with 2 parameters will do 
     if (call.Method.Name == "Select" && call.Arguments.Count == 2) { 
      return ExtractMemberExpression(call.Arguments[1]); 
     } 
    } 

    return null; 
} 
+0

真棒,谢谢 – Magpie