Tipos Genéricos no .Net Framework

Você precisa estar logado para dar um feedback. Clique aqui para efetuar o login
Para efetuar o download você precisa estar logado. Clique aqui para efetuar o login
Confirmar voto
0
 (1)  (0)

Veja neste artigo como utilizar tipos genéricos no .NET Framework, para criação de métodos e classes que necessitam trabalhar com argumentos de tipos inicialmente desconhecidos.

O Generics do .NET Framework implementaram a possibilidade de parâmetros receberem tipos desconhecidos até o momento da execução do método. Os métodos que tratam tipos genéricos desmistificam suas características apenas no momento em que ele estiver sendo utilizado. Além de métodos, também é possível a geração de classes complexas e totalmente genéricas, permitindo escrever códigos que atendam necessidades comuns em um projeto, sem perder a confiabilidade em conversões, boxing ou qualquer outra necessidade fundamental.

Geralmente os tipos genéricos estão identificados com a letra T, em maiúsculo, mas é uma letra convencionalmente utilizada em teste e não obrigatoriamente é necessário utilizá-la.

Utilizando tipos genéricos no .NET Framework

A declaração de um tipo genérico .NET Framework é simples. Como o exemplo a seguir:

Listagem 1: Declarando método genérico

public void MetodoGenerico<T>(T input)
{        
} 

Com o identificado <T>, definimos o tipo que será incluído nesse método. Ao declarar o valor para T na chamada do método, o parâmetro de entrada assumrá automaticamente o mesmo tipo. Ele não precisa obrigatoriamente ser preenchido.

Listagem 2: Chamando Método Genérico no .NET Framework

public void ChamandoMetodoGenerico()
{
  var program = new Program();
  var inteiro = 2;
  float flutuante = 2.3F;

  MetodoGenerico(program);
  MetodoGenerico(inteiro);
  MetodoGenerico<float>(flutuante);
}

Simples assim, a declaração de classes não tem muitas diferenças na sua declaração, utilizamos a mesma concepção.

Listagem 3: Classe Genérica no .NET Framework

public class Generics<T>
{
  public Generics()
  {         
  }

  public Generics(T input)
  {
    var prop = input;
  }
}

Então, para utilizar uma classe que utiliza genérics, pode-se proceder da seguinte forma:

Listagem 4: Chamando uma classe genérica

public void ChamandoClasseGenerica()
{
  Generics<Program> objProgram = new Generics<Program>();
  Generics<int> objInt = new Generics<int>(10);
} 

Repare que agora o valor para <T> é obrigatório, pois é preciso informar qual será o tipo do objeto instanciado.

As interfaces de classes também podem ser genéricas, a declaração é idêntica à das classes.

A declaração de classes genéricas pode ser feita de forma restritiva, permitindo assim que os tipos que a classe poderá receber durante a sua instância sejam controlados.

Utilizando o operador where é possível realizar esse controle, definindo regras para a declaração do tipo genérico T. A abaixo vemos um exemplo básico de uso do where, onde foi definido que o tipo T deverá, obrigatoriamente, ser uma classe.

Listagem 5: Receber apenas classes

public class Generics<T> where T : class
{
        public Generics()
        {
        }

  public Generics(T input)
  {
    var prop = input;
  }
} 

Da mesma forma, por exemplo, é possível estabelecer que uma classe genérica só receba o tipo struct para o argumento T. Existe também a possibilidade de definir que o tipo T tem de herdar de uma interface, como a IDisposable, por exemplo. Assim, quando eu declarar um tipo para a classe, o interpretador irá verificar se o mesmo combina com as opções definidas pela classe genérica.

Listagem 6: Classe genérica com tipos e interfaces

public class Generics<T> where T : class, IDisposable, IObserver<T>, new()
{
  public Generics()
  {
  }

  public Generics(T input)
  {
    var prop = input;
  }
} 

A classe genérica não é limitada a receber apenas um tipo, um exemplo é a classe Dictionary do framework. Essa classe possibilita receber dois tipos e os mesmos são armazenados em um array de duas posições.

A declaração para esse tipo é feita da seguinte forma:

Listagem 7: Classe genérica com dois parâmetros

public class Generics<T, I>
{
  public Generics()
  {
  }

  public Generics(T input)
  {
    var prop = input;
  }

  public Generics(T input, I input2)
  {
    var prop = input;
    var prop2 = input2;
  }
} 

Os conceitos de definição de regras par ao tipo T, vistos anteriormente, podem também serem aplicados agora. Por exemplo, para cada tipo de entrada informado para a classe pode ser utilizado o operador where, como podemos ver abaixo.

Listagem 8: Classe com dois parâmetros e operadores

public class Generics<T, I>
  where T : System.NullReferenceException, IConvertible
  where I : struct, ICloneable
{
  public Generics()
  {
  }

  public Generics(T input)
  {
    var prop = input;
  }

  public Generics(T input, I input2)
  {
    var prop = input;
    var prop2 = input2;
  }
} 

Codificar

Abaixo temo um exemplo de código que realiza a conversão de tipos, utilizando método de extensão. Nele é capturado o tipo definido para o argumento T e o tipo da variável que está sendo passada.

Listagem 9: Converter Genérico

public static T To<T>(this IConvertible obj)
{
  try
  {
    Type TypeReturn = typeof(T);
    if (TypeReturn.IsGenericType && (TypeReturn.GetGenericTypeDefinition() == typeof(Nullable<>)))
    {
      if (obj == null || (string)obj == string.Empty)
      {
        return (T)(object)null;
      }
      return (T)Convert.ChangeType(obj, Nullable.GetUnderlyingType(TypeReturn));
    }
    return (T)Convert.ChangeType(obj, TypeReturn);
  }
  catch
  {
    return default(T);
  }
} 

Ele captura o valor para conversão pelo método de extensão e o T é o tipo para o qual ele deseja que o valor seja convertido. Existe uma validação para os tipos Nullable, caso se deseje converter um True ou False para o tipo Boolean?, por exemplo, também é possível.

Conclusão

Os tipos genéricos têm várias vantagens e utilizações. A reutilização de código é o que mais é chamativo. Permite que funções que seriam repetitivas, por causa dos tipos que seriam passados para elas, se tornem o menor dos problemas.

Essa prática exige certo cuidado, pois o compilador só apontará o erro no momento que o código estiver sendo executado, então é importante tomar cuidado com alguns convertes que não sejam de tipos seguros.

 
Você precisa estar logado para dar um feedback. Clique aqui para efetuar o login
Receba nossas novidades
Ficou com alguma dúvida?