Para um melhor entendimento deste Artigo veja o Índice (Programação Orientada a Objetos) |
![]() |
Tipos Genéricos (Generics) Tipos genéricos ou programação genérica é simples de entender. Imagine que você não saiba o tipo de objeto que a sua classe, método ou propriedade vai receber como parâmetro ou retorno, neste caso você pode usar Generics. Vamos pegar como exemplo uma Janela, eu não sei o tipo de janela que irei ter, ela pode ser uma veneziana, uma janela basculante ou uma janela de correr, logo vou declarar a minha classe como “Generics” vejamos como fazer isso: namespace Desenvolvedores.Net.ExemploGenerics { class Janela<T> { public Janela() { /* * aqui temos que instanciar a nossa propriedade * Tipo com um valor default. * para que ao acessarmos a mesma não retorne erro. */ Tipo = (T)Activator.CreateInstance<T>(); } //podemos usar no construtor public Janela(T _tipo) { /* * aqui não precisamos fazer como foi feito no construtor acima, * pois já estamos passando o tipo */ Tipo = _tipo; } //na propriedade public T Tipo { get; set; } public bool Aberta { get; set; } public bool Quebrada { get; set; } public void Quebrar() { Quebrada = true; } public void Consertar() { Quebrada = false; } public void Abrir() { Aberta = true; } public void Fechar() { Aberta = false; } //como tipo de parâmetro em métodos public void SetTipo(T value) { Tipo = value; } //como retorno em métodos public T GetTipo() { return Tipo; } } } No código acima, reparem na linha selecionada a declaração está assim: Janela do tipo Euroglass. namespace Desenvolvedores.Net.ExemploGenerics { class Euroglass : Janela<Euroglass> { } } Percebam também que podemos usar o tipo <T> em qualquer lugar da nossa classe, Métodos, Propriedades, Construtores. Vejamos abaixo as declarações de nossas classes de janelas que iremos usar para testes. Janela Basculante: namespace Desenvolvedores.Net.ExemploGenerics { public enum TipoEixo { Horizontal, Vertical } class Basculante { public TipoEixo Eixo { get; set; } } } Janela Veneziana: namespace Desenvolvedores.Net.ExemploGenerics { public enum TipoLamina { Fixa, Movel } class Veneziana { public TipoLamina Lamina { get; set; } } } Janela de Correr: namespace Desenvolvedores.Net.ExemploGenerics { class DeCorrer { public void Correr() { Console.WriteLine("A Janela correu"); } } } Agora vamos a um exemplo de uso: namespace Desenvolvedores.Net.ExemploGenerics { class Program { static void Main(string[] args) { //Aqui iremos declarar uma janela basculante Janela<Basculante> basculante = new Janela<Basculante>(); //veja que ao acessar a propriedade Tipo, //teremos a propriedade Eixo, que vem do tipo Basculante if (basculante.Tipo.Eixo == TipoEixo.Horizontal) Console.WriteLine("Janela basculante com eixo horizontal"); else Console.WriteLine("Janela basculante com eixo vertical"); //vamos agora a outro tipo de janela, janela de correr Janela<DeCorrer> correr = new Janela<DeCorrer>(); //chamaremos o método que existe no tipo de janela Correr correr.Tipo.Correr(); //aqui modificaremos um pouco a chamada //para ver o uso do construtor Veneziana venez = new Veneziana(); venez.Lamina = TipoLamina.Movel; Janela<Veneziana> veneziana = new Janela<Veneziana>(venez); if (veneziana.Tipo.Lamina == TipoLamina.Fixa) Console.WriteLine("Janela veneziana com lâminas fixas"); else Console.WriteLine("Janela veneziana com lâminas móveis"); //modificaremos o tipo de lâmina para teste veneziana.Tipo.Lamina = TipoLamina.Fixa; if (veneziana.Tipo.Lamina == TipoLamina.Fixa) Console.WriteLine("Janela veneziana com lâminas fixas"); else Console.WriteLine("Janela veneziana com lâminas móveis"); Console.ReadKey(); } } } Terminamos aqui a explicação básica do tipo genérico, vamos agora ver alguns tópicos avançados. Do jeito que nossa classe janela foi declarada ela aceita qualquer tipo de objeto, ou seja, podemos declarar a nossa janela assim: Janela<Porta> porta = new Janela<Porta>(); Mas eu não quero permitir que a nossa Janela seja uma porta, logo temos que restringir o tipo de objetos que <T> irá aceitar, deste modo podemos usar a declaração where, que irá nos ajudar a restringir o tipo que irá ser usado em <T>. namespace Desenvolvedores.Net.ExemploGenerics { interface IJanela { } } Após criado a interface, modificamos a nossa classe Janela para restringir o uso de de tipos em <T>. Veja: namespace Desenvolvedores.Net.ExemploGenerics { class Janela<T> where T : IJanela { public Janela() { /* * aqui temos que instanciar a nossa propriedade * Tipo com um valor default. * para que ao acessarmos a mesma não retorne erro. */ Tipo = (T)Activator.CreateInstance<T>(); } //podemos usar no construtor public Janela(T _tipo) { /* * aqui não precisamos fazer como foi feito no construtor acima, * pois já estamos passando o tipo */ Tipo = _tipo; } //na propriedade public T Tipo { get; set; } public bool Aberta { get; set; } public bool Quebrada { get; set; } public void Quebrar() { Quebrada = true; } public void Consertar() { Quebrada = false; } public void Abrir() { Aberta = true; } public void Fechar() { Aberta = false; } //como tipo de parâmetro em métodos public void SetTipo(T value) { Tipo = value; } //como retorno em métodos public T GetTipo() { return Tipo; } } } Veja na linha selecionada a declaração class Janela<T> where T : IJanela o uso de where T : IJanela, onde usamos o where, isso indica que só iremos aceitar objetos que implementem a interface IJanela. The type ‘Desenvolvedores.Net.ExemploGenerics.Basculante’ cannot be used as type parameter ‘T’ in the generic type or method ‘Desenvolvedores.Net.ExemploGenerics.Janela<T>’. There is no implicit reference conversion from ‘Desenvolvedores.Net.ExemploGenerics.Basculante’ to ‘Desenvolvedores.Net.ExemploGenerics.IJanela’. E assim para todos os outros tipos, para isso temos que corrigir as declarações de nossas classes. Veja: Janela Basculante: namespace Desenvolvedores.Net.ExemploGenerics { public enum TipoEixo { Horizontal, Vertical } class Basculante: IJanela { public TipoEixo Eixo { get; set; } } } Janela Veneziana: namespace Desenvolvedores.Net.ExemploGenerics { public enum TipoLamina { Fixa, Movel } class Veneziana: IJanela { public TipoLamina Lamina { get; set; } } } Janela de Correr: namespace Desenvolvedores.Net.ExemploGenerics { class DeCorrer: IJanela { public void Correr() { Console.WriteLine("A Janela correu"); } } } Pronto. Isso fará com que as nossas classes de tipo de Janelas possam ser usadas em nossa Janela<T>, e não permitirá mais o uso do tipo Porta. namespace Desenvolvedores.Net.ExemploGenerics { class Generics { //retorno com um tipo Genérico public T RetornarTipoGenerico<T>() { int x = 10; int y = 10; object ret = x + y; ret = Convert.ChangeType(ret, typeof(T)); return (T)ret; } //tipo de parâmetro genérico public void ParametroGenerico<T>(T _Param1) { Console.WriteLine("O parâmetro 1 e do tipo " + _Param1.GetType().ToString() + ". E seu valor é de " + _Param1.ToString()); } } } Reparem que aqui eu não declarei na classe, e sim no declaração do método. Exemplo de uso: static void Main(string[] args) { Generics g = new Generics(); Console.WriteLine(g.RetornarTipoGenerico<string>()); g.ParametroGenerico<double>(4); Console.ReadKey(); } Podemos ter múltiplas declaracões de genéricos, veja: class Janela<T, K> { } E podemos também restringir seus tipos: class Janela<T, K> where T : IJanela where K : ICloneable { } E isto vale para os métodos também. /// <summary> /// Exemplo de múltiplos genéricos /// </summary> /// <typeparam name="R">define o retorno do método</typeparam> /// <typeparam name="P">define o tipo de parâmetro para o método /// </typeparam> /// <param name="param1">parâmetro 1</param> /// <returns>R</returns> public R MultiplosGenericos<R, P>(P param1) { return (R)new object(); } O intuito deste artigo foi introduzir o conceito de generics, com o tempo você ira descobrir que seu uso é bastante útil. |
É isso ai pessoal 🙂
Até o próximo
♦ Marcelo