2010-06-23 42 views
1

我正在'泛化'.NET 3.5 MVC應用程序中的一些代碼,並且偶然發現了一個問題。如何傳遞一個委託來創建一個表達式樹,這是一個MethodCallExpression

背景

我有一個SomeController類的一些行動:

public ActionResult Renew(string qualification, int tierId) { ... } 
public ActionResult Reinstate(string qualification, int tierId) { ... } 
public ActionResult Withdraw(string qualification, int tierId) { ... } 

在我使用的是強類型的擴展輔助方法來創建一個ActionLink的視圖(這個通用的方法來自Microsoft.Web.Mvc.dll)。樣的用途是

Html.ActionLink<SomeController>(c=>c.Renew(Model.Qualification, Model.TierId),"Renew") 

只有我有一個定義的方法調用的表達式的視圖屬性,所以我可以這樣做:

Html.ActionLink(Model.Action,"Renew") 

在視圖模型的Action屬性具有以下簽名

public Expression<Action<SomeController>> Action { get; set; } 

當我在一個控制器動作我可以使用下面的代碼創建視圖:

model.Action = c => c.Renew(dto.Qualification.Name, t.Id) 

方法

到目前爲止好,所有的強類型的工作很好,但這是我的問題開始的地方。我希望能夠用傳入組裝視圖模型的方法的參數替換對c => c.Renew(dto.Qualification.Name, t.Id)的顯式調用。

我希望執行以下操作:

private SomeViewModel CreateViewModel(SomeDto dto, Tier t, Func<string, int, ActionResult>> actionToCall) { 
    return new SomeViewModel { 
    ... 
    Action = a => actionToCall(dto.Qualification.Name, t.Id), 
    } 
} 

,然後使用此方法來構建模型,並通過適當的控制器的動作作爲一個參數

var model = CreateViewModel(dto,tier,this.Reinstate) 

問題

該解決方案編譯,但是當我開始渲染ActionLink時,我得到一個期望,因爲表達式傳入作爲動作不是MethodCallExpression類型。該異常由View中的Html.ActionLink擴展方法拋出。

回答

2

我想你想讓CreateViewModel接受表達式樹而不是委託。 ActionLink似乎認爲它獲得了一個表達式樹,它是一個lambda表達式,其正文是參數上的一個方法調用。如果您對在以CreateViewModel通過表達相同的假設,你可以拉出來的MethodInfo對象,並通過做這樣的事情手動構建表達式樹:

private SomeViewModel CreateViewModel(SomeDto dto, Tier t, 
    Expression<Func<string, int, ActionResult>> actionToCall) 
{ 
    var methodCallExpression = (MethodCallExpression)actionToCall.Body; 
    var param = Expression.Parameter(typeof(SomeController), null); 
    return new SomeViewModel() 
    { 
     Action = 
      Expression.Lambda<Action<SomeController>>(
       Expression.Call(
        param, 
        methodCallExpression.Method, 
        Expression.Constant(dto.Qualification.Name), 
        Expression.Constant(t.Id)), 
       param) 
    }; 
} 
+0

謝謝。我會放棄它。 你能不能通過參數建立一個表達式樹? – mfloryan 2010-06-23 14:14:01

+0

@mfloryan:您當然可以構建一個調用作爲參數傳入的委託的表達式樹,但表達式樹將具有引用該參數的InvocationExpression。這聽起來像ActionLink期待一個MethodCallExpression。 – Quartermeister 2010-06-25 13:26:23

0

這個幫助器的工作方式是試圖確定基於lambda表達式的URL,它應該始終是控制器上的一個方法調用。這樣它就知道傳遞的動作名稱和參數。如果lambda表達式不再是MethodCallExpression,則無法確定URL。

+0

是的,我明白了。我的問題是如何獲得正確的lambda表達式(或者是否可以基於傳入的參數創建) – mfloryan 2010-06-23 14:12:25

相關問題