Esse artigo trata dois assuntos bastante importantes e que segue uma das boas práticas de programação que é o uso de “Structures” e “Enum”e mostrar como usar os mesmo em seu projeto. Vamos primeiramente falar um pouco sobre o que é um “Structures”.

Muito semelhante a uma classe, a Structure requer menos memória que uma classe, instancia mais rapidamente e é considerada uma boa prática de programação para objetos menores, mas somente para objetos menores. Um tipo struct é um tipo de valor normalmente usado para encapsular pequenos grupos de variáveis relacionadas, como as coordenadas de um retângulo ou as características de um item em um inventário. Os Structs são tipos de dados definidos pelo usuário e que consistem em um conjunto de variáveis simples. Os tipos de valores são armazenados no stack e cada vez que alteramos seu valor, um novo endereço de memória é utilizado. Além disso, as structs se comportam como classes.

Apesar das funcionalidades semelhantes, as structs são geralmente mais eficientes do que classes em termos de consumo de recursos. Para decidir quando usar uma estrutura ao invés de classes, deve-se analisar se o objeto:


  • Possui instâncias com tamanho de até 16 bytes;
  • Não é alterado com frequência após sua criação;
  • Não é convertido para uma classe.

As structs podem implantar uma interface, mas não podem herdá-la de outra struct. Por esse motivo, as struct membros não podem ser declarados como protegidos.

Uma estrutura possui as seguintes características:


  • Pode ter métodos, campos, indexadores, propriedades, métodos de operação e eventos;
  • Pode ter construtores definidos, mas não destruidores. No entanto, você não pode definir um construtor padrão para uma estrutura, pois ele é definido automaticamente e não pode ser alterado;
  • Não pode herdar outras estruturas ou classes;
  • Não pode ser usada como uma base para outras classes ou estruturas;
  • Pode implementar uma ou mais interfaces;
  • Membros de estrutura não podem ser especificados como abstratos, virtuais ou protegidos;
  • Quando se cria um objeto struct usando o operador ”New”, ele é criado e o construtor apropriado é chamado. Ao contrário de classes, estruturas podem ser instanciadas sem usar o novo operador;
  • Se o operador New não é utilizado, o campo permanecerá não atribuído e o objeto não pode ser utilizado até que todos os campos são inicializados.

Uma estrutura em C# é simplesmente um tipo de dados composto que consiste em um número de elementos de outros tipos. Pode conter campos, métodos, constantes, construtores, propriedades, indexadores, operadores e até mesmo outros tipos de estrutura.

A palavra-chave struct pode ser usada para declarar uma estrutura. A forma geral de uma declaração de estrutura em C# é a mesma apresentada na Listagem 1.

Listagem 1. Estrutura Declaração e criação de objetos

<Modificadores> struct <struct_name> 
  { 
  // membros Estrutura 
  }

Os objetos de uma struct podem ser criados usando o operador New, como se segue na Listagem 2.

Listagem 2. Instanciando uma Struct.

MinhaEstrutura ms = new MinhaEstrutura ();

Uma struct em C# podem conter vários campos que podem ser declarados como privados, públicos ou interno. Lembre-se que dentro de uma struct só podemos declarar um campo.

Não podemos inicializar um campo dentro de uma estrutura. No entanto, podemos usar um construtor para inicializar os campos de estrutura.

Uma struct também pode conter métodos estático ou não estático, mas os métodos estáticos podem acessar somente outros membros estáticos e não podem invocar usando um objeto da estrutura, mas apenas usando o nome da struct.

Os operadores podem ser sobrecarregados dentro da struct e as mesmas regras aplicáveis para a classe C# também são aplicáveis neste caso. Ambos os operadores unários e binários podem ser sobrecarregados. A estrutura não pode herdar de outra classe ou estrutura e não podem ser a classe base para uma classe. Mas lembre-se que em C# todos os tipos são direta ou indiretamente herdando o objeto classe base super e, portanto, a estrutura também.

