2017-02-14 7 views
2

Я пытаюсь использовать отражение для автоматического создания представления. Html.DisplayFor и некоторые другие помощники принимают Expression<Func<,>>, который берет начало с LambdaExpression. Казалось, я был бы в состоянии вручную сгенерировать свой собственный лямбда и затем передать, что, но это бросает эту ошибку:Могу ли я использовать тип LambdaExpression для HTML-помощников MVC?

The type arguments for method 'DisplayExtensions.DisplayFor<TModel, TValue>(HtmlHelper<TModel>, Expression<Func<TModel, TValue>>)' cannot be inferred from the usage. Try specifying the type arguments explicitly.`

Вот моя разметка:

<tr> 
    @foreach (var pi in Model.GetType().GetProperties()) 
    { 
     <td> 
      @Html.DisplayFor(ExpressionHelpers.GetPropertyGetterLambda(pi)) 
     </td> 
    } 
</tr> 

Я уверен, что происходит, что .DisplayFor требует общих аргументов типа для вывода типов для Func<TModel, TValue>, но я использую LambdaExpression, который скрывает типы.

Похоже, что единственный способ сделать то, что я хочу, - это построить/скомпилировать выражение, которое на самом деле вызывает .DisplayFor с использованием аргументов типа безопасности, но это кажется слишком сложным.

Есть ли другой способ достичь моей цели, или мне лучше было бы просто выводить результаты непосредственно на HTML, а не называть помощников?

Edit: По желанию, вот код для GetPropertyGetterLambda:

public static LambdaExpression GetPropertyGetterLambda(PropertyInfo pi, BindingTypeSafety TypeSafety) 
{ 
    if (pi.CanRead) 
    { 
     ParameterExpression entityParameter = Expression.Parameter(TypeSafety.HasFlag(BindingTypeSafety.TypeSafeEntity) ? 
      pi.ReflectedType : typeof(object)); 
     LambdaExpression lambda = Expression.Lambda(GetPropertyReadExpression(entityParameter, pi, TypeSafety), entityParameter); 
     return lambda; 
    } 
    else 
    { 
     return null; 
    } 
} 
+0

Можете ли вы показать, что реализация метода? –

+0

@EhsanSajjad Обновлено – oscilatingcretin

ответ

0

Существует еще одно решение для этого я рекомендую первый. Измените свой цикл на DisplayForModel вызова:

@Html.DisplayForModel() 

Это сделает все свойства, используя DisplayFor внутри. Вы можете изменить это, изменив Object.cshtml в папке DisplayTemplates (либо в папке Views, в которой вы работаете, либо в папке Shared для применения по всему миру).

Если этого недостаточно или вы действительно хотите использовать LambdaExpression, вот альтернатива. Это потребует добавления метода расширения DisplayFor<TModel>(LambdaExpression expression). Это было бы что-то вроде (обратите внимание, что я на самом деле не проверял это, но это близко к тому, что необходимо):

public static IHtmlString DisplayFor<TModel>(this HtmlHelper<TModel> helper, LambdaExpression expression) 
    { 
     var wrapperClass = typeof(DisplayExtensions); 
     ///find matching DisplayFor<TModel, TProperty> method 
     var matchingMethod = wrapperClass.GetMethods() 
      .Single(c => c.IsStatic 
       && c.Name == "DisplayFor" 
       && c.GetGenericArguments().Count() == 2 
       && c.GetParameters().Count() == 2 //overloads don't have same # of parameters. This should be sufficient. 
       ).MakeGenericMethod(typeof(TModel), expression.ReturnType); //Make generic type from the TModel and the Return Type 

     //invoke the method. The result is a IHtmlString already, so just cast. 
     return (IHtmlString) matchingMethod.Invoke(null, new Object[] { helper, expression }); 
    } 
+0

Ваше второе решение в основном состоит в том, что я собираюсь отступить, но используя отражение для создания делегата во время выполнения с деревьями выражений. Я не думаю, что он сначала будет работать в моем случае, но хорошо знать об этом. – oscilatingcretin

+0

@oscilatingcretin Почему, по-вашему, первое не сработает? –

Смежные вопросы