我试图创建一个函数,我可以传入一个表达式来说明我感兴趣的属性。我让它适用于顶级属性但不适用于嵌套属性。
示例模型
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?
我正在寻找一种从复杂对象中挑选任何属性的方法。
答案 0 :(得分: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;
}