Coerções e conversões de tipo (Guia de Programação em C#)

Como o C# é tipado estaticamente no tempo de compilação, depois que uma variável é declarada, ela não pode ser declarada novamente ou atribuída a um valor de outro tipo, a menos que esse tipo possa ser convertido implicitamente no tipo da variável. Por exemplo, a string não pode ser convertida implicitamente em int. Portanto, depois de declarar i como um int, não é possível atribuir a cadeia de caracteres "Hello" a ele, como mostra o código a seguir:

int i;

// error CS0029: Cannot implicitly convert type 'string' to 'int'
i = "Hello";

No entanto, às vezes é necessário copiar um valor para uma variável ou um parâmetro de método de outro tipo. Por exemplo, você pode ter que passar uma variável de inteiro para um método cujo parâmetro é digitado como double. Ou talvez precise atribuir uma variável de classe a uma variável de um tipo de interface. Esses tipos de operações são chamados de conversões de tipo. No C#, você pode realizar os seguintes tipos de conversões:

  • Conversões implícitas: nenhuma sintaxe especial é necessária porque a conversão sempre é bem sucedida e nenhum dado será perdido. Exemplos incluem conversões de tipos integrais menores para maiores e conversões de classes derivadas para classes base.

  • Conversões explícitas (casts): as conversões explícitas exigem uma expressão cast. A conversão é necessária quando as informações podem ser perdidas na conversão ou quando a conversão pode não funcionar por outros motivos. Exemplos típicos incluem a conversão numérica para um tipo que tem menos precisão ou um intervalo menor e a conversão de uma instância de classe base para uma classe derivada.

  • Conversões definidas pelo usuário: as conversões definidas pelo usuário são realizadas por métodos especiais que podem ser definidos para habilitar conversões explícitas e implícitas entre tipos personalizados que não têm uma relação de classe base/classe derivada. Para saber mais, confira Operadores de conversão definidos pelo usuário.

  • Conversões com classes auxiliares: para converter entre tipos não compatíveis, assim como inteiros e objetos System.DateTime, ou cadeias de caracteres hexadecimais e matrizes de bytes, você pode usar a classe System.BitConverter, a classe System.Convert e os métodos Parse dos tipos numéricos internos, tais como Int32.Parse. Para obter mais informações, consulte Como converter uma matriz de bytes em um int, Como converter uma cadeia de caracteres em um número e Como converter entre cadeias de caracteres hexadecimais e tipos numéricos.

Conversões implícitas

Para tipos numéricos internos, uma conversão implícita poderá ser feita quando o valor a ser armazenado puder se ajustar à variável sem ser truncado ou arredondado. Para tipos integrais, isso significa que o intervalo do tipo de origem é um subconjunto apropriado do intervalo para o tipo de destino. Por exemplo, uma variável do tipo long (inteiro de 64 bits) pode armazenar qualquer valor que um int (inteiro de 32 bits) pode armazenar. No exemplo a seguir, o compilador converte implicitamente o valor de num à direita em um tipo long antes de atribuí-lo a bigNum.

// Implicit conversion. A long can
// hold any value an int can hold, and more!
int num = 2147483647;
long bigNum = num;

Para obter uma lista completa de todas as conversões numéricas implícitas, consulte a seção Conversões numéricas implícitas do artigo Conversões numéricas internas.

Para tipos de referência, uma conversão implícita sempre existe de uma classe para qualquer uma das suas interfaces ou classes base diretas ou indiretas. Nenhuma sintaxe especial é necessária porque uma classe derivada sempre contém todos os membros de uma classe base.

Derived d = new Derived();

// Always OK.
Base b = d;

Conversões explícitas

No entanto, se uma conversão não puder ser realizada sem o risco de perda de informações, o compilador exigirá que você execute uma conversão explícita, que é chamada de cast. Uma conversão é uma maneira de informar explicitamente ao compilador que você pretende fazer a conversão e que você está ciente de que poderá ocorrer perda de dados ou a conversão poderá falhar em tempo de execução. Para executar uma conversão, especifique entre parênteses o tipo para o qual você está convertendo, na frente do valor ou da variável a ser convertida. O programa a seguir converte um double em um int. O programa não será compilado sem a conversão.

class Test
{
    static void Main()
    {
        double x = 1234.7;
        int a;
        // Cast double to int.
        a = (int)x;
        System.Console.WriteLine(a);
    }
}
// Output: 1234

Para obter uma lista completa de conversões numéricas explícitas com suporte, consulte a seção Conversões numéricas explícitas do artigo Conversões numéricas internas.

Para tipos de referência, uma conversão explícita será necessária se você precisar converter de um tipo base para um tipo derivado:

// Create a new derived type.
Giraffe g = new Giraffe();

// Implicit conversion to base type is safe.
Animal a = g;

// Explicit conversion is required to cast back
// to derived type. Note: This will compile but will
// throw an exception at run time if the right-side
// object is not in fact a Giraffe.
Giraffe g2 = (Giraffe)a;

Uma operação de conversão entre tipos de referência não altera o tipo de tempo de execução do objeto subjacente. Ela apenas altera o tipo do valor que está sendo usado como uma referência a esse objeto. Para obter mais informações, consulte Polimorfismo.

Exceções de conversão de tipo em tempo de execução

Em algumas conversões de tipo de referência, o compilador não poderá determinar se uma conversão será válida. É possível que uma operação de conversão que é compilada corretamente falhe em tempo de execução. Conforme mostrado no exemplo a seguir, um tipo de conversão que falha em tempo de execução fará com que uma InvalidCastException seja lançada.

class Animal
{
    public void Eat() => System.Console.WriteLine("Eating.");

    public override string ToString() => "I am an animal.";
}

class Reptile : Animal { }
class Mammal : Animal { }

class UnSafeCast
{
    static void Main()
    {
        Test(new Mammal());

        // Keep the console window open in debug mode.
        System.Console.WriteLine("Press any key to exit.");
        System.Console.ReadKey();
    }

    static void Test(Animal a)
    {
        // System.InvalidCastException at run time
        // Unable to cast object of type 'Mammal' to type 'Reptile'
        Reptile r = (Reptile)a;
    }
}

O método Test tem um parâmetro Animal, assim, converter explicitamente o argumento a em um Reptile é fazer uma suposição perigosa. É mais seguro não fazer suposições, mas sim verificar o tipo. O C# fornece o operador is para habilitar o teste de compatibilidade antes de realmente executar uma conversão. Para saber mais, confira Como converter com segurança usando a correspondência de padrões e os operadores “is” e “as”.

Especificação da linguagem C#

Para saber mais, confira a seção Conversões da Especificação da linguagem C#.

Confira também