Sobrecarga de operador – operadores predefinidos unários, aritméticos, de igualdade e de comparação

Um tipo definido pelo usuário pode sobrecarregar um operador C# predefinido. Ou seja, um tipo pode fornecer a implementação personalizada de uma operação caso um ou ambos os operandos sejam desse mesmo tipo. A seção Operadores sobrecarregáveis mostra quais operadores do C# podem ser sobrecarregados.

Use a palavra-chave operator para declarar um operador. Uma declaração de operador deve satisfazer as regras a seguir:

  • Ela inclui os modificadores public e static.
  • Um operador unário tem um parâmetro de entrada. Um operador binário tem dois parâmetros de entrada. Em cada caso, pelo menos um parâmetro deve ter o tipo T ou T?, em que T é o tipo que contém a declaração do operador.

O exemplo a seguir define uma estrutura simplificada para representar um número racional. A estrutura sobrecarrega alguns dos operadores aritméticos:

public readonly struct Fraction
{
    private readonly int num;
    private readonly int den;

    public Fraction(int numerator, int denominator)
    {
        if (denominator == 0)
        {
            throw new ArgumentException("Denominator cannot be zero.", nameof(denominator));
        }
        num = numerator;
        den = denominator;
    }

    public static Fraction operator +(Fraction a) => a;
    public static Fraction operator -(Fraction a) => new Fraction(-a.num, a.den);

    public static Fraction operator +(Fraction a, Fraction b)
        => new Fraction(a.num * b.den + b.num * a.den, a.den * b.den);

    public static Fraction operator -(Fraction a, Fraction b)
        => a + (-b);

    public static Fraction operator *(Fraction a, Fraction b)
        => new Fraction(a.num * b.num, a.den * b.den);

    public static Fraction operator /(Fraction a, Fraction b)
    {
        if (b.num == 0)
        {
            throw new DivideByZeroException();
        }
        return new Fraction(a.num * b.den, a.den * b.num);
    }

    public override string ToString() => $"{num} / {den}";
}

public static class OperatorOverloading
{
    public static void Main()
    {
        var a = new Fraction(5, 4);
        var b = new Fraction(1, 2);
        Console.WriteLine(-a);   // output: -5 / 4
        Console.WriteLine(a + b);  // output: 14 / 8
        Console.WriteLine(a - b);  // output: 6 / 8
        Console.WriteLine(a * b);  // output: 5 / 8
        Console.WriteLine(a / b);  // output: 10 / 4
    }
}

Você pode estender o exemplo anterior definindo uma conversão implícita de int em Fraction. Em seguida, os operadores sobrecarregados seriam compatíveis com os argumentos desses dois tipos. Ou seja, tornaria-se possível adicionar um inteiro a uma fração e obter uma fração como um resultado.

Use também a palavra-chave operator para definir uma conversão de tipo personalizado. Para saber mais, confira Operadores de conversão definidos pelo usuário.

Operadores sobrecarregáveis

A tabela a seguir mostra os operadores que podem ser sobrecarregados:

Operadores Observações
+x, -x, !x, ~x, ++, --, true, false Os operadores true e false devem ser sobrecarregados juntos.
x + y, x - y, x * y, x / y, x % y,
x & y, x | y, x ^ y,
x << y, x >> y, x >>> y
x == y, x != y, x < y, x > y, x <= y, x >= y Deve ser sobrecarregado em pares da seguinte maneira: == e !=, < e >, <= e >=.

Operadores não sobrecarregáveis

A tabela a seguir mostra os operadores que não podem ser sobrecarregados:

Operadores Alternativas
x && y, x || y Sobrecarregue os operadores true e false e os operadores & ou |. Para obter mais informações, consulte Operadores lógicos condicionais definidos pelo usuário.
a[i], a?[i] Defina um indexador.
(T)x Defina 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.
+=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>=, >>>= Sobrecarregue o operador binário correspondente. Por exemplo, quando você sobrecarrega o operador binário +, += é implicitamente sobrecarregado.
^x, x = y, x.y, x?.y, c ? t : f, x ?? y, ??= y,
x..y, x->y, =>, f(x), as, await, checked, unchecked, default, delegate, is, nameof, new,
sizeof, stackalloc, switch, typeof, with
Nenhum.

Especificação da linguagem C#

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

Confira também