Itération sur les propriétés d'une expression lambda

.net c# expression-trees lambda

Question

J'essaie de générer un contrôle complexe qui est utilisé fréquemment dans mon site Web, mais avec des champs différents. La fonctionnalité dans le contrôle est toujours la même, ce sont juste les champs sous-jacents qui changent.

Pour obtenir la méthode d'affichage de différents champs, je tente de créer une extension HTMLHelper qui accepte un paramètre Expression<Func<TModel,TProperty>> , qui contiendrait les propriétés d'une classe requise pour l'affichage dans le contrôle. Par exemple:

La vue:

@model Project.Core.Page
@Html.MyHelper(p => new { p.Author.Name, p.Author.Location, p.Author.Age });

C'est l'extension avec laquelle j'ai des problèmes - comment puis-je parcourir les paramètres fournis dans le lambda pour fournir à chacun un TextBoxFor() , ou même créer manuellement un élément d' input et le renseigner avec la value et le name du paramètre lambda?

L'extension in psuedo:

@model Project.Core.Page
@Html.MyHelper(p => new { p.Author.Name, p.Author.Location, p.Author.Age });

Je sens que je regarde ça depuis trop longtemps, et j’ai aussi l’impression que je ne parviens pas à y parvenir plus facilement.

Toute aide est grandement appréciée. Si vous avez besoin de plus amples détails ou si j'ai oublié quelque chose d'important, faites-le moi savoir.

Réponse acceptée

Si vous supposez ce qui suit:

  1. Le résultat de l'expression d'entrée est une projection (retourne un nouvel objet, anonyme ou non).
  2. Les éléments de la projection sont tous MemberExpressions et ne contiennent pas d'appel à une méthode sur le modèle ou ses enfants.

Ensuite, vous pouvez réaliser ce que vous voulez en utilisant l’approche suivante:

Modifier:

Après avoir réalisé que mon premier exemple ne pouvait pas gérer les objets dotés de propriétés complexes, j'ai mis à jour le code afin d'utiliser une méthode d'assistance pour accéder aux valeurs de propriété. Cette méthode parcourt la chaîne de propriétés en utilisant la récursivité pour renvoyer les valeurs appropriées.

public static MvcHtmlString MyHelper<TModel,object>(
    this HtmlHelper<TModel> helper, 
    Expression<Func<TModel,object>> expression) {

        var newExpression = expression.Body as NewExpression;
        TModel model = helper.ViewData.Model;

        foreach (MemberExpression a in newExpression.Arguments) {

            var propertyName = a.Member.Name;
            var propertyValue = GetPropertyValue<TModel>(model, a);

            // Do whatever you need to with the property name and value;

        }

    }

    private static object GetPropertyValue<T>(T instance, MemberExpression me) {

        object target;

        if (me.Expression.NodeType == ExpressionType.Parameter) {
            // If the current MemberExpression is at the root object, set that as the target.            
            target = instance;
        }
        else {                
            target = GetPropertyValue<T>(instance, me.Expression as MemberExpression);
        }

        // Return the value from current MemberExpression against the current target
        return target.GetType().GetProperty(me.Member.Name).GetValue(target, null);

    }

Remarque: je n’ai pas directement implémenté cela en tant que méthode d’extension MVC dans mon IDE; une légère variation de la syntaxe peut donc être requise.


Réponse populaire

L'expression que vous aurez créée sera relativement compliquée - il faudra extraire toutes les propriétés, puis appeler le constructeur de type anonyme. "Désassembler" peut devenir pénible ... bien que si vous voulez toujours essayer, je suggérerais de laisser une implémentation de méthode vide et de regarder dans le débogueur pour voir à quoi ressemble l'expression.

Si vous préférez une forme de code d’appel un peu plus laide, il serait beaucoup plus simple d’implémenter ceci:

@Html.MyHelper(p => p.Author.Name, p => p.Author.Location, p => p.Author.Age);

Vous pouvez faire que cela prenne un params Expression<TModel, object> ou vous pouvez déclarer plusieurs surcharges avec différents nombres de paramètres, par exemple

@Html.MyHelper(p => p.Author.Name, p => p.Author.Location, p => p.Author.Age);

etc.




Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi