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.
Você pode sobrecarregar um operador C# predefinido em um tipo definido pelo usuário. Ao sobrecarregar um operador, você fornece uma implementação personalizada para a operação quando um ou ambos os operandos são desse tipo. Consulte a seção Operadores sobrecarregados para obter uma lista de operadores C# que você pode sobrecarregar.
A linguagem C# faz referência a documentos da versão mais recentemente lançada da linguagem C#. Ele também contém a documentação inicial para funcionalidades em pré-visualizações públicas para o próximo lançamento do idioma.
A documentação identifica qualquer recurso introduzido pela primeira vez nas três últimas versões do idioma ou nas versões prévias públicas atuais.
Dica
Para descobrir quando um recurso foi introduzido pela primeira vez em C#, consulte o artigo sobre o histórico de versão da linguagem C#.
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, você pode sobrecarregar os operadores de incremento (++) e decremento (--) 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. - 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 têm precedência sobre qualquer operador estático para «op». Se o tipo de x não declarar um operador sobrecarregado «op»= 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#: