top of page
  • Foto do escritorFábio Henrique

C# Generic Constraints

Generic constraints são uma forma de deixar seu código mais consistente reduzindo a possibilidades de erros bobos acontecerem.


O exemplo abaixo mostra uma classe com boa margem para erros. O método Adestrar assume que o tipo genérico informado possui uma propriedade Adestrado e isso é péssimo pois, como pode observar a propriedade Adestrado é um requisito para que o método funcione corretamente


class Adestramento<T>
{
    public static void Adestrar(T obj) 
    {
      obj.GetType().GetProperty("Adestrado").SetValue(objtruenull);
    }
}

A classe acima está tão mal escrita que permite que você a invoque desta forma:


Adestramento<int>.Adestrar(0);

E obviamente fazendo isso um erro será lançado em tempo de execução!


Os generic constraints servem justamente para evitar este tipo de coisa.


Está claro que a classe Adestramento não deve receber tipos primitivos. Neste caso poderíamos usar um generic constraint que lançaria um erro em tempo de compilação caso alguém tentasse usar um tipo primitivo como no exemplo anterior.


class Adestramento<Twhere Tclass
{
    public static void Adestrar(T obj) 
    {
      obj.GetType().GetProperty("Adestrado").SetValue(objtruenull);
    }
}

Repare que foi adicionado a declaração da classe where T: class isso informa ao compilador que o argumento provido a esta classe deve ser um tipo de referência logo, se tentar passar um tipo primitivo, por exemplo, verá o seguinte erro de compilação.



Ao menos agora sabemos que não podemos passar certos tipos à classe Adestramento porém, o código continua passível de erros em tempo de execução.


using System;

namespace GenericConstraints
{
    class Program
    {
        static void Main(string[] args)
        {
          var hachiko = new Cachorro();
          var sequoia = new Arvore();
          Adestramento<Cachorro>.Adestrar(hachiko);
          Adestramento<Arvore>.Adestrar(sequoia);

          Console.ReadKey();
        }
    }

    class Adestramento<Twhere Tclass
    {
        public static void Adestrar(T obj) 
        {
      obj.GetType().GetProperty("Adestrado").SetValue(objtruenull);
        }
    }

    class Cachorro
    {
      public bool Adestrado { getset; }
    }

    class Arvore
    {
      public string Tipo { getset; }
    }
}

O código acima não apresenta erros de compilação porém ao executá-lo está chamada irá lançar um erro


Adestramento<Arvore>.Adestrar(sequoia);

Isto ocorre porque apesar de Arvore ser um tipo de referência ela não possui a propriedade Adestrado


Para corrigir isto basta modificar o generic constraint aplicado


class Adestramento<Twhere TCachorro
{
   public static void Adestrar(T obj) 
   {
      obj.GetType().GetProperty("Adestrado").SetValue(objtruenull);
   }
}

Agora o compilador irá apontar que o tipo Arvore não é válido para a classe Adestramento



Imagine que temos outros tipos animais e que queremos usar a classe Adestramento para todos eles. Neste caso nosso código ficaria assim


using System;

namespace GenericConstraints
{
    class Program
    {
       static void Main(string[] args)
       {
         var hachiko = new Cachorro();
         var tom = new Gato();

         Adestramento<Cachorro>.Adestrar(hachiko);
         Adestramento<Gato>.Adestrar(tom);

         Console.ReadKey();
       }
    }

  class Adestramento<Twhere TAnimal
  {
    public static void Adestrar(T obj) 
    {
      obj.GetType().GetProperty("Adestrado").SetValue(objtruenull);
     }
  }

 class Animal 
 {
    public bool Adestrado { getset; }
 }

 class Cachorro : Animal
 {
 }
 
 class Gato : Animal
 {
 }

}

Acho que agora está clara a utilidade do generic constraints e como você deve ter percebido existem tipos diferentes de constraints.



148 visualizações0 comentário

Posts recentes

Ver tudo

Comentários


bottom of page