Ajouter une propriété au type anonyme après la création

101

J'utilise un objet anonyme pour transmettre mes attributs Html à certaines méthodes d'assistance. Si le consommateur n'a pas ajouté d'attribut ID, je souhaite l'ajouter dans ma méthode d'assistance.

Comment puis-je ajouter un attribut à cet objet anonyme?

Boris Callens
la source

Réponses:

17

Si vous essayez d'étendre cette méthode:

public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, object routeValues);

Bien que je sois sûr que les extensions d'objets de Khaja fonctionneraient, vous pourriez obtenir de meilleures performances en créant un RouteValueDictionary et en passant l'objet routeValues, ajoutez vos paramètres supplémentaires à partir du contexte, puis revenez en utilisant la surcharge ActionLink qui prend un RouteValueDictionary au lieu d'un objet:

Cela devrait faire l'affaire:

    public static MvcHtmlString MyLink(this HtmlHelper helper, string linkText, string actionName, object routeValues)
    {
        RouteValueDictionary routeValueDictionary = new RouteValueDictionary(routeValues);

        // Add more parameters
        foreach (string parameter in helper.ViewContext.RequestContext.HttpContext.Request.QueryString.AllKeys)
        {
            routeValueDictionary.Add(parameter, helper.ViewContext.RequestContext.HttpContext.Request.QueryString[parameter]);
        }

        return helper.ActionLink(linkText, actionName, routeValueDictionary);
    }
Levitikon
la source
Fonctionne comme un charme, cela devrait être la réponse acceptée! BTW: Si vous utilisez les surcharges d'objets d'ActionLink () jusqu'à présent, vous devez encapsuler htmlAttributes avec HtmlHelper.AnonymousObjectToHtmlAttributes (htmlAttributes) afin d'appeler la surcharge correcte!
DR
79

La classe d'extension suivante vous fournira ce dont vous avez besoin.

public static class ObjectExtensions
{
    public static IDictionary<string, object> AddProperty(this object obj, string name, object value)
    {
        var dictionary = obj.ToDictionary();
        dictionary.Add(name, value);
        return dictionary;
    }

    // helper
    public static IDictionary<string, object> ToDictionary(this object obj)
    {
        IDictionary<string, object> result = new Dictionary<string, object>();
        PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(obj);
        foreach (PropertyDescriptor property in properties){
            result.Add(property.Name, property.GetValue(obj));
        }
        return result;
    }
}
Khaja Minhajuddin
la source
4
100% correct. Même si généralement vous utilisez des types anonymes pour les attributs Html, il s'agit en fait d'un IDictionary <string, object> et vous pouvez donc en ajouter / supprimer facilement.
Peter Munnings
12
msdn.microsoft.com/en-us/library/… fait la même chose, mais il est intégré à System.Web.Mvc.HtmlHelper.
Mir
1
Pourquoi ToDictionary est-il public et non privé, cela n'a pas de sens d'exposer cette méthode?
Professeur de programmation
52

Je suppose que vous voulez dire ici les types anonymes, par exemple, new { Name1=value1, Name2=value2}etc. Ils sont simplement générés automatiquement.

Ce que tu pourrais faire, c'est écrire new { old.Name1, old.Name2, ID=myId }mais je ne sais pas si c'est vraiment ce que tu veux. Des détails supplémentaires sur la situation (y compris des exemples de code) seraient idéaux.

Vous pouvez également créer un objet conteneur qui a toujours un ID et tout autre objet contenant le reste des propriétés.

Jon Skeet
la source
-1
public static string TextBox(this HtmlHelper html, string value, string labelText, string textBoxId, object textBoxHtmlAttributes, object labelHtmlAttributes){}

Cela accepterait la valeur d'identifiant que la zone de texte devrait avoir et à laquelle l'étiquette devrait faire référence. Si le consommateur n'inclut plus la propriété "id" dans textBoxHtmlAttributes, la méthode créera une étiquette incorrecte.

Je peux vérifier par réflexion si cet attribut est ajouté dans l'objet labelHtmlAttributes. Si tel est le cas, je souhaite l'ajouter ou créer un nouvel objet anonyme auquel il a été ajouté. Mais comme je ne peux pas créer un nouveau type anonyme en parcourant les anciens attributs et en ajoutant mon propre attribut "id", je suis un peu coincé.

Un conteneur avec une propriété ID fortement typée, puis une propriété "attributs" typée anonyme nécessiterait des réécritures de code qui ne correspondent pas à l'exigence "ajouter un champ id".

J'espère que cette réponse est compréhensible. C'est la fin de la journée, je ne peux plus mettre mon cerveau en ligne.

Boris Callens
la source
Eh bien ... vous pouvez créer un nouveau type (avec CodeDOM, etc.) contenant les propriétés pertinentes. Mais le code serait moche comme l'enfer. Puis-je suggérer qu'au lieu de prendre un objet et de regarder les propriétés via la réflexion, vous preniez un IDictionary <string, string> ou quelque chose? (Suite)
Jon Skeet
Vous pouvez créer ce dictionnaire avec une méthode d'assistance qui a fait tout le travail de réflexion - et éventuellement une méthode wrapper qui a fait précisément cela - mais un dictionnaire semble plus proche de ce que vous essayez vraiment de représenter; Les initialiseurs d'objets anonymes ne sont que syntaxiquement pratiques.
Jon Skeet