Operadores de teste de tipo e expressão de conversão is, as, typeof e conversões

Esses operadores e expressões executam a verificação de tipo ou a conversão de tipo. O operador is verifica se o tipo de runtime de uma expressão é compatível com um determinado tipo. O operador as converte uma expressão explicitamente para determinado tipo se o tipo do respectivo runtime for compatível com o tipo em questão. As expressões de conversão executam uma conversão explícita para um tipo de destino. O operador typeof obtém a instância System.Type para um tipo.

Operador is

O operador is verifica se o tipo do resultado de uma expressão em tempo de execução é compatível com determinado tipo. O operador is também testa um resultado de expressão em relação a um padrão.

A expressão com o operador is de teste de tipo tem o seguinte formato

E is T

em que E é uma expressão que retorna um valor e T é o nome de um tipo ou um parâmetro de tipo. E não pode ser um método anônimo ou uma expressão lambda.

O operador is retorna true quando o resultado de uma expressão não é nulo e qualquer uma das seguintes condições é verdadeira:

O operador is não considera conversões definidas pelo usuário.

O seguinte exemplo demonstra que o operador is retorna true se o tipo do resultado de uma expressão em tempo de execução é derivado de determinado tipo, ou seja, existe uma conversão de referência entre tipos:

public class Base { }

public class Derived : Base { }

public static class IsOperatorExample
{
    public static void Main()
    {
        object b = new Base();
        Console.WriteLine(b is Base);  // output: True
        Console.WriteLine(b is Derived);  // output: False

        object d = new Derived();
        Console.WriteLine(d is Base);  // output: True
        Console.WriteLine(d is Derived); // output: True
    }
}

O próximo exemplo mostra que o operador is leva em conta conversões boxing e unboxing, mas não considera conversões numéricas:

int i = 27;
Console.WriteLine(i is System.IFormattable);  // output: True

object iBoxed = i;
Console.WriteLine(iBoxed is int);  // output: True
Console.WriteLine(iBoxed is long);  // output: False

Para saber mais sobre conversões em C#, confira o capítulo Conversões da Especificação da linguagem C#.

Teste de tipo com correspondência de padrões

O operador is também testa um resultado de expressão em relação a um padrão. O seguinte exemplo mostra como usar um padrão de declaração para verificar o tipo de uma expressão em tempo de execução:

int i = 23;
object iBoxed = i;
int? jNullable = 7;
if (iBoxed is int a && jNullable is int b)
{
    Console.WriteLine(a + b);  // output 30
}

Para obter informações sobre os padrões com suporte, confira Padrões.

Operador as

O operador as converte explicitamente o resultado de uma expressão para uma determinada referência ou tipo de valor anulável. Se a conversão não for possível, o operador as retornará null. Ao contrário de uma expressão de conversão, o operador as nunca gera uma exceção.

A expressão da forma

E as T

em que E é uma expressão que retorna um valor e T é o nome de um tipo ou um parâmetro de tipo, produz o mesmo resultado que

E is T ? (T)(E) : (T)null

exceto que E é avaliado apenas uma vez.

O operador as considera apenas as conversões de referência, anulável, boxing e unboxing. Não é possível usar o operador as para executar uma conversão definida pelo usuário. Para fazer isso, use uma expressão de conversão.

O exemplo a seguir demonstra o uso do operador as:

IEnumerable<int> numbers = new List<int>(){10, 20, 30};
IList<int> indexable = numbers as IList<int>;
if (indexable != null)
{
    Console.WriteLine(indexable[0] + indexable[indexable.Count - 1]);  // output: 40
}

Observação

Como mostrado no exemplo anterior, você precisa comparar o resultado da expressão as com null para verificar se uma conversão foi bem-sucedida. Você pode usar o operador is para testar se a conversão foi bem-sucedida e, se for bem-sucedida, atribuir seu resultado a uma nova variável.

Expressão de conversão

Uma expressão de conversão do formulário (T)E realiza uma conversão explícita do resultado da expressão E para o tipo T. Se não existir nenhuma conversão explícita do tipo E para o tipo T, ocorrerá um erro em tempo de compilação. No tempo de execução, uma conversão explícita pode não ter êxito e uma expressão de conversão pode lançar uma exceção.

O exemplo a seguir demonstra conversões numéricas e de referência explícitas:

double x = 1234.7;
int a = (int)x;
Console.WriteLine(a);   // output: 1234

int[] ints = [10, 20, 30];
IEnumerable<int> numbers = ints;
IList<int> list = (IList<int>)numbers;
Console.WriteLine(list.Count);  // output: 3
Console.WriteLine(list[1]);  // output: 20

Para saber mais sobre conversões explícitas sem suporte, confira a seção Conversões explícitas da Especificação da linguagem C#. Para saber mais sobre como definir uma conversão de tipo explícito ou implícito personalizado, confira Operadores de conversão definidos pelo usuário.

Outros usos de ()

Você também usa parênteses para chamar um método ou chamar um delegado .

Outro uso dos parênteses é ajustar a ordem na qual as operações em uma expressão são avaliadas. Para saber mais, confira Operadores C#.

Operador typeof

O operador typeof obtém a instância System.Type para um tipo. O argumento do operador typeof deve ser o nome de um tipo ou um parâmetro de tipo, como mostra o exemplo a seguir:

void PrintType<T>() => Console.WriteLine(typeof(T));

Console.WriteLine(typeof(List<string>));
PrintType<int>();
PrintType<System.Int32>();
PrintType<Dictionary<int, char>>();
// Output:
// System.Collections.Generic.List`1[System.String]
// System.Int32
// System.Int32
// System.Collections.Generic.Dictionary`2[System.Int32,System.Char]

O argumento não deve ser um tipo que exija anotações de metadados. Como exemplo, confira os seguintes tipos:

  • dynamic
  • string? (ou qualquer tipo de referência anulável)

Esses tipos não são representados diretamente em metadados. Os tipos incluem atributos que descrevem o tipo subjacente. Em ambos os casos, você pode usar o tipo subjacente. Em vez de dynamic, você pode usar object. Em vez de string?, você pode usar string.

Você também pode usar o operador typeof com tipos genéricos não associados. O nome de um tipo genérico não associado deve conter o número apropriado de vírgulas, que é um a menos que o número de parâmetros de tipo. O exemplo a seguir mostra o uso do operador typeof com um tipo genérico não associado:

Console.WriteLine(typeof(Dictionary<,>));
// Output:
// System.Collections.Generic.Dictionary`2[TKey,TValue]

O operador typeof não pode ter como argumento uma expressão. Para obter a instância System.Type para o tipo do resultado de uma expressão em tempo de execução, use o método Object.GetType.

Teste de tipo com o operador typeof

Use o operador typeof para verificar se o tipo do resultado da expressão em tempo de execução corresponde exatamente a determinado tipo. O seguinte exemplo demonstra as diferenças entre as verificações de tipo executadas com o operador typeof e com o operador is:

public class Animal { }

public class Giraffe : Animal { }

public static class TypeOfExample
{
    public static void Main()
    {
        object b = new Giraffe();
        Console.WriteLine(b is Animal);  // output: True
        Console.WriteLine(b.GetType() == typeof(Animal));  // output: False

        Console.WriteLine(b is Giraffe);  // output: True
        Console.WriteLine(b.GetType() == typeof(Giraffe));  // output: True
    }
}

Capacidade de sobrecarga do operador

Os operadores is, as e typeof não podem ser sobrecarregados.

Um tipo definido pelo usuário não pode criar uma sobrecarregar para o operador (), mas pode definir conversões de tipo personalizadas, que podem ser executadas por uma expressão de conversão. Para saber mais, confira Operadores de conversão definidos pelo usuário.

Especificação da linguagem C#

Para obter mais informações, confira as seguintes seções da especificação da linguagem C#:

Confira também