Как передать делегата для создания дерева выражений, которое является MethodCallExpression

Я надеюсь 'обобщать' некоторый код в.NET 3.5 приложения MVC и споткнулся в проблему.

Фон

У меня есть класс 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 ввести. Это исключение выдается HTML. Метод расширения ActionLink от Представления.

1
задан mfloryan 23 June 2010 в 10:45
поделиться

2 ответа

Я думаю, вы хотите, чтобы CreateViewModel принимал выражение дерево, а не делегат. ActionLink, кажется, предполагает, что ему передается дерево выражения, которое является лямбда-выражением, тело которого является вызовом метода для параметра. Если вы сделаете такое же предположение относительно выражения, переданного в 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)
    };
}
2
ответ дан 2 September 2019 в 23:34
поделиться

Способ работы этого помощника заключается в том, что он пытается определить URL на основе лямбда-выражения, которое всегда должно быть вызовом метода в контроллере. Таким образом, он знает имя действия и переданные параметры. Если лямбда-выражение больше не является MethodCallExpression, то определить URL невозможно.

0
ответ дан 2 September 2019 в 23:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: