2013-04-25 13 views
30

Próbuję utworzyć wyrażenie lambda dla zagnieżdżonej właściwości w czasie wykonywania z nazwy właściwości. Zasadniczo próbuję utworzyć wyrażenia lambda podanej przez:Skonstruuj wyrażenie lambdy dla właściwości zagnieżdżonej ze stringa

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

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

z klasami:

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

Jednak wszystko mam podane jest typem Foo a łańcuch "myBar.name"

Jeśli były normalną właściwością, taką jak potrzebująca wartości "myBar", a następnie mogłem użyć następującego:

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); 
} 

Jednak ten kod nie działa dla zagnieżdżonych właściwości i nie jestem pewien jak utworzyć LambdaExpression, aby wykonać pracę z foo.myBar.name.

Myślę, że to będzie coś takiego:

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

Ale nie wydaje się wypracować jak dostać to wszystko działa, lub jeśli istnieje lepszy sposób to zrobić w czasie wykonywania .

Odpowiedz

62

Czy chodziło Ci o:

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); 
} 

Na przykład:

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

Tak, dokładnie to, czego szukałem, moim błędem było myślenie, że muszę wywołać wyrażenie ciała (używając "Call") przed uzyskaniem zagnieżdżonej własności. – Seph

+0

Świetna odpowiedź! +1 dla jasności – ps2goat

+0

Fantastyczna odpowiedź od Marca Gravella, która rozwiązała to dla mnie. Jako bonus, resharper zrobił to na swój kod: var param = Expression.Parameter (type, "x"); Wyrażenie body = propertyName.Split ('.') Aggregate (param, Expression.PropertyOrField); return Express.Lambda (body, param); –