Os principais operadores aritméticos e de comparação podem ser adaptados para serem usados pelas tuas próprias classes e estruturas. Isto é conhecido como sobrecarga de operadores.
Este artigo é uma discussão aprofundada da sintaxe, bem como de quais os operadores que podem ser sobrecarregados e quais não podem.
A maioria dos operadores tem a forma:
static <return type> operaator <operator symbols>(<parameters>);
Os operadores de conversão de tipo têm a forma:
static (explicit|implicit) operator <cast-to-type>(<cast-from-type> <parameter name>);
Os operadores comportam-se da mesma forma que os métodos estáticos.
Exemplos de sintaxe:
struct Point
{
decimal x;
decimal y;
public static bool operator ==(Point pt, Point ptOther)
{
return pt.x == ptOther.x && pt.y == ptOther.y;
}
public static bool operator !=(Point pt, Point ptOther)
{
return !(pt == ptOther);
}
public static Point operator *(Point pt, decimal scale)
{
var ptNew = new Point();
ptNew.x = pt.x * scale;
ptNew.y = pt.y * scale;
return ptNew;
}
public static implicit operator Point((decimal x, decimal y) xy)
{
var pt = new Point();
pt.x = xy.x;
pt.y = xy.y;
return pt;
}
public static explicit operator (decimal x, decimal y)(Point pt)
{
return (pt.x, pt.y);
}
}
Muitas vezes, é produtivo implementar um método Equals() e chamá-lo a partir do operador ==. Da mesma forma, para as comparações podes implementar a interface IComparable. Em ambos os casos, matas dois coelhos com pouco mais do que uma cajadada.
Convém notar que não podes criar operadores a partir de símbolos que não façam parte do conjunto padrão de operadores. Só podes usar símbolos já existentes para as operações em que a documentação especifica que podem ser sobrecarregadas. Os operadores que podem ser sobrecarregados estão listados aqui.
Repara que a ordem dos parâmetros é importante quando estes têm tipos diferentes. No código de exemplo acima, pt * 10m é uma expressão válida, enquanto 10m * pt não compila.
Esta documentação de sobrecarga de operadores detalha a sintaxe.