0Pricing
C# Academy · Lección

Prácticas recomendadas para sobrecargar operadores

Mantenga intuitivos los operadores sobrecargados.

Prácticas recomendadas para sobrecargar operadores es una lección gratuita de C# Academy en CoddyKit. Esta es la lección 4 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de C# Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de C# Academy incluye 4 lecciones en total.

Buenas prácticas para sobrecargar operadores

La sobrecarga de operadores es una herramienta poderosa. Bien utilizada, hace que los tipos de valor sean intuitivos; mal utilizada, vuelve críptico el código. En esta lección se presentan principios para mantener predecibles los operadores sobrecargados.

Sobrecargue solo cuando el significado sea evidente

Sobrecargue un operador solo cuando su significado no sea ambiguo para su tipo. + en un vector significa claramente una suma componente a componente; + en un Order solo confundiría a quienes lean el código.

using System;

public struct Vector2
{
    public int X, Y;
    public Vector2(int x, int y) { X = x; Y = y; }
    // + means adding components: obvious and expected
    public static Vector2 operator +(Vector2 a, Vector2 b)
        => new Vector2(a.X + b.X, a.Y + b.Y);
    public override string ToString() => "(" + X + ", " + Y + ")";
}

public class Program
{
    public static void Main()
    {
        Console.WriteLine(new Vector2(1, 2) + new Vector2(3, 4));
    }
}

Preserve las expectativas matemáticas

Mantenga los operadores coherentes con la intuición: a + b debería ser igual a b + a cuando las matemáticas sean conmutativas, y + no debería restar en secreto. Estas sorpresas provocan errores sutiles.

using System;

public struct Money
{
    public decimal Amount;
    public Money(decimal a) { Amount = a; }
    public static Money operator +(Money a, Money b) => new Money(a.Amount + b.Amount);
    public override string ToString() => "$" + Amount;
}

public class Program
{
    public static void Main()
    {
        var x = new Money(3);
        var y = new Money(5);
        Console.WriteLine((x + y).Amount == (y + x).Amount); // commutative
    }
}

Mantenga la simetría y las parejas

El lenguaje empareja ciertos operadores, pero usted también debe mantener la simetría lógica: si añade +, considere añadir -; si añade <, proporcione también > y las variantes con igualdad. Los conjuntos de operadores incompletos frustran a quienes los utilizan.

using System;

public struct Length
{
    public int Mm;
    public Length(int mm) { Mm = mm; }
    public static Length operator +(Length a, Length b) => new Length(a.Mm + b.Mm);
    public static Length operator -(Length a, Length b) => new Length(a.Mm - b.Mm);
    public override string ToString() => Mm + "mm";
}

public class Program
{
    public static void Main()
    {
        Console.WriteLine(new Length(50) + new Length(20));
        Console.WriteLine(new Length(50) - new Length(20));
    }
}

No modifique los operandos

Los operadores deberían ser puros: calcular y devolver un valor nuevo, sin modificar los operandos. Modificar un operando dentro de + contradice todas las expectativas de quien lea el código.

using System;

public struct Vector2
{
    public int X, Y;
    public Vector2(int x, int y) { X = x; Y = y; }
    public static Vector2 operator +(Vector2 a, Vector2 b)
        => new Vector2(a.X + b.X, a.Y + b.Y); // returns new, mutates nothing
    public override string ToString() => "(" + X + ", " + Y + ")";
}

public class Program
{
    public static void Main()
    {
        var a = new Vector2(1, 1);
        var unused = a + new Vector2(9, 9);
        Console.WriteLine("a is still " + a);
    }
}

Mantenga == coherente con Equals

Una buena práctica recurrente es que, siempre que sobrecargue ==, invalide Equals y GetHashCode para que todas las formas de comprobar la igualdad coincidan. La incoherencia en este punto es uno de los errores más comunes al sobrecargar operadores.

using System;

public struct Point
{
    public int X, Y;
    public Point(int x, int y) { X = x; Y = y; }
    public override bool Equals(object obj) => obj is Point p && p.X == X && p.Y == Y;
    public override int GetHashCode() => HashCode.Combine(X, Y);
    public static bool operator ==(Point a, Point b) => a.Equals(b);
    public static bool operator !=(Point a, Point b) => !a.Equals(b);
}

public class Program
{
    public static void Main()
    {
        Console.WriteLine(new Point(1, 1) == new Point(1, 1));
    }
}

Proporcione alternativas con nombre

Algunos lenguajes y herramientas de análisis no pueden utilizar operadores. Ofrecer un método con nombre como Add junto con + mejora la interoperabilidad y la facilidad de descubrimiento.

using System;

public struct Vector2
{
    public int X, Y;
    public Vector2(int x, int y) { X = x; Y = y; }
    public Vector2 Add(Vector2 other) => new Vector2(X + other.X, Y + other.Y);
    public static Vector2 operator +(Vector2 a, Vector2 b) => a.Add(b);
    public override string ToString() => "(" + X + ", " + Y + ")";
}

