none
Mvps, Experts, etc... Qual a solução! Reflection, Generics, Herança???? RRS feed

  • Pergunta

  • Vejam o seguinte código:

     

    public class ClasseBase

    {

           public List<ClasseBase> teste()

           {

                  List<ClasseBase> list = new List<ClasseBase>();

                  for (int x = 0; x < 10; x++)

                  {

                          foreach (PropertyInfo prop in this.GetType().GetProperties())

                          {

                                prop.SetValue(this, "Cidade" + x.ToString(), null);

                                Console.WriteLine("Teste de SetValue: " + prop.GetValue(this, null));

                          }

                         

                         list.Add(this);

                 }

                return list;

           }

    }

     

     

    public class Cidades : ClasseBase

    {

              string cidade;

              public string Cidade

              {

                    set { cidade = value; }

                    get { return cidade; }

              }

    }

     

    class TestList

    {

            static void Main(string[] args)

            {

                   Cidades teste = new Cidades();

     

                   foreach (Cidades i in teste.teste())

                   {

                          System.Console.Write(i.Cidade + " ");

                   }

     

                  System.Console.WriteLine("\nPronto");

           }

    }

     

    Eu não entendo o porque o método teste retorna somente a última cidade da listagem!!!

    Vejam que através de reflection eu seto a classe base e imprimo e ocorre tudo OK!

     

    Mas na hora

    que eu pego o retorno list do método ele me retorna somente a última cidade ele mostra a última cidade 10 vezes???

     

    Por favor, não adicionem a classe filha dentro da classe base, este código deve servir para várias classes filhas diferentes

    eu não posso limitar o código do método teste.

     

    Como fazer o retorno correto da listagem???

     

    Agradeço muito a ajuda de todos!!!

    segunda-feira, 2 de abril de 2007 20:05

Respostas

  • É o mesmo objeto. Você está incluindo na lista dez referências ao mesmo objeto, e setando a propriedade "Cidade" um monte de vezes. O valor da última vez que você setou é o que você verá, porque, repito, trata-se do mesmo objeto.

     

    Ademais, isso que você está fazendo é errado. No momento em que uma classe derivada que não contiver a propriedade "Cidade" tiver aquele método executado você receberá um erro. Não se acessa propriedades de uma classe derivada de uma classe base, mas sim o contrário. Se precisar fazer algum processamento que lide com o tipo da classe, sobrescreva o método na classe derivada em questão.

     

    Você está violando todas as regras de herança.

     

    De qualquer forma, se você quiser ver dez valores diferentes na propriedade "Cidade", você precisa criar dez objetos, isto é precisa instanciar dez vezes a classe "Cidades" e adicionar as respectivas referências à lista:

     

     

        public List<ClasseBase> teste()
        {
            Console.WriteLine(this.GetType().Name);
     
            List<ClasseBase> list = new List<ClasseBase>();
            for (int x = 0; x < 10; x++)
            {
                // Nova instãncia desse objeto.
                object cb = Activator.CreateInstance(this.GetType());
                // Seta propriedade "Cidade". Só finciona se a classe derivada contiver
                // essa propriedade, do contrário ocorrerá um erro.
                PropertyInfo prop = this.GetType().GetProperty("Cidade");
                prop.SetValue(cb, "Cidade" + x.ToString(), null);
     
                Console.WriteLine("Teste de SetValue: " + prop.GetValue(this, null));
                // Adiciona nova instância à lista.
                list.Add((ClasseBase)cb);
            }
            return list;
        }
    }
     
    public class Cidades : ClasseBase
    {
        string cidade;
     
        public string Cidade
        {
            set { cidade = value; }
            get { return cidade; }
        }
    }
     
    class TestList
    {
        static void Main(string[] args)
        {
            Cidades teste = new Cidades();
     
            foreach (Cidades i in teste.teste())
            {
                System.Console.Write(i.Cidade + " ");
            }
     
            System.Console.WriteLine("\nPronto");
            Console.ReadLine();
       }
    }

     

    segunda-feira, 2 de abril de 2007 22:00
  • Você não deve simplesmente assumir, num método de uma classe base, a existência de uma propriedade que está implementada na classe derivada, como você estava fazendo com a propriedade "Cidade", que era refenciada pelo **nome** na classe base, simplesmente porque sso fará com que outra classe derivada da classe base, que eventualmente não tenha aquela propriedade, não possa invocar o método da classe derivada, como eu disse no post anterior. Daí você estar violando os princípios da herança.

     

    Não há nada errado em incluir na classe base um método de listagem genérico, que retorne, por exemplo, um lista das propriedades do objeto, desde que você não assuma coisas sobre as classes derivadas, como o nome de uma propriedade, por exemplo. Uma classe derivada pode assumir que a classe base tenha uma propriedade X (ela herdou a propriedade, afinal), mas a classe base não poder assumir que a classe derivada tenha uma propriedade X.

    terça-feira, 3 de abril de 2007 18:22
  • ok! Faça assim. Utilize List ao invés de Array isso se você estiver utilizando a versão 2.0 ou posterior do C#

     

    Para que o código funcione, é necessário fazer uma alteração na classe Designer.cs do seu resource file. Mude o modificador 'internal' para 'public' para toda a classe do Resource File.

     

    public class Exemplo

    {

           private List<Icon> lista;

           private Random randomico;

     

           public Exemplo(object objeto)

           {

                   lista = new List<Icon>();

                   randomico = new Random(0);

                   foreach (PropertyInfo prop in objeto.GetType().GetProperties())

                    {

                           if (prop.PropertyType == typeof(Icon))

                           {

                                  Icon icone = (Icon)prop.GetValue(objeto, null);

                                   lista.Add(icone);

                           }

                    }

           }

     

     

           public Icon IconeRandomico()

           {

                  if (lista.Count == 0)

                     return null;

     

                 int Numero = randomico.Next(lista.Count - 1);

                 return lista[Numero];

            }

    }

     

     

    Você irá utilizar essa classe da seguinte maneira.

     

    Trocando randomicamente os ícones do formulário:

     

    public partial class Form1 : Form

    {

                Exemplo teste;

                public Form1()

                {

                            InitializeComponent();

                            ResourceIcone resIcon = new ResourceIcone();

                            teste = new Exemplo(resIcon);

                }

     

                private void button1_Click(object sender, EventArgs e)

                {

                       this.Icon = teste.IconeRandomico();

                }

     

    sexta-feira, 13 de julho de 2007 19:06

Todas as Respostas

  • É o mesmo objeto. Você está incluindo na lista dez referências ao mesmo objeto, e setando a propriedade "Cidade" um monte de vezes. O valor da última vez que você setou é o que você verá, porque, repito, trata-se do mesmo objeto.

     

    Ademais, isso que você está fazendo é errado. No momento em que uma classe derivada que não contiver a propriedade "Cidade" tiver aquele método executado você receberá um erro. Não se acessa propriedades de uma classe derivada de uma classe base, mas sim o contrário. Se precisar fazer algum processamento que lide com o tipo da classe, sobrescreva o método na classe derivada em questão.

     

    Você está violando todas as regras de herança.

     

    De qualquer forma, se você quiser ver dez valores diferentes na propriedade "Cidade", você precisa criar dez objetos, isto é precisa instanciar dez vezes a classe "Cidades" e adicionar as respectivas referências à lista:

     

     

        public List<ClasseBase> teste()
        {
            Console.WriteLine(this.GetType().Name);
     
            List<ClasseBase> list = new List<ClasseBase>();
            for (int x = 0; x < 10; x++)
            {
                // Nova instãncia desse objeto.
                object cb = Activator.CreateInstance(this.GetType());
                // Seta propriedade "Cidade". Só finciona se a classe derivada contiver
                // essa propriedade, do contrário ocorrerá um erro.
                PropertyInfo prop = this.GetType().GetProperty("Cidade");
                prop.SetValue(cb, "Cidade" + x.ToString(), null);
     
                Console.WriteLine("Teste de SetValue: " + prop.GetValue(this, null));
                // Adiciona nova instância à lista.
                list.Add((ClasseBase)cb);
            }
            return list;
        }
    }
     
    public class Cidades : ClasseBase
    {
        string cidade;
     
        public string Cidade
        {
            set { cidade = value; }
            get { return cidade; }
        }
    }
     
    class TestList
    {
        static void Main(string[] args)
        {
            Cidades teste = new Cidades();
     
            foreach (Cidades i in teste.teste())
            {
                System.Console.Write(i.Cidade + " ");
            }
     
            System.Console.WriteLine("\nPronto");
            Console.ReadLine();
       }
    }

     

    segunda-feira, 2 de abril de 2007 22:00
  •  

    Angus só mais uma pergunta, você falou que eu estava violanda regras de herança....

     

    O que estou fazendo é o seguinte, tenho uma classe base, esta é uma classe de persistência, nela tenho métodos de inserção, atualização, exclusão e finalmente

    graças a sua ajuda o método de listagem, esse por sua vez vai ser mais implementado ainda.

     

    Através da classe base por reflection leio as propriedades das classes que herdam desta classe base, cada propriedade das classes herdadas tem atributos especificando nome tabelas, colunas, tamanho de colunas, etc... Então eu simplesmente crio as classes de negócios, e faço mapeamento nelas através de

    atributos!

     

    Isto serve para eu acessar o banco de dados nesta classe base, e persistir a informação de acordo com a classe herdada, assim eu não preciso ficar criando os

    mesmo métodos para todas as classes e ficar especificando campos.

     

    Resumindo, simplesmente crio uma classe e ela herda esses métodos de Inserção, Atualização, Exclusão, Listagem, da classe base, esses

    métodos que fazem a leitura da classe herdada para fazer as operações determinadas.

     

    Isto é errado, estou quebrando as regras de herança? A sua resposta é muito importante para mim, eu não quero seguir o caminho errado da coisa....

     

    Eu antes programava em linguagem estruturada, hoje estou apanhando muito da orientação a objeto, isso que eu estava fazendo que eu achava que era a vantagem

    da herança, estou tentando seguir os Patterns and Practices, mas agora a dúvida ficou grande!

     

    Veja que a minha classe herdada vai ter métodos da classe base.

    Se eu estiver errado, eu devo mudar essa classe base de forma que ela consuma as classes herdadas, para a persistência dos dados?

    terça-feira, 3 de abril de 2007 11:51
  • mais uma coisinha... Angus eu só utilizo o foreach para ler todas as propriedades que podem ter na classe.

     

    A sua resposta é muito importante para mim!

     

    Obrigado!

    terça-feira, 3 de abril de 2007 12:14
  • Você não deve simplesmente assumir, num método de uma classe base, a existência de uma propriedade que está implementada na classe derivada, como você estava fazendo com a propriedade "Cidade", que era refenciada pelo **nome** na classe base, simplesmente porque sso fará com que outra classe derivada da classe base, que eventualmente não tenha aquela propriedade, não possa invocar o método da classe derivada, como eu disse no post anterior. Daí você estar violando os princípios da herança.

     

    Não há nada errado em incluir na classe base um método de listagem genérico, que retorne, por exemplo, um lista das propriedades do objeto, desde que você não assuma coisas sobre as classes derivadas, como o nome de uma propriedade, por exemplo. Uma classe derivada pode assumir que a classe base tenha uma propriedade X (ela herdou a propriedade, afinal), mas a classe base não poder assumir que a classe derivada tenha uma propriedade X.

    terça-feira, 3 de abril de 2007 18:22
  •  Rodrigo da Silva Brito wrote:

    mais uma coisinha... Angus eu só utilizo o foreach para ler todas as propriedades que podem ter na classe.

     

    A sua resposta é muito importante para mim!

     

    Obrigado!

     

    Eu não entendi?  isso é uma pergunta?

    terça-feira, 3 de abril de 2007 18:24
  • Angus obrigado por sua resposta! Então agora estou mais seguro!

     

    Sobre a pergunta acima é que no exemplo eu havia colocado um:

     

    foreach (PropertyInfo prop in this.GetType().GetProperties())

     

    que lê todas as propriedades da classe.

     

    e você colocou:

     

    foreach (PropertyInfo prop in this.GetType().GetProperty("Cidade"))

     

    que pega somente uma propriedade X.

     

     

    no exemplo eu coloquei um dado com o nome de CIDADE só para o exemplo.

     

    mas na classe real eu utilizo reflection, para ler o nome da propriedade e passar para um DbReader para dar o retorno do dado, daí para passar

    o retorno da listagem.

     

    Essa classe então vai ser reposnsável por toda a persistência de dados, os métodos de inclusão, alteração, inserção eu já havia implementado,

    mas tive muita dificuldade na montagem do método de listagem, mas graças a sua ajuda agora está tudo ok!

     

    Muito obrigado!

     

    Valeu D++! Até!

     

     

     

    terça-feira, 3 de abril de 2007 18:35
  • Opa galera... estava procurando uma coisa na net talvez vcs podem me ajudar.

    Eu add varios icones em um resource file e pretendo usa-los randomicamente desta forma:

    this.Icon = meuArrayIconesPreencidoDoResource[rnd];


    Ouvi disser que preciso usar Reflection pra acessa todos icones do meu resorces via codigo, correto?

    Ja tentei de varias formas, como eu faço isto? valew.

    Unica coisa que tentei e nada deu foi:

    Type t = Type.GetType("AlertOcorrencia.img");
    Icon [] o = (Icon)Activator.CreateInstance(t);

    so q nada deu.
    tentei tb:

                foreach (PropertyInfo prop in t.GetProperties()){
                    MessageBox.Show(prop.GetType().ToString());
                }

    e nada...

    Alguem pode me ajudar?
    quinta-feira, 12 de julho de 2007 23:37
  • Você deve utilizar os objetos de System.Resources.

     

    using System.Resources;

      

    internal class ManageResources

    {

            private ResourceManager resourceManager;

            public ManageResources(object obj)

            {

                     string name = obj.GetType().ToString();

                     resourceManager = new ResourceManager(name, Assembly.GetExecutingAssembly());

            }

          

            internal Icon Localize(string key)

            {

                   return (Icon)resourceManager.GetObject(key);

            }

    }

     

    internal void MetodoDemonstracao()

    {

         ManageResources manageResources = new ManageResources("o seu objeto resource");

         Icon meuIcone = manageResources.Localize("O nome do seu ícone, no objeto resource");´

    }

     

    Teoricamente é isso, eu não fiz testes, talves seja necessário alguns ajustes...

     

     

     

    sexta-feira, 13 de julho de 2007 12:26
  • Opa.. valew pela ajuda, acebei de ler seu post mas pelo q estou vendo se resume nesta linha:

    Icon meuIcone = manageResources.Localize("O nome do seu ícone, no objeto resource");´

    como vou usa-lo no form irei usar desta forma:

    this.Icon = new manageResources.Localize("O nome do seu ícone, no objeto resource");

    Certo?

    So q axo q tem um problema, nao quero chamar meus icones pelo nome, quero chama-los por algum indice.

    Quero pular um Array de Icon e atribui-lo ao meu form randomicamente e no seu exemplo eu devo saber nomes de todos os icones para chama-los q é um problema pois tenho uns 20 icones e amanha quando for por mais 20 nao vai funcionar =/

    Tem alguma dica pra coloca-los em um array de Icon?



    Obrigado..

    sexta-feira, 13 de julho de 2007 12:43
  • ok! Faça assim. Utilize List ao invés de Array isso se você estiver utilizando a versão 2.0 ou posterior do C#

     

    Para que o código funcione, é necessário fazer uma alteração na classe Designer.cs do seu resource file. Mude o modificador 'internal' para 'public' para toda a classe do Resource File.

     

    public class Exemplo

    {

           private List<Icon> lista;

           private Random randomico;

     

           public Exemplo(object objeto)

           {

                   lista = new List<Icon>();

                   randomico = new Random(0);

                   foreach (PropertyInfo prop in objeto.GetType().GetProperties())

                    {

                           if (prop.PropertyType == typeof(Icon))

                           {

                                  Icon icone = (Icon)prop.GetValue(objeto, null);

                                   lista.Add(icone);

                           }

                    }

           }

     

     

           public Icon IconeRandomico()

           {

                  if (lista.Count == 0)

                     return null;

     

                 int Numero = randomico.Next(lista.Count - 1);

                 return lista[Numero];

            }

    }

     

     

    Você irá utilizar essa classe da seguinte maneira.

     

    Trocando randomicamente os ícones do formulário:

     

    public partial class Form1 : Form

    {

                Exemplo teste;

                public Form1()

                {

                            InitializeComponent();

                            ResourceIcone resIcon = new ResourceIcone();

                            teste = new Exemplo(resIcon);

                }

     

                private void button1_Click(object sender, EventArgs e)

                {

                       this.Icon = teste.IconeRandomico();

                }

    }

     

    sexta-feira, 13 de julho de 2007 19:06
  • ok! Faça assim. Utilize List ao invés de Array isso se você estiver utilizando a versão 2.0 ou posterior do C#

     

    Para que o código funcione, é necessário fazer uma alteração na classe Designer.cs do seu resource file. Mude o modificador 'internal' para 'public' para toda a classe do Resource File.

     

    public class Exemplo

    {

           private List<Icon> lista;

           private Random randomico;

     

           public Exemplo(object objeto)

           {

                   lista = new List<Icon>();

                   randomico = new Random(0);

                   foreach (PropertyInfo prop in objeto.GetType().GetProperties())

                    {

                           if (prop.PropertyType == typeof(Icon))

                           {

                                  Icon icone = (Icon)prop.GetValue(objeto, null);

                                   lista.Add(icone);

                           }

                    }

           }

     

     

           public Icon IconeRandomico()

           {

                  if (lista.Count == 0)

                     return null;

     

                 int Numero = randomico.Next(lista.Count - 1);

                 return lista[Numero];

            }

    }

     

     

    Você irá utilizar essa classe da seguinte maneira.

     

    Trocando randomicamente os ícones do formulário:

     

    public partial class Form1 : Form

    {

                Exemplo teste;

                public Form1()

                {

                            InitializeComponent();

                            ResourceIcone resIcon = new ResourceIcone();

                            teste = new Exemplo(resIcon);

                }

     

                private void button1_Click(object sender, EventArgs e)

                {

                       this.Icon = teste.IconeRandomico();

                }

     

    sexta-feira, 13 de julho de 2007 19:06
  • nossa cara!! Big Smile funcionou perfeitamente...
    Tudo que eu queria...



    Valew.. Muito obrigado...
    sexta-feira, 13 de julho de 2007 20:06