Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
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 tipo. A seção Operadores sobrecarregados mostra quais operadores C# podem ser sobrecarregados.
Use a operator
palavra-chave para declarar um operador. Uma declaração de operador deve atender às seguintes regras:
- Ele inclui um
public
modificador. - 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
ouT?
ondeT
está o tipo que contém a declaração do operador. - Ele inclui o
static
modificador, exceto para os operadores de atribuição composta, como+=
. - Os operadores increment (
++
) e decrement (--
) podem ser implementados como métodos estáticos ou de instância.
O exemplo a seguir define uma estrutura simplificada para representar um número racional. A estrutura sobrecarrega alguns dos operadores aritméticos:
public struct Fraction
{
private int numerator;
private int denominator;
public Fraction(int numerator, int denominator)
{
if (denominator == 0)
{
throw new ArgumentException("Denominator cannot be zero.", nameof(denominator));
}
this.numerator = numerator;
this.denominator = denominator;
}
public static Fraction operator +(Fraction operand) => operand;
public static Fraction operator -(Fraction operand) => new Fraction(-operand.numerator, operand.denominator);
public static Fraction operator +(Fraction left, Fraction right)
=> new Fraction(left.numerator * right.denominator + right.numerator * left.denominator, left.denominator * right.denominator);
public static Fraction operator -(Fraction left, Fraction right)
=> left + (-right);
public static Fraction operator *(Fraction left, Fraction right)
=> new Fraction(left.numerator * right.numerator, left.denominator * right.denominator);
public static Fraction operator /(Fraction left, Fraction right)
{
if (right.numerator == 0)
{
throw new DivideByZeroException();
}
return new Fraction(left.numerator * right.denominator, left.denominator * right.numerator);
}
// Define increment and decrement to add 1/den, rather than 1/1.
public static Fraction operator ++(Fraction operand)
=> new Fraction(operand.numerator++, operand.denominator);
public static Fraction operator --(Fraction operand) =>
new Fraction(operand.numerator--, operand.denominator);
public override string ToString() => $"{numerator} / {denominator}";
// New operators allowed in C# 14:
public void operator +=(Fraction operand) =>
(numerator, denominator ) =
(
numerator * operand.denominator + operand.numerator * denominator,
denominator * operand.denominator
);
public void operator -=(Fraction operand) =>
(numerator, denominator) =
(
numerator * operand.denominator - operand.numerator * denominator,
denominator * operand.denominator
);
public void operator *=(Fraction operand) =>
(numerator, denominator) =
(
numerator * operand.numerator,
denominator * operand.denominator
);
public void operator /=(Fraction operand)
{
if (operand.numerator == 0)
{
throw new DivideByZeroException();
}
(numerator, denominator) =
(
numerator * operand.denominator,
denominator * operand.numerator
);
}
public void operator ++() => numerator++;
public void operator --() => numerator--;
}
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
para Fraction
. Em seguida, operadores sobrecarregados dão suporte a argumentos desses dois tipos. Ou seja, se tornaria possível adicionar um inteiro a uma fração e obter uma fração como resultado.
Você também usa a operator
palavra-chave para definir uma conversão de tipo personalizada. Para saber mais, confira Operadores de conversão definidos pelo usuário.
Operadores sobrecarregados
A tabela a seguir mostra os operadores que podem ser sobrecarregados:
Operadores | Anotaçõ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 >= . |
+= , -= , *= , /= , %= , , &= , , \|= , ^= , <<= , , >>= , >>>= |
Os operadores de atribuição composta podem ser sobrecarregados no C# 14 e em versões posteriores. |
Um operador sobrecarregado de atribuição composta deve seguir estas regras:
- Deve incluir o modificador
public
. - Ele não pode incluir o
static
modificador. - O tipo de retorno deve ser
void
. - A declaração deve incluir um parâmetro, que representa o lado direito da atribuição composta.
A partir do C# 14, os operadores de incremento (++
) e decremento (--
) podem ser sobrecarregados como membros de instância. Os operadores de instância podem melhorar o desempenho evitando a criação de uma nova instância. Um operador de instância deve seguir estas regras:
- Deve incluir o modificador
public
. - Ele não pode incluir o
static
modificador. - O tipo de retorno deve ser
void
. - Ele não pode declarar parâmetros, mesmo que esses parâmetros tenham um valor padrão.
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 realizadas por uma expressão de conversão. Para saber mais, confira Operadores de conversão definidos pelo usuário. |
^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. |
Antes do C# 14, os operadores compostos não podiam ser sobrecarregados. Sobrecarregar o operador binário correspondente sobrecarrega implicitamente o operador de atribuição composta correspondente.
Resolução de sobrecarga do operador
Importante
Esta seção se aplica ao C# 14 e posterior. Antes do C# 14, operadores de atribuição composta definidos pelo usuário e operadores de incremento e decremento de instância não são permitidos.
Se x
for classificada como uma variável em uma expressão de atribuição composta, como x «op»= y
, os operadores de instância são preferidos sobre qualquer operador estático para «op»
. Se um operador sobrecarregado «op»=
não for declarado para o tipo de x
ou x
não for classificado como uma variável, os operadores estáticos serão usados.
Para o operador postfix ++
, se x
não for classificado como uma variável ou a expressão x++
for usada, a instância operator++
é ignorada. Caso contrário, a preferência será dada à instância operator ++
. Por exemplo
x++; // Instance operator++ preferred.
y = x++; // instance operator++ isn't considered.
O motivo dessa regra é que y
deve ser atribuído ao valor de x
antes de ser incrementado. O compilador não pode determinar isso para uma implementação definida pelo usuário em um tipo de referência.
Para o operador de prefixo ++
, se x
for classificado como uma variável em ++x
, o operador de instância será preferido em vez de um operador estático unário.
Especificação da linguagem C#
Para obter mais informações, confira as seguintes seções da especificação da linguagem C#: