2013-04-25 15 views
30

Tôi đang cố tạo biểu thức lambda cho thuộc tính lồng nhau tại thời gian chạy từ tên của đúng. Về cơ bản tôi đang cố gắng để tạo ra các biểu thức lambda được xác định bởi:Xây dựng LambdaExpression cho thuộc tính lồng nhau từ chuỗi

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

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

Với các lớp:

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

Tuy nhiên tất cả Tôi nhất định là loại Foo và chuỗi "myBar.name"

Nếu nó là một tài sản bình thường như chỉ cần giá trị "myBar" thì tôi có thể sử dụng như sau:

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

Tuy nhiên mã này không hoạt động đối với thuộc tính lồng nhau và tôi không chắc chắn cách tạo LambdaExpression để thực hiện công việc của foo.myBar.name.

Tôi nghĩ rằng nó sẽ là một cái gì đó như thế này:

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

Nhưng tôi dường như không thể làm việc ra làm thế nào để có được nó tất cả làm việc, hoặc nếu có một cách tốt hơn để làm điều này ở thời gian chạy .

Trả lời

62

Bạn có nghĩa là:

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

Ví dụ:

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

Đúng đó là chính xác những gì tôi đang tìm kiếm, sai lầm của tôi đã nghĩ rằng tôi cần phải gọi biểu thức cơ thể (sử dụng 'Gọi') trước khi nhận được thuộc tính lồng nhau. – Seph

+0

Câu trả lời hay! 1 cho rõ ràng – ps2goat

+0

câu trả lời tuyệt vời từ Marc Gravell mà giải quyết nó cho tôi. Như một phần thưởng, resharper đã làm điều này với mã của bạn: var param = Expression.Parameter (type, "x"); Biểu thức body = propertyName.Split ('.'). Tổng hợp (param, Expression.PropertyOrField); trả về Expression.Lambda (body, param); –