Tornando uma coleção customizada iterável no VBA (for each / IUnknown / NewEnum)

Na linguagem de programação Java, existem três principais famílias de coleções sendo que cada uma delas pode implementar vários objetos dentro da mesma família. Citando cada uma dessas grandes famílias e suas breves características são:

List – Adiciona-se objetos / valores à uma coleção permitindo a iteração rápida entre eles.

Set – Adiciona-se objetos / valores à uma coleção permitindo a iteração entre eles sendo estes não repetidos.

Map – Adiciona-se objetos / valores à uma coleção identificados por uma chave (key, value).

No VBA temos duas opções: (1) criar uma matriz (array) dos objetos ou valores que queremos “colecionar”. Ex:

dim i() as Integer
ReDim i(8) as Integer

Ou (2) instanciar e utilizar um objeto do tipo Collection. Ex:

dim animais as Collection
set animais = new Collection

ou até mesmo abreviando a instrução:

dim animais as new Collection

O primeiro ponto “contra” à utilizar o objeto Collection pura e simplesmente é que ele aceita qualquer tipo de valor:

animais.add 1
animais.add “uma string”

Além do Java possuir várias coleções em 3 principais famílias, temos, na linguagem, o Generics, que faz com que definamos em tempo de compilação qual o tipo que uma determinada coleção vai aceitar:

List<Animal> animais = new ArrayList<Animal>(); /*coleção que só aceita instância de animais*/

Para contornar esta limitação, podemos implementar uma classe no VBA (Módulo de Classe) que representa uma coleção com seus métodos específicos da escolha do programador:

dim animal as new Animal
animal.Nome = “Leão”
animais.addAnimal animal

Desta forma, não fica muito melhor que a coleção customizada aceite apenas animais (e não números nem strings) ?

Bem, o objeto nativo [Collection] no VBA possui uma característica muito interessante que é a capacidade de se iterar por seus itens usando-se da instrução [for each]. Ex:

for each animal in animais
        ‘faça algo com cada animal achado na coleção…
next animal
 

Porém, ao se codificar nossa nova coleção, perdemos provisóriamente a capacidade de se usar esta sintaxe. Veja o erro apresentado:

erro iterator

Existe, então, uma forma “OCULTA” de se permitir com que uma coleção customizada aceite essa propriedade.

Objetivo final: implementar no módulo de classe o método NewEnum conforme abaixo:

Public Function NewEnum() As IUnknown
Set NewEnum = pCol.[_NewEnum]
End Function

Passos:

(1) Opcional: a interface IUnknown é uma interface oculta do VBA. Para que possamos vê-la na janela Object Browser temos que selecionar a opção de ver objetos ocultos:

exibir membros ocultos

Após fazer isso podemos verificar a existência do membro que antes era oculto:

membro oculto desocultado

Esse primeiro passo não é essencial para que o código funcione. Ele é apenas importante para percebermos que a interface existe (não vem do além).        😀

(2) Exporte a classe que representa uma nova coleção para, por exemplo, a área de trabalho do seu computador:

exportar classe vba

(3) Na sua área de trabalho ou  em outro local que você tenha salvo a classe, abra-á com o bloco de notas e cole na mesma o seguinte código:

cole o código NewEnum

Public Function NewEnum() As IUnknown
Attribute NewEnum.VB_UserMemId = -4
Set NewEnum = pCol.[_NewEnum]
End Function
 

(4) Apague a classe original contida no projeto e importe o arquivo com essas alterações previamente salvas:

importar arquivo de classe vba

Pronto !!!

Observe que no código VBA a linha destacada abaixo em vermelho fica oculta:

Public Function NewEnum() As IUnknown
Attribute NewEnum.VB_UserMemId = -4
Set NewEnum = pCol.[_NewEnum]
End Function

Veja imagem:

vba iterador linha oculta

Faça o download de uma planilha MS Excel com código VBA de exemplo: CustomCollection.xlsm

Esta entrada foi publicada em Visual Basic 6.0 e VBA com as etiquetas , , , , , , . ligação permanente.

Deixe uma Resposta

Preencha os seus detalhes abaixo ou clique num ícone para iniciar sessão:

Logótipo da WordPress.com

Está a comentar usando a sua conta WordPress.com Terminar Sessão / Alterar )

Imagem do Twitter

Está a comentar usando a sua conta Twitter Terminar Sessão / Alterar )

Facebook photo

Está a comentar usando a sua conta Facebook Terminar Sessão / Alterar )

Google+ photo

Está a comentar usando a sua conta Google+ Terminar Sessão / Alterar )

Connecting to %s