2013-04-25 25 views
30

我想从属性的名称在运行时创建一个嵌套属性的lambda表达式。基本上我想创建由指定的lambda表达式:构建从字符串嵌套属性的LambdaExpression

var expression = CreateExpression<Foo, object>(foo => foo.myBar.name); 

private static Expression CreateExpression<TEntity, TReturn>(Expression<Func<TEntity, TReturn>> expression) 
{ 
    return (expression as Expression); 
} 

随着等级:

class Foo 
{ 
    public Bar myBar { get; set; } 
} 
class Bar 
{ 
    public string name { get; set; } 
} 

但是,所有我给出的的Foo类型和字符串"myBar.name"

如果是一个正常的属性,如只需要值"myBar"然后我可以使用以下内容:

private static LambdaExpression GetPropertyAccessLambda(Type type, string propertyName) 
{ 
    ParameterExpression odataItParameter = Expression.Parameter(type, "$it"); 
    MemberExpression propertyAccess = Expression.Property(odataItParameter, propertyName); 
    return Expression.Lambda(propertyAccess, odataItParameter); 
} 

但是,此代码不适用于嵌套属性,我不确定如何创建LambdaExpression来执行foo.myBar.name的工作。

我认为这将是这样的:

GetExpression(Expression.Call(GetExpression(Foo, "myBar"), "name")) 

但我似乎无法工作,如何把一切工作,或是否有更好的方式在运行时要做到这一点。

回答

62

你的意思是:

static LambdaExpression CreateExpression(Type type, string propertyName) { 
    var param = Expression.Parameter(type, "x"); 
    Expression body = param; 
    foreach (var member in propertyName.Split('.')) { 
     body = Expression.PropertyOrField(body, member); 
    } 
    return Expression.Lambda(body, param); 
} 

例如:

class Foo { 
    public Bar myBar { get; set; } 
} 
class Bar { 
    public string name { get; set; } 
} 
static void Main() { 
    var expression = CreateExpression(typeof(Foo), "myBar.name"); 
    // x => x.myBar.name 
} 

+0

是的,这正是我正在寻找的,我的错误是认为我需要在获取嵌套属性之前调用正文表达式(使用'Call')。 – Seph 2013-04-25 08:38:01

+0

很好的答案! +1为清晰 – ps2goat 2014-06-20 22:13:13

+0

来自Marc Gravell为我解决了它的梦幻般的答案。作为奖励,resharper这样做了你的代码: var param = Expression.Parameter(type,“x”); Expression body = propertyName.Split('。')。Aggregate (param,Expression.PropertyOrField); return Expression.Lambda(body,param); – 2015-06-18 12:22:11