Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. 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 no caso de um ou ambos os operandos serem desse tipo. A seção Operadores sobrecarregáveis mostra quais operadores C# podem ser sobrecarregados.
Use a operator
palavra-chave para declarar um operador. A declaração do operador deve satisfazer as seguintes regras:
- 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 tipo
T
ouT?
ondeT
é o tipo que contém a declaração do operador. - Inclui o
static
modificador, exceto para os operadores de atribuição compostos, 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
. Então, operadores sobrecarregados apoiariam argumentos desses dois tipos. Ou seja, tornar-se-ia 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 obter mais informações, consulte Operadores de conversão definidos pelo usuário.
Operadores sobrecarregados
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 em conjunto. |
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 forma: == e != , < e > , <= e >= . |
+= , -= , , *= /= , %= , &= , \|= , ^= <<= >>= >>>= |
Os operadores de atribuição compostos podem ser sobrecarregados em C# 14 e posterior. |
Um operador sobrecarregado de atribuição composta deve seguir estas regras:
- Deve incluir o modificador
public
. - 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 decréscimo (--
) podem ser sobrecarregados como membros da 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
. - Não pode incluir o
static
modificador. - O tipo de retorno deve ser
void
. - Ele não pode declarar nenhum parâmetro, 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 |
Sobrecarregar os operadores true e false , assim como 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 transmissão. Para obter mais informações, consulte 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 composto correspondente.
Resolução de sobrecarga de operadores
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 decréscimo de instância não eram permitidos.
Se x
for classificado 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 se a expressão x++
for utilizada, a instância operator++
será ignorada. Caso contrário, é dada preferência à instância operator ++
. Por exemplo
x++; // Instance operator++ preferred.
y = x++; // instance operator++ isn't considered.
A razão para esta 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 é preferido sobre um operador unário estático.
Especificação da linguagem C#
Para obter mais informações, consulte as seguintes seções da especificação da linguagem C#: