Olá,

Hoje irei falar de um recurso bem interessante, trata-se dos indexadores, o indexador é um array inteligente, ele pode ser usado tanto em classes como estrutura. Iremos criar um pequeno form que irá atuar como uma agenda, iremos gravar Nome e Telefone e posteriormente iremos pesquisar tanto o Nome quanto o Telefone que inserimos, utilizando os indexadores.

Requisitos para o Exemplo: Neste nosso exemplo iremos usar o Visual Studio 2008 com Framework 3.5, caso não tenha instalado, efetue o download gratuitamente no seguinte site :  http://www.microsoft.com/Express/

 

1-      No Visual Studio, crie um novo projeto do tipo WPF Application, o nome da solução pode deixar como Indexer, o nome do projeto escolha AgendaTelefonica conforme imagem abaixo:

 
1- Novo Projeto

 

 

2-      Dentro do Projeto Crie 3 arquivos do tipo Class, com os seguintes nomes :

-Agenda (Agenda.cs)

-Nome (Nome.cs)

-NumeroTelefone (NumeroTelefone.cs)

      3-   Abra o arquivo Nome.cs, a primeira alteração que iremos fazer é no construtor da classe, no construtor iremos definir um parâmetro de entrada, este valor irá preencher um campo da classe, conforme o código abaixo:

private string nome;

public Nome(string text)

{

      this.nome = text;

}

 

Agora, vamos criar dentro desta classe a propriedade que terá seu modificador publico para que possamos acessar de fora mesma, vale ressaltar que esta propriedade será apenas leitura, por isso não iremos implementar o método set.

public string Texto

{

      get { return this.nome; }

}

 

Para finalizar a implementação desta classe, iremos inserir mais 3 métodos sendo eles  GetHashCode() e  Equals() , conforme o código abaixo:

public override int GetHashCode()

{

      return this.nome.GetHashCode();

}

public override bool Equals(object outro)

{

      return (outro is Nome) && Equals((Nome)outro);

}

public bool Equals(Nome outro)

{

      return this.nome == outro.nome;

}

 
           A função desta classe Nome será armazenar e buscar os nomes, o nome é fornecido para o construtor, a implementação dos métodos Equals e GetHashCode é devido a necessidade de comparar os nomes durante a pesquisa em um array de valores.
 

Mais informações sobre Equals e GetHashCode acesse :
Equals ->
http://msdn.microsoft.com/pt-br/library/ms173147.aspx
GetHashCode ->
http://msdn.microsoft.com/pt-br/library/system.object.gethashcode.aspx

                Faça a mesma implementação da classe Nome para a Classe NumeroTelefones, conforme código abaixo:

class NumeroTelefones

{

public NumeroTelefones(string texto)

{

      this.numero = texto;

}

public NumeroTelefones()

{

 

}

public string Text

{

      get { return this.numero; }

}

 

public override int GetHashCode()

{

      return this.numero.GetHashCode();

}

 

public override bool Equals(object other)

{

      return (other is NumeroTelefones) && Equals((NumeroTelefones)other);

}

 

public bool Equals(NumeroTelefones other)

{

      return this.numero == other.numero;

}

 

private string numero;

}

 

Vamos abrir o arquivo Agenda.cs, dentro da classe agenda iremos implementar dois arrays privados: um array de valores para Nome e um array de valore para NumeroTelefones, conforme código abaixo:

private int tamanhoAtualIndice;

private Nome[] nomes;

private NumeroTelefones[] telefones;

 

No construtor da classe iremos instanciar e inicializar as variáveis declaradas acima:

//Definindo o Construtor da Classe Agenda

public Agenda()

{

      this.tamanhoAtualIndice = 0;

      this.nomes = new Nome[0];

      this.telefones = new NumeroTelefones[0];

}

 

Criaremos um método que irá inserir os valores dentro de um Index das classes Nome e NumeroTelefones, veja o exemplo abaixo, repare que estamos acessando o índex do nome pela notação de colchetes.  A sintaxe que utilizamos em um indexador é bem parecida com a de um array, no entando, existem algumas diferença, tais como:

- Os indexadores sofrem sobrecarga (overload) já os arrays não.

- Os indexadores podem utilizar subscritos não numéricos, como string, object e etc, enquanto os arrays só podem utilizar subscritos inteiros.

public void Add(Nome nome, NumeroTelefones numero)

{

      aumentarArrays();

      this.nomes[tamanhoAtualIndice] = nome;

      this.telefones[tamanhoAtualIndice] = numero;

      this.tamanhoAtualIndice++;

}

 

No código acima, estamos chamando o método aumentarArrays(em breve iremos falar deste), e estamos usando a variável tamanhoAtualIndice dentro dos índices dos campos nomes e telefones.

Criando o método aumentarArrays; Este método será chamado por Add para verificar se os arrays estão cheios quando o usuário adiciona um outro valor, ele cria dois novos arrays maiores copia o valor para eles e então descarta os antigos, uma vez que para redimensionar um array precisamos copiar os elementos para um novo array, copiar os elementos (omitir alguns se o novo array for menor) e então atualizar qualquer referência ao array original para que ela se refira ao novo array, isso poderia ser resolvido com outras estruturas de coleções como ArrayList e etc., porém não é o intuito deste artigo falar sobre.

private void aumentarArrays()

{

      if (this.tamanhoAtualIndice == this.nomes.Length)

      {

        int aumentarIndice = tamanhoAtualIndice + 16;

        Nome[] maisNomes = new Nome[aumentarIndice];

        this.nomes.CopyTo(maisNomes, 0);

        NumeroTelefones[] maisTelefones = new NumeroTelefones[aumentarIndice];

        this.telefones.CopyTo(maisTelefones, 0);

        this.nomes = maisNomes;

        this.telefones = maisTelefones;

      }

}

 

Agora vamos à implementação dos indexadores, lembrando que um indexador não é um método por isso não há parênteses contendo parâmetros, mas há colchetes que especificam um índice. Esse índice é utilizado para especificar que elemento está sendo acessado. Todos os indexadores utilizam a palavra-chave this no lugar do nome e vale a pena falar que em uma classe ou estrutura podemos definir no máximo um indexador.

                Com base nas informações acima, vamos declarar o indexador da classe Nome, veja o código abaixo:

public Nome this[NumeroTelefones numero]

{

  get

  {

     int i = Array.IndexOf(this.telefones, numero);

     if (i != -1)

         return this.nomes[i];

     else

         return new Nome();

   }

}

 

                O método de acesso get do Indexador da Classe Nome possui a finalidade de localizar o nome que corresponde ao número de telefone especificado na consulta. Para fazer isso estamos usando o método IndexOf da classe Array. O método IndexOf executa uma pesquisa em um array, retornando o índice do primeiro item no array correspondente a pesquisa. O primeiro argumento para IndexOf é o array a ser pesquisado (telefones),já o segundo argumento é o item que estou pesquisando, o IndexOf retorna o índice inteiro do elemento se ele o encontrar; caso contrário, IndexOf retorna -1. Se o indexador encontrar o número de telefone, ele deve retorná-lo; caso contrário ele deve retornar um nome vazio.

                Vamos fazer a mesma coisa com Telefone:

public NumeroTelefones this[Nome nome]

{

   get

   {

      int i = Array.IndexOf(this.nomes, nome);

      if (i != -1)

          return this.telefones[i];

      else

          return new NumeroTelefones();

    }

}

  

               A classe Agenda deverá ficar da seguinte maneira:

class Agenda

{

  private int tamanhoAtualIndice;

  private Nome[] nomes;

  private NumeroTelefones[] telefones;

 

  //Definindo o Construtor da Classe Agenda

  public Agenda()

  {

      this.tamanhoAtualIndice = 0;

      this.nomes = new Nome[0];

      this.telefones = new NumeroTelefones[0];

      }

           

      public void Add(Nome nome, NumeroTelefones numero)

      {

            aumentarArrays();

            this.nomes[tamanhoAtualIndice] = nome;

            this.telefones[tamanhoAtualIndice] = numero;

            this.tamanhoAtualIndice++;

      }

        public Nome this[NumeroTelefones numero]

        {

            get

            {

                int i = Array.IndexOf(this.telefones, numero);

                if (i != -1)

                    return this.nomes[i];

                else

                    return new Nome();

            }

        }

 

        public NumeroTelefones this[Nome nome]

        {

            get

            {

                int i = Array.IndexOf(this.nomes, nome);

                if (i != -1)

                    return this.telefones[i];

                else

                    return new NumeroTelefones();

            }

        }

 

            private void aumentarArrays()

            {

                  if (this.tamanhoAtualIndice == this.nomes.Length)

                  {

                        int aumentarIndice = tamanhoAtualIndice + 16;

                       

                        Nome[] maisNomes = new Nome[aumentarIndice];

                        this.nomes.CopyTo(maisNomes, 0);

                       

                        NumeroTelefones[] maisTelefones = new NumeroTelefones[aumentarIndice];

                        this.telefones.CopyTo(maisTelefones, 0);

                                  

                        this.nomes = maisNomes;

                        this.telefones = maisTelefones;

                  }

            }

 

 

      }

 

        Finalizamos nosso código iremos criar um pequeno formulário para efetuar os testes.

        1-) Abra o arquivo Windows1.xaml e insira os controles abaixo:

Controle

Propriedades

Observação

TextBox

- Altere a propriedade ID do controle para “nomeTextBox”;

É importante sempre que inserir um controle na pagina um nome simples e objetivo para que o mesmo possa ser localizado facilmente no código.

TextBox

- Altere a propriedade ID do controle para “telefoneTextBox”;

 

Button

- Altere a propriedade ID do controle para “addButton”;

Este será o botão responsável por disparar o evento que irá adicionar os valores das texbox dentro da array.

Button

- Altere a propriedade ID do controle para “pesqTelefoneTextBox”;

Este será o botão responsável por disparar o evento que irá efetuar as pesquisas por telefone.

Button

- Altere a propriedade ID do controle para “pesqNomeTextBox”;

Este será o botão responsável por disparar o evento que irá efetuar as pesquisas por nome.

 

        Alinhe os controles conforme a imagem abaixo:


2- Protótipo da tela

       Dê um duplo clique em cima do botão Add, o Visual Studio irá criar o evento Click do botão automaticamente, dentro deste evento insira o código abaixo:

private Agenda agenda = new Agenda();

private void addClick(object sender, RoutedEventArgs e)

{

   if (!String.IsNullOrEmpty(name.Text) && !String.IsNullOrEmpty(phoneNumber.Text))

   {

       agenda.Add(new Nome(nomeTextBox.Text),

                              new NumeroTelefones(telefoneTextBox.Text));

                nomeTextBox.Text = "";

                telefoneTextBox.Text = "";

     }

}

 

Faça o mesmo processo com pesqTelefoneButton;

private void pesqTelefoneButtonClick(object sender, RoutedEventArgs e)

{

   string text = telefoneTextBox.Text;

   if (!String.IsNullOrEmpty(text))

   {

       nomeTextBox.Text = agenda[new NumeroTelefones(text)].Texto;

   }

}

 

Dê um clique duplo em cima do botão pesqNomeButton, e insira o código abaixo:

private void pesqNomeButtonClick(object sender, RoutedEventArgs e)

{

   string text = nomeTextBox.Text;

   if (!String.IsNullOrEmpty(text))

   {

      telefoneTextBox.Text = agenda[new Nome(text)].Text;

   }

}

 

Já podemos efetuar os testes, compile a aplicação e veja se a mesma irá ocorrer erros, caso não ocorra nenhum erro, execute a aplicação e efetue os seguintes testes:

1-) Digite um nome e um telefone e clique em adicionar;

2-) Vá na textBox do Nome e digite o nome que você acabou de adicionar e clique em pesquisar Nome, você verá que o textBox do telefone irá preencher automaticamente.

 

Por enquanto é isso, nos vemos na próxima, abraço.

 

Mais informações sobre indexadores:

- http://msdn.microsoft.com/pt-br/library/6x16t2tx.aspx

- http://www.csharphelp.com/archives/archive140.html