Operadores e Conversão de Tipos em C#

Operadores

Operadores simplificados:

Operador condicional (ternário): forma compacta de if-else. Se a condição for verdadeira, retorna o primeiro valor; caso contrário, o segundo.

condition ? true_value : false_value

Operadores checked e unchecked: O bloco checked ativa a verificação de estouro aritmético, lançando OverflowException se ocorrer. O bloco unchecked desativa essa verificação (comportamento padrão).

int valor = 2147483647;
checked
{
    valor++;
}
Console.WriteLine(valor);  // overflow exception
int valor = 2147483647;
unchecked
{
    valor++;
}
Console.WriteLine(valor);  // -2147483648

Operador is: Verifica se um objeto é compatível com um tipo específico (se é do tipo ou deriva dele).

object texto = "Olá";
if (texto is string)
{
    Console.WriteLine("texto é uma string");
}

Operador as: Converte explicitamente uma referência; se a conversão falhar, retorna null em vez de lançar exceção.

object obj1 = "C#";
object obj2 = 42;
string str1 = obj1 as string;  // "C#"
string str2 = obj2 as string;  // null

Operador sizeof: Retorna o tamanho em bytes de um tipo de valor na pilha. Para tipos não primitivos, deve estar em um bloco unsafe.

Console.WriteLine(sizeof(decimal));  // 16

Operador typeof: Obtém o objeto Type de um tipo específico.

Type tipo = typeof(DateTime);
Console.WriteLine(tipo.FullName);

Operadores ? (nullable) e ?? (coalescência nula): Tipos anuláveis permitem representar valores indefinidos. O operador ?? retorna o primeiro operanod se não for nulo; caso contrário, retorna o segundo.

int? a = null;
int? b = a + 10;  // null
int? c = a * 3;   // null

int? valor = null;
int resultado = valor ?? -1;   // resultado = -1
valor = 5;
resultado = valor ?? -1;       // resultado = 5

Prioridade de Operadores

A ordem de precedência segue as regras padrão da linguagem. Por exemplo, multiplicação e divisão têm precedência sobre adição e subtração.

Segurança de Tipos e Conversões

Conversão implícita: Ocorre automaticamente quando não há perda de dados.

int valorInt = 100;
long valorLong = valorInt;  // implícita

Conversão explícita (cast): Necessária quando pode haver perda de dados ou quando o tipo de destino é "menor".

double valorDouble = 123.45;
int valorInt = (int)valorDouble;  // 123

Boxing e Unboxing: Boxing é a conversão de um tipo de valor para object (ou qualquer tipo de interface que implemente). Unboxing é a operação inversa.

int numero = 42;
object obj = numero;         // boxing (implícito)
int numeroDeVolta = (int)obj; // unboxing (explícito)

Comparação de Igualdade

ReferenceEquals: Método estático que verifica se duas referências apontam para a mesma instância.

object a = new object();
object b = a;
Console.WriteLine(object.ReferenceEquals(a, b));  // True

Equals virtual: Pode ser sobrescrito para comparar valores.

Equals estático: Trata valores nulos de forma segura.

Operador ==: Por padrão, compara referências em tipos de referência, mas pode ser sobrecarregado para comparar valores.

Sobrecarga de Operadores

É possível definir operadores personalizados para tipos definidos pelo usuário usando a palavra-chave operator. O exemplo a seguir sobrecarrega o operador + para somar dois vetores 2D.

public struct Vetor2D
{
    public double X;
    public double Y;

    public Vetor2D(double x, double y) { X = x; Y = y; }

    public static Vetor2D operator +(Vetor2D v1, Vetor2D v2)
    {
        return new Vetor2D(v1.X + v2.X, v1.Y + v2.Y);
    }

    public override string ToString() => $"({X}, {Y})";
}

// Uso:
Vetor2D v1 = new Vetor2D(3.0, 4.0);
Vetor2D v2 = new Vetor2D(1.5, 2.5);
Vetor2D v3 = v1 + v2;
Console.WriteLine(v3);  // (4.5, 6.5)

Operadores que podem ser sobrecarregados incluem: +, -, *, /, ==, !=, <, >, etc. Alguns operadores como && e || não podem ser sobrecarregados diretamente, mas podem ser simulados através de & e |.

Conversões Definidas pelo Usuário

É possível criar conversões implícitas ou explícitas entre tipos próprios usando implicit operator ou explicit operator. O exemplo abaixo define uma estrutura Temperatura que permite conversão de/para double (Celsius).

public struct Temperatura
{
    private double celsius;

    public Temperatura(double celsius) { this.celsius = celsius; }

    // Conversão implícita de double para Temperatura
    public static implicit operator Temperatura(double graus)
    {
        return new Temperatura(graus);
    }

    // Conversão explícita de Temperatura para double
    public static explicit operator double(Temperatura t)
    {
        return t.celsius;
    }

    public override string ToString() => $"{celsius} °C";
}

// Uso:
Temperatura t1 = 25.5;          // implícita
double valor = (double)t1;      // explícita
Console.WriteLine(t1);          // 25,5 °C
Console.WriteLine(valor);       // 25,5

Regras importantes:

  • Conversões implícitas não devem lançar exceções nem perder dados.
  • Uma conversão deve ser definida dentro do tipo de origem ou do tipo de destino.
  • Não é possível definir conversões entre tipos que já possuem relação de herança.

Tags: CSharp operators type-conversion boxing unboxing

Publicado em 7-6 21:54