2013-04-25 41 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