Los principales operadores aritméticos y de comparación se pueden adaptar para que los usen tus propias clases y structs. Esto se conoce como sobrecarga de operadores.
Este artículo es un análisis exhaustivo de la sintaxis, así como de qué operadores se pueden sobrecargar y cuáles no.
La mayoría de los operadores tienen la forma:
static <return type> operaator <operator symbols>(<parameters>);
Los operadores de conversión tienen la forma:
static (explicit|implicit) operator <cast-to-type>(<cast-from-type> <parameter name>);
Los operadores se comportan igual que los métodos estáticos.
Ejemplos de sintaxis:
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);
}
}
A menudo resulta productivo implementar un método Equals() y llamarlo desde el operador ==. De forma similar, para las comparaciones puedes implementar la interfaz IComparable. En ambos casos, matas dos pájaros de un tiro y algo más.
Ten en cuenta que no puedes crear operadores a partir de símbolos que no formen parte del conjunto estándar de operadores. Solo puedes usar símbolos existentes para aquellas operaciones en las que la documentación especifique que se pueden sobrecargar. Los operadores que se pueden sobrecargar están listados aquí.
Ten en cuenta que el orden de los parámetros es importante cuando difieren en tipo. En el código de ejemplo anterior, pt * 10m es una expresión válida, mientras que 10m * pt no compilará.
Esta documentación sobre la sobrecarga de operadores detalla la sintaxis.