As estruturas não suportam herança e não podemos usar as palavras-chave virtual, override, new, abstratic, com os métodos struct. Os tipos de struct nunca são abstratos e estão sempre implicitamente vedados. Os modificadores abstratos ou selados não são permitidos em uma declaração struct. Como a herança não é suportada por estruturas, a acessibilidade declarada de um membro do struct não pode ser protegido ou interno.

Todos os tipos struct são implicitamente herdados de classe de objeto e é possível substituir os métodos da classe de objeto dentro de um struct usando a palavra-chave override. Lembre-se que este é um caso especial em estruturas C#.

Apesar das funcionalidades semelhantes, as structs são geralmente mais eficientes do que classes em termos de consumo de recursos. Para decidir quando usar uma estrutura ao invés de classes deve-se analisar se o objeto:


  • Possui instâncias com tamanho de até 16 bytes;
  • Não é alterado com frequência após sua criação;
  • Não é convertido para uma classe.

As Structs devem ser usadas para objetos com poucas informações e por objetos como tipo .NET, como Integer, String, Decimal, Date e etc.

Podemos usá-las sempre que você precisar de uma estrutura para armazenar dados e não precisar criar heranças, polimorfismos e quando a quantidade de dados a armazenar seja até 24 bytes. Para acima desse valor use classes.

A estrutura encapsula um pequeno grupo de variáveis ​​relacionadas dentro de um único tipo de dados definido pelo usuário. Além disso, melhora o uso de velocidade e memória, além da melhora no desempenho e clareza de seu código. Uma estrutura pode ser definida em um namespace, independentemente de qualquer outro tipo definido pelo usuário (classe ou estrutura), ou pode ser definida como um tipo aninhado dentro da declaração de outro tipo. Quando for necessário criar um objeto de estrutura usando o operadornew, o construtor apropriado é chamado.Diferentemente das classes, as structs podem ser instanciadas sem usar o operador new.Em tais casos, não há nenhuma chamada de construtor, que faz a alocação mais eficiente.

Vamos mostrar na prática como podemos usar uma estrutura em nossos projetos. Para começarmos, abra o Visual Studio e crie um projeto Windows Forms, como mostra a Figura 1.

Criando
um novo projeto

Figura 1. Criando um novo projeto

Depois do projeto ControlIT.SisPac estiver criado, vamos criar a estrutura com o código da Listagem 3.

Listagem 3. Criando uma estrutura.

public struct stEndereco
  {
      private string tipologra;
      private string logradouro;
      private int numero;
      private string complemento;
      private string bairro;
      private string cidade;
      private string uf;
      private string cep;
   }

A palavra Strucure identifica um código de declaração de uma estrutura. Em seguida foram definidos os campos que vão fazer parte junto com seus respectivos tipos. Não existe nenhuma herança para estruturas como há para classes.Uma estrutura não pode herdar uma outra estrutura ou classe, e também não pode ser base de uma classe.Estruturas, no entanto, herdam da classe baseObject.

Na Listagem 4 temos a criação dos objetos criados a partir da Structure.

Listagem 4. Criação de objetos

public string Tipologra
  {
     set { tipologra = value; }
     get { return tipologra; }
  }
   
  public string Logradouro
  {
     set { logradouro = value; }
     get { return logradouro; }
  }
   
  public int Numero
  {
     set { numero = value; }
     get { return numero; }
  }
   
  public string Complemento
  {
     set { complemento = value; }
     get { return complemento; }
  }

Na Listagem 5 temos a lista de parâmetros passados ao se criar o construtor. Esses parâmetros recebidos servem para iniciar os valores dos atributos.

Listagem 5. Parâmetros


  public stEndereco(string ptl, string plo, int pnu, string pco)
  {
     tipologra = ptl;
     logradouro = plo;
     numero= pnu;
     complemento = pco;
  }

Depois disso vamos criar o formulário de cadastro de clientes para testar nossa aplicação, conforme mostra a Figura 2.

Tela de
Cadastro de Cliente

Figura 2. Tela de Cadastro de Cliente

Repare que a tela é bem simples, apenas com os labels e os texts para recolher as informações e um único botão, o qual terá a mesma configuração presente na Listagem 6.

Listagem 6. Botão salvar de nossa aplicação.

private void bt_salvar(object sender, EventArgs e)
   {
       stEndereco ste = new stEndereco();
       ste.Tipologra = cmbTipoVia.Text;
       ste.Logradouro = txtLogradouro.Text;
       ste.Numero = txtnumero.Text;
       ste.Complemento = txtcomplemento.Text;
       MessageBox.Show("ok");
   }

Enum

Uma das boas práticas de programação em C# é o uso do enum. Ele serve para substituirmos constantes nomeadas que são relacionadas mas ficam “perdidas” no código. A palavra-chave enum é usada para declarar uma enumeração, um tipo distinto que consiste em um conjunto de constantes. O Enum é um tipo de valor e não pode herdar ou ser herdado.

Geralmente é melhor definir um enum dentro de um namespace para que todas as classes dele possam acessá-lo. No entanto, um enum também pode ser aninhado em classes ou Structures. O. NET Framework Class Library enums contém muitos exemplos de como eles são utilizados. Por exemplo, toda vez que você colocar um ícone em um MessageBox, você usa o MessageBoxIcon ENUM. Sempre existem situações em que você está usando um conjunto de números relacionados em um programa, então considere substitui estes números com enums.

Ele é um objeto string cujo valor normalmente é escolhido de uma lista de valores permitidos e que são enumerados explicitamente na especificação da coluna na criação da tabela. O valor pode ser a string vazia ("") ou NULL sob as seguintes circunstâncias:


  • Se você inserir um valor inválido em um enum(isto é, uma string que não está presente na lista de valores permitidos), a string vazia é inserida no lugar como um valor especial de erro. Esta string pode se diferenciar de uma string vazia 'normal' pelo fato de que esta string tem o valor numérico 0. Veremos mais sobre este assunto mais tarde.
  • Se um enum é declarado null, null é também um valor permitido para a coluna, e o valor padrão é null. Se um enum é declaarado not null, o valor padrão é o primeiro elemento da lista de valores permitidos.

Cada enumeração tem um índice, onde:


  • Valores da lista de elementos permitidos na especificação da coluna são números começados com 1;
  • O valor de índice de uma string vazia que indique erro é 0.

Por padrão, o primeiro enumerador tem o valor 0 e o valor de cada enumerador sucessor aumente em 1.

Os tipos aceitos para um enum são byte, sbyte, short, ushort, int, uint, long, ou ulong. Uma variável do tipo Dia pode ser atribuída a qualquer valor no intervalo do tipo subjacente, pois os valores não são limitados às constantes nomeadas. Porém, algumas vezes torna-se necessário fazer uma representação dos valores deste Enum na interface, mais comumente em um DropDownList.

O Enum tem os métodos descritos a seguir:


  • String toString(), que retorna uma string com o nome da instância (em maiúsculas);
  • valueOf (String nome), que retorna o objeto da classe enum cujo nome é a string do argumento e;
  • int ordinal(), que retorna o número de ordem do objeto na enumeração.

Em se tratando do tempo de execução no projeto, um tipo de dado enumerado é geralmente implementado usando-se inteiros. Entretanto, comparando-se a usar somente inteiros, os tipos enumerados tornam o código fonte mais bem documentado do que através do uso explícito de "números mágicos".

A seguir estão vantagens de usar um enum em vez de um tipo numérico:

Você especifica claramente para o código do cliente que os valores são válidos para a variável;

No Visual Studio, o IntelliSense lista os valores definidos.

