Agregar propiedad al tipo anónimo después de la creación

101

Utilizo un objeto anónimo para pasar mis atributos Html a algunos métodos auxiliares. Si el consumidor no agregó un atributo de ID, quiero agregarlo en mi método auxiliar.

¿Cómo puedo agregar un atributo a este objeto anónimo?

Boris Callens
fuente

Respuestas:

17

Si está intentando extender este método:

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

Aunque estoy seguro de que las extensiones de objeto de Khaja funcionarían, es posible que obtenga un mejor rendimiento creando un RouteValueDictionary y pasando el objeto routeValues, agregue sus parámetros adicionales del Context, luego regrese usando la sobrecarga ActionLink que toma RouteValueDictionary en lugar de un objeto:

Esto debería funcionar:

    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
fuente
Funciona como un encanto, ¡esta debería ser la respuesta aceptada! Por cierto: si está utilizando las sobrecargas de objetos de ActionLink () hasta ahora, debe ajustar htmlAttributes con HtmlHelper.AnonymousObjectToHtmlAttributes (htmlAttributes) para llamar a la sobrecarga correcta.
DR
79

La siguiente clase de extensión le proporcionará lo que necesita.

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
fuente
4
100% correcto. Aunque generalmente usa tipos anónimos para Atributos Html, en realidad es un IDictionary <string, object> y, por lo tanto, puede agregar / eliminar fácilmente de él.
Peter Munnings
12
msdn.microsoft.com/en-us/library/… hace lo mismo, pero está integrado en System.Web.Mvc.HtmlHelper.
Mir
1
¿Por qué ToDictionary es público y no privado, no tiene sentido exponer este método?
Profesor de programación
52

Supongo que te refieres a tipos anónimos aquí, por ejemplo, new { Name1=value1, Name2=value2}etc. Si es así, no tienes suerte: los tipos anónimos son tipos normales en el sentido de que son código compilado y fijo. Simplemente resultan ser autogenerados.

Lo que podrías hacer es escribir, new { old.Name1, old.Name2, ID=myId }pero no sé si eso es realmente lo que quieres. Algunos detalles más sobre la situación (incluidos ejemplos de código) serían ideales.

Alternativamente, puede crear un objeto contenedor que siempre tenga un ID y cualquier otro objeto que contenga el resto de las propiedades.

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

Esto aceptaría el valor de identificación que debería tener el cuadro de texto y al que debería hacer referencia la etiqueta. Si el consumidor ahora no incluye la propiedad "id" en el textBoxHtmlAttributes, el método creará una etiqueta incorrecta.

Puedo verificar mediante la reflexión si este atributo se agrega en el objeto labelHtmlAttributes. Si es así, quiero agregarlo o crear un nuevo objeto anónimo que lo tenga agregado. Pero como no puedo crear un nuevo tipo anónimo recorriendo los atributos antiguos y agregando mi propio atributo "id", estoy un poco atascado.

Un contenedor con una propiedad de ID fuertemente tipada y luego una propiedad de "atributos" tipeada anónima requeriría reescrituras de código que no pesen para el requisito de "agregar un campo de identificación".

Espero que esta respuesta sea comprensible. Es el final del día, ya no puedo poner mi cerebro en línea ...

Boris Callens
fuente
Bueno ... podría crear un nuevo tipo (con CodeDOM, etc.) que contuviera las propiedades relevantes. Pero el código sería feo como el infierno. ¿Puedo sugerir que en lugar de tomar un objeto y mirar las propiedades a través de la reflexión, tome un IDictionary <string, string> o algo así? (Continuación)
Jon Skeet
Podrías construir ese diccionario con un método de ayuda que hiciera todo el asunto de la reflexión, y posiblemente tener un método de envoltura que hiciera precisamente eso, pero un diccionario parece estar más cerca de lo que realmente estás tratando de representar; Los inicializadores de objetos anónimos son útiles sintácticamente.
Jon Skeet