2012-03-19 50 views
4

我有一個Expression,用於從我的視圖中獲取我的Model中的項目列表。 我想要做什麼,ListExpression,我可以在Expression Tree的一個級別上向後走以獲得父節點嗎?從表達式獲取父成員

比方說,這是我的視圖模型:

public class MyModel { 
    public MyClass myClass { get; set;} 
} 

...

public class MyClass { 
    public List<string> MyList { get; set;} 
} 

我有一個HtmlHelper,它接受一個Expression如下渲染列表頁面:

public static MvcHtmlString RenderList(this HtmlHelper<TModel> html, Expression<Func<TModel, IEnumerable<TItem>>> dataExpression) 
{ 
    var list = dataExpression.Compile()(html.ViewData.Model); 

    ... 

    return MvcHtmlString.Create(...); 
} 

我打電話給我的幫手如下:

@model MyNamespace.Models.MyModel 
@Html.RenderList(m => m.myClass.MyList) 

這一切工作正常,我的問題是,我可以把給定Expression它指向List<string>並獲得它的父節點(MyClass),然後編譯它反對我Model得到它的價值。因此,這Expression相當於:

m => m.myClass 

這是我曾嘗試:

// This gets the correct expression 
var exp = ((MemberExpression)this._dataExpression.Body).Expression; 
// Create a parameter representing the type of the Model ? 
var parameter = Expression.Parameter(typeof(TModel)); 
// Create lambda 
var lambda = Expression.Lambda<Func<TModel, dynamic>>(exp, parameter); 
// Try and compile against the view model 
var obj = lambda.Compile()(html.ViewData.Model); 

回答

4

下面應該工作:

public static IHtmlString RenderList<TModel, TItem>(
    this HtmlHelper<TModel> html, 
    Expression<Func<TModel, IEnumerable<TItem>>> dataExpression 
) 
{ 
    var parentEx = ((MemberExpression)dataExpression.Body).Expression; 
    var lambda = Expression.Lambda<Func<TModel, object>>(parentEx, dataExpression.Parameters[0]); 
    var value = ModelMetadata.FromLambdaExpression(lambda, html.ViewData).Model; 

    ... 
} 

很顯然,你應該添加一個最小誤差的檢查,這爲了簡潔起見,我在此故意省略代碼。

+0

謝謝你,非常完美。 – Gabe 2012-03-19 20:38:16

1

你必須使用相同的參數表達在新的lambda表達式:

var lambda = Expression.Lambda<Func<MyModel, dynamic>>(exp, 
    this._dataExpression.Parameters);