Os Enum são tipos que herdam a System.Enum na Base Class Library (BCL). Um requisito comum é converter entre o ENUM e uma variável do tipo sua base. Caso você esteja recebendo contribuições na forma de um int de um usuário ou um arquivo, então você pode lançá-la para um ENUM e utilizá-la de forma significativa em seu programa. Devemos considerar que a manipulação de variáveis do tipo valor oferece uma performance superior a variável do tipo referência, por não possuir a necessidade de alocação em heap (área de alocação dinâmica) e não ser acessada através de um ponteiro. Dependendo da linguagem, a representação de inteiros pode não ser visível ao programador, o que previne operações como aritmética. Uma das vantagens de se ter enum é que podem ser tratados como se fossem inteiros, ou seja, podemos usar em switchs e ifs, além de podermos comparar a tipagem ao invés de comparar strings.

Nas Listagens 7 a 9 temos exemplo de três Enums: Enum Status, Tamanho e TipoCliente. É possível criar qualquer tipo de lista enumerada e utilizá-la para referenciar internamente no código, deixando mais claro seu código e ações.

Listagem 7. Lista enumerada de Status.

public enum Status
  {
    Ativo = 1;
    Inativo = 2;
    Aguardando = 3;
    Cancelado =4;
  }

Como você pode observar, a sintaxe da declaração da estrutura acima é semelhante a de uma classe, ou seja, uma estrutura pode possuir construtores, porém não possui destrutores e os construtores têm de ser customizados. A tentativa de declarar o construtor default gera um erro de compilação.

Listagem 8. Lista enumerada de Tamanho.

public enum Tamanho{ pequeno, medio, grande, extragrande }

Listagem 9. Lista enumerada de TipoCliente

 public enum TipoCliente
  {
      Pessoafisica = 1;
      Pessoajuridica = 2;
      Orgaopublico = 3;
      ONG = 4;
  }

Veja que foi criada uma lista enum do tipo de cliente que será gravada no banco somente aquele que tiver o valor inteiro, e toda vez que for exibido ao usuário por meio de uma interface, será exibida a descrição ao invés do valor inteiro.

Dentro do conceito que é chamado de programação robusta, ou como acontece com qualquer constante, todas as referências para os valores individuais de um enum são convertidas em numéricos em tempo de compilação.Isso pode criar possíveis problemas de versionamento. Atribuindo valores adicionais para novas versões de enums ou alterando os valores dos membros enum em uma nova versão, pode causar problemas para o código-fonte dependente.Valores de enumeração são frequentemente usados em alternar instruções.Se os elementos adicionais foram adicionados para o enum,pode ser selecionado o tipo e a seção padrão da instrução switch inesperadamente.

O enum nos permitem criar listas para tornar mais fácil a vida do desenvolvedor e principalmente para evitar erros de comparação e ainda padronizar determinada opção dentro do sistema, pois são basicamente listas que são enumeradas. Desta forma, sempre terá uma Chave e um Valor que juntos formam um registro único, ou seja, não é possível criar um enumerador que tenha a mesma chave e valor. Essas listas geralmente são pequenas e atribuir valores adicionais para novas versões de enums ou alterar os valores dos membros em uma nova versão pode causar problemas para o código-fonte dependente. Valores de enumeração são frequentemente usados em alternar instruções.

É possível também definir outros tipos numéricos para os elementos em vez de apenas int, por exemplo, é possível defini-los como byte e long,porém, nestes casos, você terá de fazer casta todo o momento que for usar o enumerador. Então, modificar o tipo do enumerador só é aconselhado quando realmente se faz necessário.

Em um enumerador, quando não são atribuídos valores para as opções, este sempre irá iniciar com o valor zero e sempre o valor de um enumerador será um número. Não há como definir uma opção com valor string, por exemplo. No entanto, é liberado para que você mesmo atribua os valores desejados para cada elemento de um enumerador ou até mesmo que omita essa atribuição se achar necessário ou ver que é necessário em apenas alguns elementos.

Se outros desenvolvedores usam seu código, você deve fornecer diretrizes sobre como o seu código deve reagir se novos elementos forem adicionados a qualquer enum.

Espero que tenham gostado desse artigo e até a próxima.