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
publicmodificador. - 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
TouT?ondeTestá o tipo que contém a declaração do operador. - Ele inclui o
staticmodificador, 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. Os operadores de método de instância são um novo recurso introduzido no C# 14.
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 + 1, operand.denominator);
public static Fraction operator --(Fraction operand) =>
new Fraction(operand.numerator - 1, 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, , ++, --, , truefalse |
Os operadores true e false devem ser sobrecarregados juntos. |
x + y, x - y, x * y, x / y, , x % yx & y, x | y, , x ^ yx << y, , x >> yx >>> y |
|
x == y, x != y, x < y, x > y, , x <= yx >= 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
staticmodificador. - 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
staticmodificador. - 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, , ??= yx..y, x->y, =>, f(x), as, , await, , checked, unchecked, default, delegate, , is, nameof, , newsizeof, stackalloc, switch, , typeofwith |
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 xantes 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#: