2017-11-11 9 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