public class Program
{
    public static void Main()
    {
        var v = new Vector2(1, 2);
        Console.WriteLine(v.Add(new Vector2(3, 4)));
        Console.WriteLine(v + new Vector2(3, 4));
    }
}

Prefiera operadores en tipos semejantes a valores

Los operadores resultan naturales en tipos inmutables semejantes a valores (estructuras o clases similares a registros). En tipos mutables donde la identidad es importante, los métodos con nombre suelen comunicar mejor la intención.

using System;

public readonly struct Rational
{
    public readonly int Num, Den;
    public Rational(int n, int d) { Num = n; Den = d; }
    public static Rational operator *(Rational a, Rational b)
        => new Rational(a.Num * b.Num, a.Den * b.Den);
    public override string ToString() => Num + "/" + Den;
}

public class Program
{
    public static void Main()
    {
        Console.WriteLine(new Rational(1, 2) * new Rational(2, 3));
    }
}

Documente los casos límite

Explique explícitamente cómo gestionan los operadores los valores especiales: división entre cero, operandos nulos en el caso de las clases o desbordamientos. Un comportamiento predecible evita tomar desprevenidos a quienes realizan las llamadas.

using System;

public struct SafeDiv
{
    public int Value;
    public SafeDiv(int v) { Value = v; }
    // Documented behavior: dividing by zero yields zero
    public static SafeDiv operator /(SafeDiv a, SafeDiv b)
        => new SafeDiv(b.Value == 0 ? 0 : a.Value / b.Value);
    public override string ToString() => Value.ToString();
}

public class Program
{
    public static void Main()
    {
        Console.WriteLine(new SafeDiv(10) / new SafeDiv(0));
        Console.WriteLine(new SafeDiv(10) / new SafeDiv(2));
    }
}

Un conjunto disciplinado de operadores

Un tipo numérico bien diseñado combina unos pocos operadores intuitivos, una igualdad coherente y la inmutabilidad. El resultado se comporta como un número integrado y es agradable de utilizar.

using System;

public readonly struct Vec
{
    public readonly double X, Y;
    public Vec(double x, double y) { X = x; Y = y; }
    public static Vec operator +(Vec a, Vec b) => new Vec(a.X + b.X, a.Y + b.Y);
    public static Vec operator -(Vec a, Vec b) => new Vec(a.X - b.X, a.Y - b.Y);
    public static Vec operator *(Vec a, double k) => new Vec(a.X * k, a.Y * k);
    public override string ToString() => "(" + X + ", " + Y + ")";
}

public class Program
{
    public static void Main()
    {
        Console.WriteLine((new Vec(1, 2) + new Vec(3, 4)) * 2);
    }
}

Póngalo en práctica

Reúna estas prácticas: un tipo de valor inmutable, operadores intuitivos, una alternativa con nombre y una igualdad coherente.

using System;

public readonly struct Meters : IEquatable<Meters>
{
    public readonly double Value;
    public Meters(double v) { Value = v; }
    public Meters Add(Meters other) => new Meters(Value + other.Value);
    public static Meters operator +(Meters a, Meters b) => a.Add(b);
    public bool Equals(Meters other) => Value == other.Value;
    public override bool Equals(object obj) => obj is Meters m && Equals(m);
    public override int GetHashCode() => Value.GetHashCode();
    public static bool operator ==(Meters a, Meters b) => a.Equals(b);
    public static bool operator !=(Meters a, Meters b) => !a.Equals(b);
    public override string ToString() => Value + "m";
}

public class Program
{
    public static void Main()
    {
        Console.WriteLine(new Meters(3) + new Meters(4));
        Console.WriteLine(new Meters(7) == new Meters(7));
    }
}

Comprobación rápida

Aplique las buenas prácticas para operadores.

Resumen

Una buena sobrecarga de operadores es disciplinada y predecible.

  • Sobrecargue solo cuando el significado sea evidente.
  • Preserve las expectativas matemáticas y la simetría.
  • Mantenga la pureza: devuelva valores nuevos y nunca modifique los operandos.
  • Mantenga == coherente con Equals/GetHashCode.
  • Ofrezca alternativas con nombre y prefiera tipos semejantes a valores.

Preguntas frecuentes

¿La lección «Prácticas recomendadas para sobrecargar operadores» es gratis?

Sí — el texto completo de «Prácticas recomendadas para sobrecargar operadores» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de C# Academy, actualiza a CoddyKit PRO. El curso de C# Academy incluye 4 lecciones en total.

¿Qué aprenderé en «Prácticas recomendadas para sobrecargar operadores»?

Mantenga intuitivos los operadores sobrecargados. Practicas C# Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar C# Academy?

No se requiere experiencia previa. C# Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 4 de 4.

¿Cuánto tiempo toma la lección «Prácticas recomendadas para sobrecargar operadores»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de C# Academy?

Sí. Cada lección de C# Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. Sobrecarga de operadores aritméticos
  2. Sobrecarga de operadores de comparación
  3. Conversiones definidas por el usuario
  4. Prácticas recomendadas para sobrecargar operadores
← Volver a C# Academy