Aggiungi proprietà al tipo anonimo dopo la creazione


101

Uso un oggetto anonimo per passare i miei attributi HTML ad alcuni metodi di supporto. Se il consumatore non ha aggiunto un attributo ID, voglio aggiungerlo nel mio metodo di supporto.

Come posso aggiungere un attributo a questo oggetto anonimo?

Risposte:


17

Se stai cercando di estendere questo metodo:

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

Anche se sono sicuro che le estensioni Object di Khaja funzionerebbero, potresti ottenere prestazioni migliori creando un RouteValueDictionary e passando l'oggetto routeValues, aggiungi i tuoi parametri aggiuntivi dal Context, quindi restituisci utilizzando l'overload di ActionLink che accetta un RouteValueDictionary invece di un oggetto:

Questo dovrebbe fare il trucco:

    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);
    }

Funziona a meraviglia, questa dovrebbe essere la risposta accettata! BTW: Se finora stai usando gli object overload di ActionLink (), devi racchiudere htmlAttributes con HtmlHelper.AnonymousObjectToHtmlAttributes (htmlAttributes) per chiamare l'overload corretto!
DR

79

La seguente classe di estensione ti fornirà ciò di cui hai bisogno.

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;
    }
}

4
Corretto al 100%. Anche se generalmente usi tipi anonimi per gli attributi Html, in realtà è un IDictionary <string, object> e quindi puoi aggiungere / rimuovere facilmente da esso.
Peter Munnings,

12
msdn.microsoft.com/en-us/library/… fa la stessa cosa, ma è integrato in System.Web.Mvc.HtmlHelper.
Mir

1
Perché ToDictionary è pubblico e non privato, non ha senso esporre questo metodo?
Professore di programmazione

52

Presumo tu intenda tipi anonimi qui, ad esempio new { Name1=value1, Name2=value2}ecc. Se è così, sei sfortunato - i tipi anonimi sono tipi normali in quanto sono codice compilato e fisso. Sono appena stati generati automaticamente.

Quello che potresti fare è scrivere new { old.Name1, old.Name2, ID=myId }ma non so se è davvero quello che vuoi. Alcuni dettagli in più sulla situazione (inclusi esempi di codice) sarebbero l'ideale.

In alternativa, puoi creare un oggetto contenitore che abbia sempre un ID e qualsiasi altro oggetto contenga il resto delle proprietà.


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

Ciò accetterebbe il valore id che la casella di testo dovrebbe avere e l'etichetta dovrebbe fare riferimento. Se il consumatore ora non include la proprietà "id" in textBoxHtmlAttributes, il metodo creerà un'etichetta errata.

Posso controllare tramite la riflessione se questo attributo viene aggiunto nell'oggetto labelHtmlAttributes. In tal caso, voglio aggiungerlo o creare un nuovo oggetto anonimo che lo abbia aggiunto. Ma poiché non riesco a creare un nuovo tipo anonimo passando attraverso i vecchi attributi e aggiungendo il mio attributo "id", sono un po 'bloccato.

Un contenitore con una proprietà ID fortemente tipizzata e quindi una proprietà "attributi" tipizzata anonima richiederebbe riscritture del codice che non pesano sul requisito "aggiungi un campo id".

Spero che questa risposta sia comprensibile. È la fine della giornata, non riesco più a mettere in riga il mio cervello ..


Beh ... si potrebbe creare un nuovo tipo (con CodeDOM ecc) che conteneva le proprietà rilevanti. Ma il codice sarebbe brutto da morire. Posso suggerire che invece di prendere un oggetto e guardare le proprietà tramite la riflessione, prendi un IDictionary <string, string> o qualcosa del genere? (Continua)
Jon Skeet

Potresti costruire quel dizionario con un metodo di supporto che ha fatto l'intera cosa di riflessione - e possibilmente avere un metodo wrapper che ha fatto proprio questo - ma un dizionario sembra più vicino a ciò che stai veramente cercando di rappresentare; gli inizializzatori di oggetti anonimi sono solo sintatticamente utili.
Jon Skeet
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.