2017-02-14 1 views
2

Ich versuche, Reflektion zu verwenden, um eine Ansicht automatisch zu generieren. Html.DisplayFor und einige der anderen Helfer nehmen Expression<Func<,>>, die von LambdaExpression abgeleitet ist. Schien wie ich in der Lage sein würde, um manuell mein eigenes Lambda zu erzeugen und dann das in passieren, aber es ist diesen Fehler zu werfen:Kann ich einen LambdaExpression-Typ für MVCs HTML-Helfer verwenden?

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.`

Hier ist mein Markup:

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

ich mir ziemlich sicher bin, was ist passiert Das .DisplayFor erfordert generische Typ Argumente, um die Typen für Func<TModel, TValue> abzuleiten, aber ich verwende LambdaExpression, die die Typen versteckt.

Es scheint die einzige Möglichkeit zu tun, was ich will ist, einen Ausdruck zu erstellen/kompilieren, der tatsächlich .DisplayFor mit typsicheren Argumenten aufruft, aber das scheint übermäßig kompliziert.

Gibt es eine andere Möglichkeit, mein Ziel zu erreichen, oder wäre es besser, wenn ich die Ergebnisse direkt an den HTML-Code übermittele, anstatt die Helfer anzurufen?

Edit: Per Anfrage, hier ist der Code für 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

können Sie diese Methodenimplementierung zeigen? –

+0

@EhsanSajjad Aktualisiert – oscilatingcretin

Antwort

0

Es gibt eine andere Lösung dafür ist, dass ich zum ersten Mal empfehlen. Ändern Sie Ihre for-Schleife zu einem DisplayForModel Aufruf:

@Html.DisplayForModel() 

Das wird rendern alle Eigenschaften, mit DisplayFor intern. Sie können dies ändern, indem Sie den Ordner Object.cshtml im Ordner DisplayTemplates (entweder im Ordner Views, in dem Sie arbeiten, oder im Ordner Shared, der global angewendet werden soll) ändern.

Wenn das nicht ausreicht, oder Sie wirklich wirklich LambdaExpression verwenden möchten, hier ist eine Alternative. Dazu müssen Sie eine Erweiterungsmethode DisplayFor<TModel>(LambdaExpression expression) hinzufügen. Es wäre etwas wie (beachten Sie, dass ich das nicht tatsächlich getestet habe, aber das ist nahe, was benötigt wird):

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

Ihre zweite Lösung ist im Grunde, worauf ich zurückgreifen würde, aber mit Reflektion, um einen Delegaten zur Laufzeit mit Ausdrucksbäumen zu erzeugen. Ich glaube nicht, dass er zuerst in meinem Fall arbeiten wird, aber gut darüber zu wissen. – oscilatingcretin

+0

@oscilatingcretin Warum denkst du, dass das erste nicht funktioniert? –

Verwandte Themen