O operador is existe desde a primeira versão do C# e ele sempre foi utilizado para verificar o tipo de um objeto em tempo de execução.
Curso C# (C Sharp) - TDD
Conhecer o cursoNeste tipo de verificação é muito comum o uso de operações “cast”. Por exemplo, vamos supor uma classe base, com duas classes filhas:
public class Forma() {}
public class Triangulo : Forma{
public int Largura { get; set; }
public int Altura { get; set; }
public int Base { get; se; }
public Triangulo(int largura, int altura, int base) {
this.largura = largura;
this.altura = altura;
this.base = base;
}
public void Perimetro (){
Console.WriteLine("O perímetro do triângulo é {0}", largura + altura + base);
}
}
public class Retangulo : Forma {
public int Largura { get; set; }
public int Altura { get; set; }
public Retangulo(int largura, int altura) {
this.largura = largura;
this.altura = altura;
}
public void Area(){
Console.WriteLine("A área do retângulo é {0}", largura * altura);
}
}
Caso houvesse uma array com essas classes, para chamar cada método delas, seria necessário realizar uma conversão:
public class Program {
public static void Main(){
Forma[] formas = { new Triangulo(10, 12, 10), new Retangulo(7, 4), new Triangulo(17, 15, 16), new Retangulo(25, 12) };
foreach (var item in formas)
{
if (item is Triangulo)
((Triangulo)item).Perimetro();
if (item is Retangulo)
((Retangulo)item).Area();
}
}
}
Repare que ao descobrir o tipo da variável, ainda é necessário realizar o cast:
if (item is Triangulo)
((Triangulo)item).Perimetro();
Para evitar este cast, no C# 7.0 foi introduzido o conceito de Pattern Matching:
Pattern Matching
O Pattern Matching adiciona mais poder ao operador is e a cláusula switch.
Agora com o operador is, após realizar uma verificação de tipo, é possível atribuir o resultado a uma variável:
public class Program {
public static void Main(){
Forma[] formas = { new Triangulo(10, 12, 10), new Retangulo(7, 4), new Triangulo(17, 15, 16), new Retangulo(25, 12) };
foreach (var item in formas)
{
if (item is Triangulo t)
t.Perimetro();
if (item is Retangulo r)
r.Area();
}
}
}
Com isso, não é mais necessário realizar o cast do objeto dentro do condicional. Este tipo de situação também nos permite uma verificação mais elaborada:
if (item is Retangulo r and r.Largura > 0)
r.Area();
Assim, apenas se item
for um objeto de Retangulo
e a propriedade Largura
deste objeto for maior que 0
, que o bloco do condicional será executado.
Não temos essas situações no exemplo acima, mas agora com o operador is também é possível verificar um valor literal:
if(item is 10)
Console.WriteLine("Item é 10");
Null:
if(item is null)
Console.WriteLine("Item é nulo");
Ou mesmo aplicar o objeto a uma variável:
if(item is var i)
Console.WriteLine("Item é do tipo {0}", i?.GetType().Name);
Desta forma, é possível descobrir o tipo do objeto quando esta informação não é conhecida.
Pattern Matching com switch
Além do operador is, o switch também recebeu novos recursos para ser aplicado Pattern Matching. Agora é possível comparar o tipo de um objeto dentro de um bloco switch:
foreach (var item in formas)
{
switch(item){
case Triangulo t:
t.Perimetro();
break;
case Retangulo r:
r.Area();
break;
case 10:
Console.WriteLine("Item é 10");
break;
case null:
Console.WriteLine("Item é nulo");
break;
case Retangulo r when r.Largura > 0:
r.Area();
break;
case var i:
Console.WriteLine("Item é do tipo {0}", i?.GetType().Name);
break;
}
}
Algumas das opções acima não se aplicam ao nosso exemplo, mas elas foram adicionadas para mostrar que as mesmas opções que vimos com o condicional if, podem ser aplicadas ao switch.
Conclusão
Agora o processo de checagem de tipo e cast de objetos está mais simples e dinâmico. Assim, caso esteja utilizando a versão 7.0 do C#, não hesite em utilizar este recurso. Ele irá melhorar a legibilidade do seu código.