Dev (Back & Front)ARTIGO

Praticando com “Reflection” e “Attributes” (WebForms e C#)

Este artigo consiste em exemplificar a utilização de alguns dos recursos do namespace System.Reflection e da classe Attributes. Como diversos artigos relacionados já foram escritos, optei por uma abordagem prática e objetiva do assunto.

O exercício tem por objetivo a criação de um método que recebe como parâmetros um objeto do tipo DropDownList e uma Lista genérica ( List<X> ), o controle será populado com os dados contidos nessa lista. Um atributo customizado servirá para marcar as propriedades da classe X que serão associadas as propriedades DataTextField e DataValueField do controle.

AttributeEntity

A Classe AttributeEntity apresenta duas propriedades booleanas, ID e Description. A primeira quando “true” indica que a propriedade marcada preencherá a DataValueField, já a segunda corresponde à propriedade DataTextField, ambas da classe DropDownList.

Essa classe herda da “Attribute”, portanto ela poderá ser usada como tal.

[AttributeEntity(Id=false, Description=true)]

Conforme definido no “AttributeUsage”, o nosso atributo customizado tem como alvo apenas propriedades, (AttributeTargets.Property) e não poderá ser utilizado mais de uma vez em um mesmo lugar (AllowMultiple=false).

Aplicável

[AttributeEntity(Id=false, Description=true)]
             public string Name
             {
                 get { return _name; }
                 set { _name = value; }
              }
     
             Não Aplicável
     
              [AttributeEntity(Id=true, Description=false)]
              [AttributeEntity(Id=false, Description=true)]
               public string Name
               {
                  get { return _name; }
                  set { _name = value; }
               }
using System;
using System.Collections.Generic;
using System.Text;

namespace ARTIGO.Utility
{
    
    [AttributeUsage(AttributeTargets.Property, AllowMultiple=false)]
    public class AttributeEntity : Attribute
    {
        #region Attributes

        private bool _id;
        private bool _description;
        
        #endregion

        #region Properties

        public bool Id
        {
            get { return _id; }
            set { _id = value; }
        }        

        public bool Description
        {
            get { return _description; }
            set { _description = value; }
        }

        #endregion
    }
}

PopulateField<X>

Na primeira linha Type t = typeof(X); ele recupera o tipo da lista parametrizada para que a reflexão seja realizada sobre ele.

No próximo passo PropertyInfo[] list = t.GetProperties(), as propriedades da classe X serão colecionadas. O objetivo é iterar por elas a fim de descobrir a que possui um atributo do tipo AttributeEntity. Como as propriedades possuem uma coleção de atributos customizados, uma nova iteração será feita para encontrar o atributo pretendido. Quando ele for encontrado, o estado de suas propriedades deverá ser verificado e com base nesses valores serão definidos os valores das propriedades DataValueField (Id) e DataTextFied (Description) do DropDownList parametrizado.

Observação: Nesse exemplo, uma mesma propriedade poderá assumir o texto e o valor de um item do controle DropDownList.

Por fim, a lista será atribuída à propriedade DataSource do controle e ele será preenchido.

PopulateField

Esse método apenas insere um item padrão no controle cujo texto é [Selecione] e o valor 0.

using System;
using System.Collections.Generic;
using System.Text;
using System.Web.UI.WebControls;
using System.Data;
using System.Reflection;
using System.Web.UI;

namespace ARTIGO.Utility
{
    public class Util
    {

        #region Methods

        /// <summary>
        /// Popula o DropDownList parametrizado com a lista genérica também parametrizada.
        /// </summary>
        /// <typeparam name="X">Tipo dos objetos que formam a lista genérica.</typeparam>
        /// <param name="pDrop">Objeto DropDownList a ser populado.</param>
        /// <param name="pSource">Lista genérica que será utilizada para preencher o controle.</param>
        public static void PopulateField<X>(DropDownList pDrop, List<X> pSource)
        {
            try
            {
                Type t = typeof(X);

                PropertyInfo[] list = t.GetProperties();

                foreach (PropertyInfo p in list)
                {
                    object[] attributes = p.GetCustomAttributes(typeof(AttributeEntity), false);

                    foreach (object attribute in attributes)
                    {
                        AttributeEntity ad = (AttributeEntity)attribute;

                        if (ad.Id)
                        {
                            pDrop.DataValueField = p.Name;
                        }

                        if (ad.Description)
                        {
                            pDrop.DataTextField = p.Name;
                        }
                    }
                }

                pDrop.DataSource = pSource;
                pDrop.DataBind();
            }
            catch
            {
                // ToDo -> Implementar tratamento de erros.
            }
            finally
            {
                PopulateField(pDrop);
            }

        }

        /// <summary>
        /// Popula o DropDownList parametrizado com apenas um item, chamado [Selecione] para que a lista não seja
        /// apresentada sem elementos.
        /// </summary>
        /// <param name="pDrop">Objeto DropDownList a ser populado.</param>
        private static void PopulateField(DropDownList pDrop)
        {
            pDrop.Items.Insert(0, new ListItem("[Selecione]", "0"));
            pDrop.SelectedIndex = 0;
        }        

        #endregion

    }
}

Utilizando…


using System;
using System.Collections.Generic;
using System.Text;

using ARTIGO.Utility;

namespace ARTIGO.Entities
{
    public class Aluno
    {
        #region Attributes

        private string _matricula;
        private string _nome;
        private DateTime _dataNacimento;

        #endregion

        #region Properties

        [AttributeEntity(Id=true, Description=false)]
        public string Matricula
        {
            get { return _matricula; }
            set { _matricula = value; }
        }

        [AttributeEntity(Id = false, Description = true)]
        public string Nome
        {
            get { return _nome; }
            set { _nome = value; }
        }

        public DateTime DataNacimento
        {
            get { return _dataNacimento; }
            set { _dataNacimento = value; }
        }

        #endregion

        #region Constructors

        public Aluno(string pNome, string pMatricula, DateTime pDataNascimento)
        {
            this.Nome = pNome;
            this.Matricula = pMatricula;
            this.DataNacimento = pDataNascimento;   
        }

        #endregion
    }
}

protected void Page_Load(object sender, EventArgs e)
    {        
        
        DropDownList ddl;
        List<Aluno>  listAluno;

        ddl       = new DropDownList();
        listAluno = new List<Aluno>();

        listAluno.Add(new Aluno("Maria",  "20092506", DateTime.Now));
        listAluno.Add(new Aluno("Carla",  "20092507", DateTime.Now));
        listAluno.Add(new Aluno("Rosana", "20092508", DateTime.Now));
        
        Util.PopulateField<Aluno>(ddl, listAluno);
        this.form1.Controls.Add(ddl);
    }

Resultado do teste proposto.Resultado do teste proposto.

Código apresentado no artigo para download.

trabalha com desenvolvimento web utilizando a plataforma .NET há cerca de cinco anos. Possui as certificações MCP, MCTS (Web e Distributed Applications) e MCPD. Graduando em Sistemas de Informação pela UVV (ES), atua também lecionando em cursos de extensão voltados para tecnologias Microsoft.

Ver perfil

Mais de Augusto César Barcelos Nunes Filho