Adicionar propriedade ao tipo anônimo após a criação

101

Eu uso um objeto anônimo para passar meus atributos Html para alguns métodos auxiliares. Se o consumidor não adicionou um atributo de ID, quero adicioná-lo ao meu método auxiliar.

Como posso adicionar um atributo a este objeto anônimo?

Boris Callens
fonte

Respostas:

17

Se você está tentando estender este método:

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

Embora eu tenha certeza de que as extensões de objeto de Khaja funcionariam, você pode obter um melhor desempenho criando um RouteValueDictionary e passando o objeto routeValues, adicione seus parâmetros adicionais do Context e retorne usando a sobrecarga ActionLink que leva um RouteValueDictionary em vez de um objeto:

Isso deve resolver o problema:

    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
fonte
Funciona perfeitamente, esta deve ser a resposta aceita! BTW: Se você estiver usando as sobrecargas de objeto de ActionLink () até agora, você deve agrupar htmlAttributes com HtmlHelper.AnonymousObjectToHtmlAttributes (htmlAttributes) para chamar a sobrecarga correta!
DR
79

A seguinte classe de extensão fornecerá o que você precisa.

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
fonte
4
100% correto. Embora geralmente você use tipos anônimos para atributos Html, na verdade é um IDictionary <string, object> e, portanto, você pode adicionar / remover facilmente dele.
Peter Munnings de
12
msdn.microsoft.com/en-us/library/… faz a mesma coisa, mas é integrado ao System.Web.Mvc.HtmlHelper.
Mir
1
Por que o ToDictionary é público e não privado, não faz sentido expor esse método?
Professor de programação de
52

Presumo que você se refira a tipos anônimos aqui, por exemplo, new { Name1=value1, Name2=value2}etc. Em caso afirmativo, você está sem sorte - tipos anônimos são tipos normais por serem códigos fixos e compilados. Eles simplesmente são gerados automaticamente.

O que você poderia fazer é escrever, new { old.Name1, old.Name2, ID=myId }mas não sei se é isso que você realmente quer. Mais alguns detalhes sobre a situação (incluindo exemplos de código) seriam ideais.

Como alternativa, você pode criar um objeto recipiente que sempre tenha um ID e qualquer outro objeto que contenha o restante das propriedades.

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

Isso aceitaria o valor de id que a caixa de texto deveria ter e o rótulo deveria se referir. Se o consumidor agora não incluir a propriedade "id" em textBoxHtmlAttributes, o método criará um rótulo incorreto.

Posso verificar por meio de reflexão se esse atributo é adicionado ao objeto labelHtmlAttributes. Em caso afirmativo, desejo adicioná-lo ou criar um novo objeto anônimo que o tenha adicionado. Mas como não consigo criar um novo tipo anônimo percorrendo os atributos antigos e adicionando meu próprio atributo "id", estou meio preso.

Um contêiner com uma propriedade de ID fortemente tipada e, em seguida, uma propriedade de "atributos" digitada anônima exigiria reescritas de código que não pesam para o requisito de "adicionar um campo de id".

Espero que esta resposta seja compreensível. É o fim do dia, não consigo mais colocar meu cérebro em linha ..

Boris Callens
fonte
Bem ... você pode criar um novo tipo (com CodeDOM etc) que contenha as propriedades relevantes. Mas o código seria muito feio. Posso sugerir que em vez de pegar um objeto e olhar as propriedades por meio de reflexão, você pegue um IDictionary <string, string> ou algo assim? (Continuação)
Jon Skeet
Você poderia construir esse dicionário com um método auxiliar que fizesse todo o reflexo - e possivelmente ter um método wrapper que fizesse exatamente isso - mas um dicionário parece estar mais próximo do que você está realmente tentando representar; inicializadores de objetos anônimos são apenas sintaticamente úteis.
Jon Skeet